aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/inode.c
diff options
context:
space:
mode:
authorJosef Bacik <jbacik@fusionio.com>2013-08-29 16:43:28 -0400
committerChris Mason <chris.mason@fusionio.com>2013-09-01 08:16:40 -0400
commit7f4f6e0a3f6db9c214de38c792c483b8076bcd6a (patch)
treeaaf7daed23b75d8c5400cee9cc39f12db134a7b3 /fs/btrfs/inode.c
parentf45388f3874535062526ec071284d836f5a4b5de (diff)
Btrfs: only update disk_i_size as we remove extents
This fixes a problem where if we fail a truncate we will leave the i_size set where we wanted to truncate to instead of where we were able to truncate to. Fix this by making btrfs_truncate_inode_items do the disk_i_size update as it removes extents, that way it will always be consistent with where its extents are. Then if the truncate fails at all we can update the in-ram i_size with what we have on disk and delete the orphan item. Thanks, Signed-off-by: Josef Bacik <jbacik@fusionio.com> Signed-off-by: Chris Mason <chris.mason@fusionio.com>
Diffstat (limited to 'fs/btrfs/inode.c')
-rw-r--r--fs/btrfs/inode.c31
1 files changed, 28 insertions, 3 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index f0e41b840739..6091ba9d2494 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -3861,6 +3861,7 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
3861 u64 extent_num_bytes = 0; 3861 u64 extent_num_bytes = 0;
3862 u64 extent_offset = 0; 3862 u64 extent_offset = 0;
3863 u64 item_end = 0; 3863 u64 item_end = 0;
3864 u64 last_size = (u64)-1;
3864 u32 found_type = (u8)-1; 3865 u32 found_type = (u8)-1;
3865 int found_extent; 3866 int found_extent;
3866 int del_item; 3867 int del_item;
@@ -3958,6 +3959,11 @@ search_again:
3958 if (found_type != BTRFS_EXTENT_DATA_KEY) 3959 if (found_type != BTRFS_EXTENT_DATA_KEY)
3959 goto delete; 3960 goto delete;
3960 3961
3962 if (del_item)
3963 last_size = found_key.offset;
3964 else
3965 last_size = new_size;
3966
3961 if (extent_type != BTRFS_FILE_EXTENT_INLINE) { 3967 if (extent_type != BTRFS_FILE_EXTENT_INLINE) {
3962 u64 num_dec; 3968 u64 num_dec;
3963 extent_start = btrfs_file_extent_disk_bytenr(leaf, fi); 3969 extent_start = btrfs_file_extent_disk_bytenr(leaf, fi);
@@ -4069,6 +4075,8 @@ out:
4069 btrfs_abort_transaction(trans, root, ret); 4075 btrfs_abort_transaction(trans, root, ret);
4070 } 4076 }
4071error: 4077error:
4078 if (last_size != (u64)-1)
4079 btrfs_ordered_update_i_size(inode, last_size, NULL);
4072 btrfs_free_path(path); 4080 btrfs_free_path(path);
4073 return err; 4081 return err;
4074} 4082}
@@ -4397,8 +4405,26 @@ static int btrfs_setsize(struct inode *inode, struct iattr *attr)
4397 btrfs_inode_resume_unlocked_dio(inode); 4405 btrfs_inode_resume_unlocked_dio(inode);
4398 4406
4399 ret = btrfs_truncate(inode); 4407 ret = btrfs_truncate(inode);
4400 if (ret && inode->i_nlink) 4408 if (ret && inode->i_nlink) {
4401 btrfs_orphan_del(NULL, inode); 4409 int err;
4410
4411 /*
4412 * failed to truncate, disk_i_size is only adjusted down
4413 * as we remove extents, so it should represent the true
4414 * size of the inode, so reset the in memory size and
4415 * delete our orphan entry.
4416 */
4417 trans = btrfs_join_transaction(root);
4418 if (IS_ERR(trans)) {
4419 btrfs_orphan_del(NULL, inode);
4420 return ret;
4421 }
4422 i_size_write(inode, BTRFS_I(inode)->disk_i_size);
4423 err = btrfs_orphan_del(trans, inode);
4424 if (err)
4425 btrfs_abort_transaction(trans, root, err);
4426 btrfs_end_transaction(trans, root);
4427 }
4402 } 4428 }
4403 4429
4404 return ret; 4430 return ret;
@@ -7537,7 +7563,6 @@ static int btrfs_truncate(struct inode *inode)
7537 u64 min_size = btrfs_calc_trunc_metadata_size(root, 1); 7563 u64 min_size = btrfs_calc_trunc_metadata_size(root, 1);
7538 7564
7539 btrfs_wait_ordered_range(inode, inode->i_size & (~mask), (u64)-1); 7565 btrfs_wait_ordered_range(inode, inode->i_size & (~mask), (u64)-1);
7540 btrfs_ordered_update_i_size(inode, inode->i_size, NULL);
7541 7566
7542 /* 7567 /*
7543 * Yes ladies and gentelment, this is indeed ugly. The fact is we have 7568 * Yes ladies and gentelment, this is indeed ugly. The fact is we have