Skip to content

Commit d4589b2

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 # Add a 2M extent at the file offset 1M without increasing i_size. fallocate -n -o 1M -l 2M $MNT/file1 # Unmount and mount again to clear the in-memory extent tree. umount $MNT mount $DEV $MNT # Use a length that fits within the range of the previously allocated # extent. We want the next fallocate to only increase the i_size. len=$((1 * 1024 * 1024)) # fallocate on the prealloc extent to change i_size. fallocate -o 1M -l $len $MNT/file1 # Check the file size, expecting 2M. du --bytes $MNT/file1 # Unmount and mount again the fs. umount $MNT mount $DEV $MNT # The file size should be the same as before (2M). 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 <austinchang@synology.com> Reviewed-by: Filipe Manana <fdmanana@suse.com> Signed-off-by: Filipe Manana <fdmanana@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
1 parent 27e8fcc commit d4589b2

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
@@ -2857,12 +2857,22 @@ static int btrfs_fallocate_update_isize(struct inode *inode,
28572857
{
28582858
struct btrfs_trans_handle *trans;
28592859
struct btrfs_root *root = BTRFS_I(inode)->root;
2860+
u64 range_start;
2861+
u64 range_end;
28602862
int ret;
28612863
int ret2;
28622864

28632865
if (mode & FALLOC_FL_KEEP_SIZE || end <= i_size_read(inode))
28642866
return 0;
28652867

2868+
range_start = round_down(i_size_read(inode), root->fs_info->sectorsize);
2869+
range_end = round_up(end, root->fs_info->sectorsize);
2870+
2871+
ret = btrfs_inode_set_file_extent_range(BTRFS_I(inode), range_start,
2872+
range_end - range_start);
2873+
if (ret)
2874+
return ret;
2875+
28662876
trans = btrfs_start_transaction(root, 1);
28672877
if (IS_ERR(trans))
28682878
return PTR_ERR(trans);

0 commit comments

Comments
 (0)