Btrfs-progs: record generation for tree blocks in fsck
When working with a user who had a broken file system I noticed that we were reading a bad copy of a block when the other copy was perfectly fine. This is because we don't keep track of the parent generation for tree blocks, so we just read whichever copy we damned well please with no regards for which is best. This fixes this problem by recording the parent generation of the tree block so we can be sure to read the most correct copy before we check it, which will give us a better chance of fixing really broken filesystems. Thanks, Signed-off-by: Josef Bacik <jbacik@fb.com> Signed-off-by: David Sterba <dsterba@suse.cz> Signed-off-by: Chris Mason <clm@fb.com>
This commit is contained in:
parent
d98a5ffe6f
commit
47c18d17c5
1 changed files with 25 additions and 7 deletions
32
cmds-check.c
32
cmds-check.c
|
@ -98,6 +98,7 @@ struct extent_record {
|
|||
u64 refs;
|
||||
u64 extent_item_refs;
|
||||
u64 generation;
|
||||
u64 parent_generation;
|
||||
u64 info_objectid;
|
||||
u64 num_duplicates;
|
||||
u8 info_level;
|
||||
|
@ -2646,7 +2647,7 @@ static struct data_backref *alloc_data_backref(struct extent_record *rec,
|
|||
}
|
||||
|
||||
static int add_extent_rec(struct cache_tree *extent_cache,
|
||||
struct btrfs_key *parent_key,
|
||||
struct btrfs_key *parent_key, u64 parent_gen,
|
||||
u64 start, u64 nr, u64 extent_item_refs,
|
||||
int is_root, int inc_ref, int set_checked,
|
||||
int metadata, int extent_rec, u64 max_size)
|
||||
|
@ -2722,6 +2723,8 @@ static int add_extent_rec(struct cache_tree *extent_cache,
|
|||
|
||||
if (parent_key)
|
||||
btrfs_cpu_key_to_disk(&rec->parent_key, parent_key);
|
||||
if (parent_gen)
|
||||
rec->parent_generation = parent_gen;
|
||||
|
||||
if (rec->max_size < max_size)
|
||||
rec->max_size = max_size;
|
||||
|
@ -2762,6 +2765,11 @@ static int add_extent_rec(struct cache_tree *extent_cache,
|
|||
else
|
||||
memset(&rec->parent_key, 0, sizeof(*parent_key));
|
||||
|
||||
if (parent_gen)
|
||||
rec->parent_generation = parent_gen;
|
||||
else
|
||||
rec->parent_generation = 0;
|
||||
|
||||
rec->cache.start = start;
|
||||
rec->cache.size = nr;
|
||||
ret = insert_cache_extent(extent_cache, &rec->cache);
|
||||
|
@ -2783,7 +2791,7 @@ static int add_tree_backref(struct cache_tree *extent_cache, u64 bytenr,
|
|||
|
||||
cache = lookup_cache_extent(extent_cache, bytenr, 1);
|
||||
if (!cache) {
|
||||
add_extent_rec(extent_cache, NULL, bytenr,
|
||||
add_extent_rec(extent_cache, NULL, 0, bytenr,
|
||||
1, 0, 0, 0, 0, 1, 0, 0);
|
||||
cache = lookup_cache_extent(extent_cache, bytenr, 1);
|
||||
if (!cache)
|
||||
|
@ -2831,7 +2839,7 @@ static int add_data_backref(struct cache_tree *extent_cache, u64 bytenr,
|
|||
|
||||
cache = lookup_cache_extent(extent_cache, bytenr, 1);
|
||||
if (!cache) {
|
||||
add_extent_rec(extent_cache, NULL, bytenr, 1, 0, 0, 0, 0,
|
||||
add_extent_rec(extent_cache, NULL, 0, bytenr, 1, 0, 0, 0, 0,
|
||||
0, 0, max_size);
|
||||
cache = lookup_cache_extent(extent_cache, bytenr, 1);
|
||||
if (!cache)
|
||||
|
@ -3318,7 +3326,7 @@ static int process_extent_item(struct btrfs_root *root,
|
|||
#else
|
||||
BUG();
|
||||
#endif
|
||||
return add_extent_rec(extent_cache, NULL, key.objectid,
|
||||
return add_extent_rec(extent_cache, NULL, 0, key.objectid,
|
||||
num_bytes, refs, 0, 0, 0, metadata, 1,
|
||||
num_bytes);
|
||||
}
|
||||
|
@ -3326,7 +3334,7 @@ static int process_extent_item(struct btrfs_root *root,
|
|||
ei = btrfs_item_ptr(eb, slot, struct btrfs_extent_item);
|
||||
refs = btrfs_extent_refs(eb, ei);
|
||||
|
||||
add_extent_rec(extent_cache, NULL, key.objectid, num_bytes,
|
||||
add_extent_rec(extent_cache, NULL, 0, key.objectid, num_bytes,
|
||||
refs, 0, 0, 0, metadata, 1, num_bytes);
|
||||
|
||||
ptr = (unsigned long)(ei + 1);
|
||||
|
@ -3839,6 +3847,7 @@ static int run_next_block(struct btrfs_trans_handle *trans,
|
|||
u64 owner;
|
||||
u64 flags;
|
||||
u64 ptr;
|
||||
u64 gen = 0;
|
||||
int ret = 0;
|
||||
int i;
|
||||
int nritems;
|
||||
|
@ -3888,8 +3897,16 @@ static int run_next_block(struct btrfs_trans_handle *trans,
|
|||
free(cache);
|
||||
}
|
||||
|
||||
cache = lookup_cache_extent(extent_cache, bytenr, size);
|
||||
if (cache) {
|
||||
struct extent_record *rec;
|
||||
|
||||
rec = container_of(cache, struct extent_record, cache);
|
||||
gen = rec->parent_generation;
|
||||
}
|
||||
|
||||
/* fixme, get the real parent transid */
|
||||
buf = read_tree_block(root, bytenr, size, 0);
|
||||
buf = read_tree_block(root, bytenr, size, gen);
|
||||
if (!extent_buffer_uptodate(buf)) {
|
||||
record_bad_block_io(root->fs_info,
|
||||
extent_cache, bytenr, size);
|
||||
|
@ -4061,6 +4078,7 @@ static int run_next_block(struct btrfs_trans_handle *trans,
|
|||
}
|
||||
}
|
||||
ret = add_extent_rec(extent_cache, &key,
|
||||
btrfs_node_ptr_generation(buf, i),
|
||||
ptr, size, 0, 0, 1, 0, 1, 0,
|
||||
size);
|
||||
BUG_ON(ret);
|
||||
|
@ -4102,7 +4120,7 @@ static int add_root_to_pending(struct extent_buffer *buf,
|
|||
add_pending(nodes, seen, buf->start, buf->len);
|
||||
else
|
||||
add_pending(pending, seen, buf->start, buf->len);
|
||||
add_extent_rec(extent_cache, NULL, buf->start, buf->len,
|
||||
add_extent_rec(extent_cache, NULL, 0, buf->start, buf->len,
|
||||
0, 1, 1, 0, 1, 0, buf->len);
|
||||
|
||||
if (root_key->objectid == BTRFS_TREE_RELOC_OBJECTID ||
|
||||
|
|
Loading…
Reference in a new issue