diff options
author | Josef Bacik <jbacik@fusionio.com> | 2013-08-29 16:43:28 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@fusionio.com> | 2013-09-01 08:16:40 -0400 |
commit | 7f4f6e0a3f6db9c214de38c792c483b8076bcd6a (patch) | |
tree | aaf7daed23b75d8c5400cee9cc39f12db134a7b3 /fs/btrfs/inode.c | |
parent | f45388f3874535062526ec071284d836f5a4b5de (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.c | 31 |
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 | } |
4071 | error: | 4077 | error: |
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 |