diff options
author | Miao Xie <miaox@cn.fujitsu.com> | 2011-12-14 20:12:01 -0500 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2011-12-15 10:50:35 -0500 |
commit | f4a2f4c548296168832ad4ab7e7f7b0cd0bf1214 (patch) | |
tree | 10df3e81cc6a10253bb007858ee862a91c596335 /fs | |
parent | 5dbc8fca8ef5d719014f22345d990e957dcfc692 (diff) |
Btrfs: fix wrong i_size when truncating a file to a larger size
Btrfsck report error 100 after the 83th case of xfstests was run, it means
the i_size of the file is wrong.
The reason of this bug is that:
Btrfs increased i_size of the file at the beginning, but it failed to expand
the file, and failed to update the i_size to the old size because there is no
enough space in the file system, so we found a wrong i_size.
This patch fixes this bug by updating the i_size just when we pass the file
expanding and get enough space to update i-node.
Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/inode.c | 18 |
1 files changed, 12 insertions, 6 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index c5ccec23984c..4bbceb928aff 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -3370,6 +3370,8 @@ int btrfs_cont_expand(struct inode *inode, loff_t oldsize, loff_t size) | |||
3370 | 3370 | ||
3371 | static int btrfs_setsize(struct inode *inode, loff_t newsize) | 3371 | static int btrfs_setsize(struct inode *inode, loff_t newsize) |
3372 | { | 3372 | { |
3373 | struct btrfs_root *root = BTRFS_I(inode)->root; | ||
3374 | struct btrfs_trans_handle *trans; | ||
3373 | loff_t oldsize = i_size_read(inode); | 3375 | loff_t oldsize = i_size_read(inode); |
3374 | int ret; | 3376 | int ret; |
3375 | 3377 | ||
@@ -3377,16 +3379,20 @@ static int btrfs_setsize(struct inode *inode, loff_t newsize) | |||
3377 | return 0; | 3379 | return 0; |
3378 | 3380 | ||
3379 | if (newsize > oldsize) { | 3381 | if (newsize > oldsize) { |
3380 | i_size_write(inode, newsize); | ||
3381 | btrfs_ordered_update_i_size(inode, i_size_read(inode), NULL); | ||
3382 | truncate_pagecache(inode, oldsize, newsize); | 3382 | truncate_pagecache(inode, oldsize, newsize); |
3383 | ret = btrfs_cont_expand(inode, oldsize, newsize); | 3383 | ret = btrfs_cont_expand(inode, oldsize, newsize); |
3384 | if (ret) { | 3384 | if (ret) |
3385 | btrfs_setsize(inode, oldsize); | ||
3386 | return ret; | 3385 | return ret; |
3387 | } | ||
3388 | 3386 | ||
3389 | mark_inode_dirty(inode); | 3387 | trans = btrfs_start_transaction(root, 1); |
3388 | if (IS_ERR(trans)) | ||
3389 | return PTR_ERR(trans); | ||
3390 | |||
3391 | i_size_write(inode, newsize); | ||
3392 | btrfs_ordered_update_i_size(inode, i_size_read(inode), NULL); | ||
3393 | ret = btrfs_update_inode(trans, root, inode); | ||
3394 | |||
3395 | btrfs_end_transaction_throttle(trans, root); | ||
3390 | } else { | 3396 | } else { |
3391 | 3397 | ||
3392 | /* | 3398 | /* |