Skip to content

Commit 3b1a4a5

Browse files
austin880625synokdave
authored andcommitted
btrfs: mark dirty extent range for out of bound prealloc extents
In btrfs_fallocate(), when the allocated range overlaps with a prealloc extent and the extent starts after i_size, the range doesn't get marked dirty in file_extent_tree. This results in persisting an incorrect disk_i_size for the inode when not using the no-holes feature. This is reproducible since commit 41a2ee7 ("btrfs: introduce per-inode file extent tree"), then became hidden since commit 3d7db6e ("btrfs: don't allocate file extent tree for non regular files") and then visible again after commit 8679d26 ("btrfs: initialize inode::file_extent_tree after i_mode has been set"), which fixes the previous commit. The following reproducer triggers the problem: $ cat test.sh MNT=/mnt/test DEV=/dev/vdb mkdir -p $MNT mkfs.btrfs -f -O ^no-holes $DEV mount $DEV $MNT touch $MNT/file1 fallocate -n -o 1M -l 2M $MNT/file1 umount $MNT mount $DEV $MNT len=$((1 * 1024 * 1024)) fallocate -o 1M -l $len $MNT/file1 du --bytes $MNT/file1 umount $MNT mount $DEV $MNT du --bytes $MNT/file1 umount $MNT Running the reproducer gives the following result: $ ./test.sh (...) 2097152 /mnt/test/file1 1048576 /mnt/test/file1 The difference is exactly 1048576 as we assigned. Fix by adding a call to btrfs_inode_set_file_extent_range() in btrfs_fallocate_update_isize(). Fixes: 41a2ee7 ("btrfs: introduce per-inode file extent tree") Signed-off-by: austinchang <[email protected]> Reviewed-by: Filipe Manana <[email protected]> Signed-off-by: Filipe Manana <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent 953902e commit 3b1a4a5

File tree

1 file changed

+10
-0
lines changed

1 file changed

+10
-0
lines changed

fs/btrfs/file.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2854,12 +2854,22 @@ static int btrfs_fallocate_update_isize(struct inode *inode,
28542854
{
28552855
struct btrfs_trans_handle *trans;
28562856
struct btrfs_root *root = BTRFS_I(inode)->root;
2857+
u64 range_start;
2858+
u64 range_end;
28572859
int ret;
28582860
int ret2;
28592861

28602862
if (mode & FALLOC_FL_KEEP_SIZE || end <= i_size_read(inode))
28612863
return 0;
28622864

2865+
range_start = round_down(i_size_read(inode), root->fs_info->sectorsize);
2866+
range_end = round_up(end, root->fs_info->sectorsize);
2867+
2868+
ret = btrfs_inode_set_file_extent_range(BTRFS_I(inode), range_start,
2869+
range_end - range_start);
2870+
if (ret)
2871+
return ret;
2872+
28632873
trans = btrfs_start_transaction(root, 1);
28642874
if (IS_ERR(trans))
28652875
return PTR_ERR(trans);

0 commit comments

Comments
 (0)