Skip to content

Commit 15c7745

Browse files
boryaskdave
authored andcommitted
btrfs: return whole extents in fiemap
`xfs_io -c 'fiemap <off> <len>' <file>` can give surprising results on btrfs that differ from xfs. btrfs prints out extents trimmed to fit the user input. If the user's fiemap request has an offset, then rather than returning each whole extent which intersects that range, we also trim the start extent to not have start < off. Documentation in filesystems/fiemap.txt and the xfs_io man page suggests that returning the whole extent is expected. Some cases which all yield the same fiemap in xfs, but not btrfs: dd if=/dev/zero of=$f bs=4k count=1 sudo xfs_io -c 'fiemap 0 1024' $f 0: [0..7]: 26624..26631 sudo xfs_io -c 'fiemap 2048 1024' $f 0: [4..7]: 26628..26631 sudo xfs_io -c 'fiemap 2048 4096' $f 0: [4..7]: 26628..26631 sudo xfs_io -c 'fiemap 3584 512' $f 0: [7..7]: 26631..26631 sudo xfs_io -c 'fiemap 4091 5' $f 0: [7..6]: 26631..26630 I believe this is a consequence of the logic for merging contiguous extents represented by separate extent items. That logic needs to track the last offset as it loops through the extent items, which happens to pick up the start offset on the first iteration, and trim off the beginning of the full extent. To fix it, start `off` at 0 rather than `start` so that we keep the iteration/merging intact without cutting off the start of the extent. after the fix, all the above commands give: 0: [0..7]: 26624..26631 The merging logic is exercised by fstest generic/483, and I have written a new fstest for checking we don't have backwards or zero-length fiemaps for cases like those above. Reviewed-by: Josef Bacik <[email protected]> Signed-off-by: Boris Burkov <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent 71795ee commit 15c7745

File tree

1 file changed

+6
-1
lines changed

1 file changed

+6
-1
lines changed

fs/btrfs/extent_io.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5210,7 +5210,7 @@ int extent_fiemap(struct btrfs_inode *inode, struct fiemap_extent_info *fieinfo,
52105210
u64 start, u64 len)
52115211
{
52125212
int ret = 0;
5213-
u64 off = start;
5213+
u64 off;
52145214
u64 max = start + len;
52155215
u32 flags = 0;
52165216
u32 found_type;
@@ -5245,6 +5245,11 @@ int extent_fiemap(struct btrfs_inode *inode, struct fiemap_extent_info *fieinfo,
52455245
goto out_free_ulist;
52465246
}
52475247

5248+
/*
5249+
* We can't initialize that to 'start' as this could miss extents due
5250+
* to extent item merging
5251+
*/
5252+
off = 0;
52485253
start = round_down(start, btrfs_inode_sectorsize(inode));
52495254
len = round_up(max, btrfs_inode_sectorsize(inode)) - start;
52505255

0 commit comments

Comments
 (0)