Skip to contentSkip to conversation

btrfs-progs: lowmem fsck: Fix inlined data extent ref lookup

PATCH New Qu Wenruo 1 participant 3 messages Nov 13, 2017 Btrfs file system

lore
Share & tools
lore

Qu Wenruo

author
#0 lore raw

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.

Fixes b0d360b541f0 ("btrfs-progs: check: introduce function to check data backref in extent tree")
---
 cmds-check.c | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)
cmds-check.c +12 -2
index 5c822b848608..0ceff5b7bbea 100644
@@ -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
author
#1 lore raw

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
------

Fixes b0d360b541f0 ("btrfs-progs: check: introduce function to check data backref in extent tree")
---
 cmds-check.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
cmds-check.c +1 -1
index 0ceff5b7bbea..b9943a0d3a0f 100644
@@ -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
author
#2 lore raw

PATCH 3/3 btrfs-progs: fsck-test: Introduce test case for false data extent backref lost

In reply to Qu Wenruo

Introduce 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
new file mode 100644
index 0000000000000000000000000000000000000000..668589f46d330cb5d6ff10b108e62585875548ca
GIT binary patch
Signature · 1 line
2.15.0