forked from Mirrors/btrfs-progs
btrfs-progs: check: Populate extent generation correctly for data extents
[BUG] When using `btrfs check --init-extent-tree`, we will create incorrect generation number for data extents in extent tree: item 10 key (13631488 EXTENT_ITEM 1048576) itemoff 15828 itemsize 53 refs 1 gen 0 flags DATA extent data backref root FS_TREE objectid 257 offset 0 count 1 [CAUSE] Since data extent generation is not as obvious as tree blocks, which has header containing its generations, so for data extents, its extent_record::generation is not really updated, resulting such 0 generation. [FIX] To get generation of a data extent, there are two sources we can rely: - EXTENT_ITEM There is always a btrfs_extent_item::generation can be utilized. Although this is not possible for --init-extent-tree use case. - EXTENT_DATA We have btrfs_file_extent_item::generation for regular and preallocated data extents. Since --init-extent-tree will go through subvolume trees, this would be the main source for extent data generation. Then we only need to make add_data_backref() to accept @gen parameter, and pass it down to extent_record structure. And for the final extent item generation update, here we add extra fallback values, if we can't find FILE_EXTENT items. In that case, we just fall back to current transid. With this modification, recreated data EXTENT_ITEM now has correct generation number: item 10 key (13631488 EXTENT_ITEM 1048576) itemoff 15828 itemsize 53 refs 1 gen 6 flags DATA extent data backref root FS_TREE objectid 257 offset 0 count 1 Reviewed-by: Su Yue <Damenly_Su@gmx.com> Signed-off-by: Qu Wenruo <wqu@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>master
parent
9a85b7db02
commit
8d45dc270a
24
check/main.c
24
check/main.c
|
@ -4810,7 +4810,7 @@ static int add_tree_backref(struct cache_tree *extent_cache, u64 bytenr,
|
||||||
|
|
||||||
static int add_data_backref(struct cache_tree *extent_cache, u64 bytenr,
|
static int add_data_backref(struct cache_tree *extent_cache, u64 bytenr,
|
||||||
u64 parent, u64 root, u64 owner, u64 offset,
|
u64 parent, u64 root, u64 owner, u64 offset,
|
||||||
u32 num_refs, int found_ref, u64 max_size)
|
u32 num_refs, u64 gen, int found_ref, u64 max_size)
|
||||||
{
|
{
|
||||||
struct extent_record *rec;
|
struct extent_record *rec;
|
||||||
struct data_backref *back;
|
struct data_backref *back;
|
||||||
|
@ -4826,6 +4826,7 @@ static int add_data_backref(struct cache_tree *extent_cache, u64 bytenr,
|
||||||
tmpl.start = bytenr;
|
tmpl.start = bytenr;
|
||||||
tmpl.nr = 1;
|
tmpl.nr = 1;
|
||||||
tmpl.max_size = max_size;
|
tmpl.max_size = max_size;
|
||||||
|
tmpl.generation = gen;
|
||||||
|
|
||||||
ret = add_extent_rec_nolookup(extent_cache, &tmpl);
|
ret = add_extent_rec_nolookup(extent_cache, &tmpl);
|
||||||
if (ret)
|
if (ret)
|
||||||
|
@ -4840,6 +4841,8 @@ static int add_data_backref(struct cache_tree *extent_cache, u64 bytenr,
|
||||||
if (rec->max_size < max_size)
|
if (rec->max_size < max_size)
|
||||||
rec->max_size = max_size;
|
rec->max_size = max_size;
|
||||||
|
|
||||||
|
if (rec->generation < gen)
|
||||||
|
rec->generation = gen;
|
||||||
/*
|
/*
|
||||||
* If found_ref is set then max_size is the real size and must match the
|
* If found_ref is set then max_size is the real size and must match the
|
||||||
* existing refs. So if we have already found a ref then we need to
|
* existing refs. So if we have already found a ref then we need to
|
||||||
|
@ -5315,6 +5318,7 @@ static int process_extent_item(struct btrfs_root *root,
|
||||||
u64 refs = 0;
|
u64 refs = 0;
|
||||||
u64 offset;
|
u64 offset;
|
||||||
u64 num_bytes;
|
u64 num_bytes;
|
||||||
|
u64 gen;
|
||||||
int metadata = 0;
|
int metadata = 0;
|
||||||
|
|
||||||
btrfs_item_key_to_cpu(eb, &key, slot);
|
btrfs_item_key_to_cpu(eb, &key, slot);
|
||||||
|
@ -5340,6 +5344,7 @@ static int process_extent_item(struct btrfs_root *root,
|
||||||
|
|
||||||
ei = btrfs_item_ptr(eb, slot, struct btrfs_extent_item);
|
ei = btrfs_item_ptr(eb, slot, struct btrfs_extent_item);
|
||||||
refs = btrfs_extent_refs(eb, ei);
|
refs = btrfs_extent_refs(eb, ei);
|
||||||
|
gen = btrfs_extent_generation(eb, ei);
|
||||||
if (btrfs_extent_flags(eb, ei) & BTRFS_EXTENT_FLAG_TREE_BLOCK)
|
if (btrfs_extent_flags(eb, ei) & BTRFS_EXTENT_FLAG_TREE_BLOCK)
|
||||||
metadata = 1;
|
metadata = 1;
|
||||||
else
|
else
|
||||||
|
@ -5362,6 +5367,7 @@ static int process_extent_item(struct btrfs_root *root,
|
||||||
tmpl.metadata = metadata;
|
tmpl.metadata = metadata;
|
||||||
tmpl.found_rec = 1;
|
tmpl.found_rec = 1;
|
||||||
tmpl.max_size = num_bytes;
|
tmpl.max_size = num_bytes;
|
||||||
|
tmpl.generation = gen;
|
||||||
add_extent_rec(extent_cache, &tmpl);
|
add_extent_rec(extent_cache, &tmpl);
|
||||||
|
|
||||||
ptr = (unsigned long)(ei + 1);
|
ptr = (unsigned long)(ei + 1);
|
||||||
|
@ -5401,14 +5407,14 @@ static int process_extent_item(struct btrfs_root *root,
|
||||||
dref),
|
dref),
|
||||||
btrfs_extent_data_ref_offset(eb, dref),
|
btrfs_extent_data_ref_offset(eb, dref),
|
||||||
btrfs_extent_data_ref_count(eb, dref),
|
btrfs_extent_data_ref_count(eb, dref),
|
||||||
0, num_bytes);
|
gen, 0, num_bytes);
|
||||||
break;
|
break;
|
||||||
case BTRFS_SHARED_DATA_REF_KEY:
|
case BTRFS_SHARED_DATA_REF_KEY:
|
||||||
sref = (struct btrfs_shared_data_ref *)(iref + 1);
|
sref = (struct btrfs_shared_data_ref *)(iref + 1);
|
||||||
add_data_backref(extent_cache, key.objectid, offset,
|
add_data_backref(extent_cache, key.objectid, offset,
|
||||||
0, 0, 0,
|
0, 0, 0,
|
||||||
btrfs_shared_data_ref_count(eb, sref),
|
btrfs_shared_data_ref_count(eb, sref),
|
||||||
0, num_bytes);
|
gen, 0, num_bytes);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
|
@ -6355,7 +6361,7 @@ static int run_next_block(struct btrfs_root *root,
|
||||||
ref),
|
ref),
|
||||||
btrfs_extent_data_ref_offset(buf, ref),
|
btrfs_extent_data_ref_offset(buf, ref),
|
||||||
btrfs_extent_data_ref_count(buf, ref),
|
btrfs_extent_data_ref_count(buf, ref),
|
||||||
0, root->fs_info->sectorsize);
|
0, 0, root->fs_info->sectorsize);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (key.type == BTRFS_SHARED_DATA_REF_KEY) {
|
if (key.type == BTRFS_SHARED_DATA_REF_KEY) {
|
||||||
|
@ -6366,7 +6372,7 @@ static int run_next_block(struct btrfs_root *root,
|
||||||
add_data_backref(extent_cache,
|
add_data_backref(extent_cache,
|
||||||
key.objectid, key.offset, 0, 0, 0,
|
key.objectid, key.offset, 0, 0, 0,
|
||||||
btrfs_shared_data_ref_count(buf, ref),
|
btrfs_shared_data_ref_count(buf, ref),
|
||||||
0, root->fs_info->sectorsize);
|
0, 0, root->fs_info->sectorsize);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (key.type == BTRFS_ORPHAN_ITEM_KEY) {
|
if (key.type == BTRFS_ORPHAN_ITEM_KEY) {
|
||||||
|
@ -6433,7 +6439,8 @@ static int run_next_block(struct btrfs_root *root,
|
||||||
add_data_backref(extent_cache,
|
add_data_backref(extent_cache,
|
||||||
btrfs_file_extent_disk_bytenr(buf, fi),
|
btrfs_file_extent_disk_bytenr(buf, fi),
|
||||||
parent, owner, key.objectid, key.offset -
|
parent, owner, key.objectid, key.offset -
|
||||||
btrfs_file_extent_offset(buf, fi), 1, 1,
|
btrfs_file_extent_offset(buf, fi), 1,
|
||||||
|
btrfs_file_extent_generation(buf, fi), 1,
|
||||||
btrfs_file_extent_disk_num_bytes(buf, fi));
|
btrfs_file_extent_disk_num_bytes(buf, fi));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -6736,7 +6743,10 @@ static int record_extent(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_extent_item);
|
struct btrfs_extent_item);
|
||||||
|
|
||||||
btrfs_set_extent_refs(leaf, ei, 0);
|
btrfs_set_extent_refs(leaf, ei, 0);
|
||||||
btrfs_set_extent_generation(leaf, ei, rec->generation);
|
if (rec->generation)
|
||||||
|
btrfs_set_extent_generation(leaf, ei, rec->generation);
|
||||||
|
else
|
||||||
|
btrfs_set_extent_generation(leaf, ei, trans->transid);
|
||||||
|
|
||||||
if (back->is_data) {
|
if (back->is_data) {
|
||||||
btrfs_set_extent_flags(leaf, ei,
|
btrfs_set_extent_flags(leaf, ei,
|
||||||
|
|
Loading…
Reference in New Issue