Skip to content

Commit 46c93e3

Browse files
adam900710kdave
authored andcommitted
btrfs-progs: fix a bug in btrfs_find_item()
[BUG] There is a seldomly utilized function, btrfs_find_item(), which has no comment and is not behaving correctly. Inside backref.c, iterate_inode_refs() and btrfs_ref_to_path() both utilize this function, to find the parent inode. However btrfs_find_item() will never return 0 if @ioff is passed as 0 for such usage, result early failure for all kinds of inode iteration functions. [CAUSE] Both functions pass 0 as the @ioff parameter initially, e.g: We have the following fs tree root: item 0 key (256 INODE_ITEM 0) itemoff 16123 itemsize 160 generation 3 transid 9 size 6 nbytes 16384 block group 0 mode 40755 links 1 uid 0 gid 0 rdev 0 sequence 1 flags 0x0(none) item 1 key (256 INODE_REF 256) itemoff 16111 itemsize 12 index 0 namelen 2 name: .. item 2 key (256 DIR_ITEM 2507850652) itemoff 16078 itemsize 33 location key (257 INODE_ITEM 0) type FILE transid 9 data_len 0 name_len 3 name: foo item 3 key (256 DIR_INDEX 2) itemoff 16045 itemsize 33 location key (257 INODE_ITEM 0) type FILE transid 9 data_len 0 name_len 3 name: foo item 4 key (257 INODE_ITEM 0) itemoff 15885 itemsize 160 generation 9 transid 9 size 16384 nbytes 16384 block group 0 mode 100600 links 1 uid 0 gid 0 rdev 0 sequence 4 flags 0x0(none) item 5 key (257 INODE_REF 256) itemoff 15872 itemsize 13 index 2 namelen 3 name: foo item 6 key (257 EXTENT_DATA 0) itemoff 15819 itemsize 53 generation 9 type 1 (regular) extent data disk byte 13631488 nr 16384 extent data offset 0 nr 16384 ram 16384 extent compression 0 (none) Then we call paths_from_inode() with: - @Inum = 257 - ipath = {.fs_root = 5} Then we got the following sequence: iterate_irefs(257, fs_root, inode_to_path) |- iterate_inode_refs() |- inode_ref_info() |- btrfs_find_item(257, 0, fs_root) | Returned 1, with @found_key updated to | (257, INODE_REF, 256). This makes iterate_irefs() exit immediately, but obviously that btrfs_find_item() call is to find any INODE_REF, not to find the exact match. [FIX] If btrfs_find_item() found an item matching the objectid and type, then it should return 0 other than 1. Fix it and keep the behavior the same across btrfs-progs and the kernel. Since we're here, also add some comments explaining the function. Signed-off-by: Qu Wenruo <wqu@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
1 parent 5ec0cf7 commit 46c93e3

File tree

1 file changed

+14
-4
lines changed

1 file changed

+14
-4
lines changed

kernel-shared/ctree.c

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1246,6 +1246,17 @@ static void reada_for_search(struct btrfs_fs_info *fs_info,
12461246
}
12471247
}
12481248

1249+
/*
1250+
* Find the first key in @fs_root that matches all the following conditions:
1251+
*
1252+
* - key.obojectid == @iobjectid
1253+
* - key.type == @key_type
1254+
* - key.offset >= ioff
1255+
*
1256+
* Return 0 if such key can be found, and @found_key is updated.
1257+
* Return >0 if no such key can be found.
1258+
* Return <0 for critical errors.
1259+
*/
12491260
int btrfs_find_item(struct btrfs_root *fs_root, struct btrfs_path *found_path,
12501261
u64 iobjectid, u64 ioff, u8 key_type,
12511262
struct btrfs_key *found_key)
@@ -1279,11 +1290,10 @@ int btrfs_find_item(struct btrfs_root *fs_root, struct btrfs_path *found_path,
12791290
}
12801291

12811292
btrfs_item_key_to_cpu(eb, found_key, path->slots[0]);
1282-
if (found_key->type != key.type ||
1283-
found_key->objectid != key.objectid) {
1293+
if (found_key->type != key.type || found_key->objectid != key.objectid)
12841294
ret = 1;
1285-
goto out;
1286-
}
1295+
else
1296+
ret = 0;
12871297

12881298
out:
12891299
if (path != found_path)

0 commit comments

Comments
 (0)