btrfs-progs: lowmem fsck: Fix inlined data extent ref lookup
PATCH 1/3 btrfs-progs: lowmem fsck: Fix inlined data extent ref lookup
When lowmem fsck tries to find backref of a specified file extent, it searches inlined data ref first.
However, extent data ref contains owner root objectid, inode number and calculated offset (file offset - extent offset).
The code only checks owner root objectid, not checking inode number nor calculated offset.
This makes lowmem mode fails to detect any backref mismatch if there is a inlined data ref with the same owner objectid.
Fix it by also checking extent data ref's objectid and offset.
--- cmds-check.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-)
cmds-check.c +12 -2
@@ -10411,11 +10411,11 @@ static int check_extent_data_item(struct btrfs_root *root,u64 disk_num_bytes;u64 extent_num_bytes;u64 extent_flags; +u64 offset;u32 item_size;unsigned long end;unsigned long ptr;int type; -u64 ref_root;int found_dbackref =0 ;int err =0 ;int ret;
@@ -10431,6 +10431,7 @@ static int check_extent_data_item(struct btrfs_root *root, disk_bytenr =btrfs_file_extent_disk_bytenr (eb, fi); disk_num_bytes =btrfs_file_extent_disk_num_bytes (eb, fi); extent_num_bytes =btrfs_file_extent_num_bytes (eb, fi); + offset =btrfs_file_extent_offset (eb, fi);/* Check unaligned disk_num_bytes and num_bytes */ if (!IS_ALIGNED (disk_num_bytes, root->fs_info->sectorsize)) {
@@ -10483,13 +10484,22 @@ static int check_extent_data_item(struct btrfs_root *root, ptr = (unsigned long )iref; end = (unsigned long )ei + item_size;while (ptr < end) { +u64 ref_root; +u64 ref_objectid; +u64 ref_offset; + iref = (struct btrfs_extent_inline_ref *)ptr; type =btrfs_extent_inline_ref_type (leaf, iref); dref = (struct btrfs_extent_data_ref *)(&iref->offset);if (type ==BTRFS_EXTENT_DATA_REF_KEY ) { ref_root =btrfs_extent_data_ref_root (leaf, dref); -if (ref_root == owner || ref_root == root->objectid) + ref_objectid =btrfs_extent_data_ref_objectid (leaf, dref); + ref_offset =btrfs_extent_data_ref_offset (leaf, dref); + +if ((ref_root == owner || ref_root == root->objectid) && + ref_objectid == fi_key.objectid && + ref_offset == fi_key.offset - offset) found_dbackref =1 ; }else if (type ==BTRFS_SHARED_DATA_REF_KEY ) { found_dbackref = !check_tree_block_ref(root, NULL,
Signature · 1 line
2.15.0
PATCH 2/3 btrfs-progs: lowmem fsck: Fix false backref lost warning for keyed extent data ref
For keyed extent ref, its offset is calculated offset (file offset - file extent offset), just like inlined extent data ref.
However the code is using file offset to hash extent data ref offset, causing false backref lost warning like:
------
ERROR: data extent[16913485824 7577600] backref lost
------
--- cmds-check.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
cmds-check.c +1 -1
@@ -10519,7 +10519,7 @@ static int check_extent_data_item(struct btrfs_root *root, dbref_key.objectid =btrfs_file_extent_disk_bytenr (eb, fi); dbref_key.type =BTRFS_EXTENT_DATA_REF_KEY ; dbref_key.offset =hash_extent_data_ref (root->objectid, - fi_key.objectid, fi_key.offset); + fi_key.objectid, fi_key.offset - offset); ret =btrfs_search_slot (NULL , root->fs_info->extent_root, &dbref_key, &path,0 ,0 );
Signature · 1 line
2.15.0
PATCH 3/3 btrfs-progs: fsck-test: Introduce test case for false data extent backref lost
In reply to Qu WenruoIntroduce a new test image, which has an extent item with no inlined extent data ref, but all keyed extent data ref.
Only in this case we can trigger fase data extent backref lost bug in lowmem mode.
--- .../020-extent-ref-cases/keyed_data_ref_only.img | Bin 0 -> 4096 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/fsck-tests/020-extent-ref-cases/keyed_data_ref_only.img
tests/fsck-tests/020-extent-ref-cases/keyed_data_ref_only.img new file binary +0 -0
Signature · 1 line
2.15.0