mirror of
https://github.com/kdave/btrfs-progs
synced 2025-04-10 11:11:16 +00:00
btrfs-progs: check: add check for metadata level mismatch
For a skinny metadata item in the extent tree, the key offset represents the level of the tree it points to. This adds a check that these values match, as otherwise it can cause a volume to go readonly when deleting a large number of inodes. See https://github.com/maharmstone/ntfs2btrfs/issues/51 Pull-request: #623 Reviewed-by: Qu Wenruo <wqu@suse.com> Signed-off-by: Mark Harmstone <mark@harmstone.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
b390c276c2
commit
d8317a445c
19
check/main.c
19
check/main.c
@ -4195,7 +4195,8 @@ static int maybe_free_extent_rec(struct cache_tree *extent_cache,
|
||||
rec->num_duplicates == 0 && !all_backpointers_checked(rec, 0) &&
|
||||
!rec->bad_full_backref && !rec->crossing_stripes &&
|
||||
rec->generation <= super_gen + 1 &&
|
||||
!rec->wrong_chunk_type) {
|
||||
!rec->wrong_chunk_type &&
|
||||
(!rec->metadata || rec->info_level == rec->level)) {
|
||||
remove_cache_extent(extent_cache, &rec->cache);
|
||||
free_all_extent_backrefs(rec);
|
||||
list_del_init(&rec->list);
|
||||
@ -4767,6 +4768,7 @@ static int add_extent_rec_nolookup(struct cache_tree *extent_cache,
|
||||
rec->extent_item_refs = tmpl->extent_item_refs;
|
||||
rec->parent_generation = tmpl->parent_generation;
|
||||
rec->generation = tmpl->generation;
|
||||
rec->level = tmpl->level;
|
||||
INIT_LIST_HEAD(&rec->backrefs);
|
||||
INIT_LIST_HEAD(&rec->dups);
|
||||
INIT_LIST_HEAD(&rec->list);
|
||||
@ -4848,6 +4850,7 @@ static int add_extent_rec(struct cache_tree *extent_cache,
|
||||
rec->num_duplicates++;
|
||||
} else {
|
||||
rec->nr = tmpl->nr;
|
||||
rec->level = tmpl->level;
|
||||
rec->found_rec = 1;
|
||||
}
|
||||
}
|
||||
@ -5592,6 +5595,8 @@ static int process_extent_item(struct btrfs_root *root,
|
||||
if (metadata)
|
||||
btrfs_check_subpage_eb_alignment(gfs_info, key.objectid, num_bytes);
|
||||
|
||||
memset(&tmpl, 0, sizeof(tmpl));
|
||||
|
||||
ptr = (unsigned long)(ei + 1);
|
||||
if (metadata) {
|
||||
u64 level;
|
||||
@ -5610,8 +5615,10 @@ static int process_extent_item(struct btrfs_root *root,
|
||||
key.objectid, level, BTRFS_MAX_LEVEL - 1);
|
||||
return -EUCLEAN;
|
||||
}
|
||||
|
||||
tmpl.level = (u8)level;
|
||||
}
|
||||
memset(&tmpl, 0, sizeof(tmpl));
|
||||
|
||||
tmpl.start = key.objectid;
|
||||
tmpl.nr = num_bytes;
|
||||
tmpl.extent_item_refs = refs;
|
||||
@ -8144,6 +8151,14 @@ static int check_extent_refs(struct btrfs_root *root,
|
||||
cur_err = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (rec->metadata && rec->level != rec->info_level) {
|
||||
fprintf(stderr,
|
||||
"metadata level mismatch on [%llu, %llu]\n",
|
||||
rec->start, rec->nr);
|
||||
cur_err = 1;
|
||||
}
|
||||
|
||||
if (rec->refs != rec->extent_item_refs) {
|
||||
fprintf(stderr, "ref mismatch on [%llu %llu] ",
|
||||
(unsigned long long)rec->start,
|
||||
|
@ -90,6 +90,7 @@ struct extent_record {
|
||||
u64 info_objectid;
|
||||
u32 num_duplicates;
|
||||
u8 info_level;
|
||||
u8 level;
|
||||
unsigned int flag_block_full_backref:2;
|
||||
unsigned int found_rec:1;
|
||||
unsigned int content_checked:1;
|
||||
|
Loading…
Reference in New Issue
Block a user