diff options
author | Wang Xiaoguang <wangxg.fnst@cn.fujitsu.com> | 2016-06-22 09:57:01 +0800 |
---|---|---|
committer | Chris Mason <clm@fb.com> | 2016-06-23 10:44:41 -0700 |
commit | c0d2f6104e8ab2eb75e58e72494ad4b69c5227f8 (patch) | |
tree | 073eb178e3bcd74405321ddd40284b06771b8f12 /crypto/ripemd.h | |
parent | 415b35a55b57a701afe7391d32a6bb0193b7d3da (diff) | |
download | linux-c0d2f6104e8ab2eb75e58e72494ad4b69c5227f8.tar.gz linux-c0d2f6104e8ab2eb75e58e72494ad4b69c5227f8.tar.bz2 linux-c0d2f6104e8ab2eb75e58e72494ad4b69c5227f8.zip |
btrfs: fix disk_i_size update bug when fallocate() fails
When doing truncate operation, btrfs_setsize() will first call
truncate_setsize() to set new inode->i_size, but if later
btrfs_truncate() fails, btrfs_setsize() will call
"i_size_write(inode, BTRFS_I(inode)->disk_i_size)" to reset the
inmemory inode size, now bug occurs. It's because for truncate
case btrfs_ordered_update_i_size() directly uses inode->i_size
to update BTRFS_I(inode)->disk_i_size, indeed we should use the
"offset" argument to update disk_i_size. Here is the call graph:
==>btrfs_truncate()
====>btrfs_truncate_inode_items()
======>btrfs_ordered_update_i_size(inode, last_size, NULL);
Here btrfs_ordered_update_i_size()'s offset argument is last_size.
And below test case can reveal this bug:
dd if=/dev/zero of=fs.img bs=$((1024*1024)) count=100
dev=$(losetup --show -f fs.img)
mkdir -p /mnt/mntpoint
mkfs.btrfs -f $dev
mount $dev /mnt/mntpoint
cd /mnt/mntpoint
echo "workdir is: /mnt/mntpoint"
blocksize=$((128 * 1024))
dd if=/dev/zero of=testfile bs=$blocksize count=1
sync
count=$((17*1024*1024*1024/blocksize))
echo "file size is:" $((count*blocksize))
for ((i = 1; i <= $count; i++)); do
i=$((i + 1))
dst_offset=$((blocksize * i))
xfs_io -f -c "reflink testfile 0 $dst_offset $blocksize"\
testfile > /dev/null
done
sync
truncate --size 0 testfile
ls -l testfile
du -sh testfile
exit
In this case, truncate operation will fail for enospc reason and
"du -sh testfile" returns value greater than 0, but testfile's
size is 0, we need to reflect correct inode->i_size.
Signed-off-by: Wang Xiaoguang <wangxg.fnst@cn.fujitsu.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Signed-off-by: Chris Mason <clm@fb.com>
Diffstat (limited to 'crypto/ripemd.h')
0 files changed, 0 insertions, 0 deletions