Commit 7f4f6e0a authored by Josef Bacik's avatar Josef Bacik Committed by Chris Mason

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: default avatarJosef Bacik <jbacik@fusionio.com>
Signed-off-by: default avatarChris Mason <chris.mason@fusionio.com>
parent f45388f3
...@@ -3861,6 +3861,7 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans, ...@@ -3861,6 +3861,7 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
u64 extent_num_bytes = 0; u64 extent_num_bytes = 0;
u64 extent_offset = 0; u64 extent_offset = 0;
u64 item_end = 0; u64 item_end = 0;
u64 last_size = (u64)-1;
u32 found_type = (u8)-1; u32 found_type = (u8)-1;
int found_extent; int found_extent;
int del_item; int del_item;
...@@ -3958,6 +3959,11 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans, ...@@ -3958,6 +3959,11 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
if (found_type != BTRFS_EXTENT_DATA_KEY) if (found_type != BTRFS_EXTENT_DATA_KEY)
goto delete; goto delete;
if (del_item)
last_size = found_key.offset;
else
last_size = new_size;
if (extent_type != BTRFS_FILE_EXTENT_INLINE) { if (extent_type != BTRFS_FILE_EXTENT_INLINE) {
u64 num_dec; u64 num_dec;
extent_start = btrfs_file_extent_disk_bytenr(leaf, fi); extent_start = btrfs_file_extent_disk_bytenr(leaf, fi);
...@@ -4069,6 +4075,8 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans, ...@@ -4069,6 +4075,8 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
btrfs_abort_transaction(trans, root, ret); btrfs_abort_transaction(trans, root, ret);
} }
error: error:
if (last_size != (u64)-1)
btrfs_ordered_update_i_size(inode, last_size, NULL);
btrfs_free_path(path); btrfs_free_path(path);
return err; return err;
} }
...@@ -4397,8 +4405,26 @@ static int btrfs_setsize(struct inode *inode, struct iattr *attr) ...@@ -4397,8 +4405,26 @@ static int btrfs_setsize(struct inode *inode, struct iattr *attr)
btrfs_inode_resume_unlocked_dio(inode); btrfs_inode_resume_unlocked_dio(inode);
ret = btrfs_truncate(inode); ret = btrfs_truncate(inode);
if (ret && inode->i_nlink) if (ret && inode->i_nlink) {
int err;
/*
* failed to truncate, disk_i_size is only adjusted down
* as we remove extents, so it should represent the true
* size of the inode, so reset the in memory size and
* delete our orphan entry.
*/
trans = btrfs_join_transaction(root);
if (IS_ERR(trans)) {
btrfs_orphan_del(NULL, inode); btrfs_orphan_del(NULL, inode);
return ret;
}
i_size_write(inode, BTRFS_I(inode)->disk_i_size);
err = btrfs_orphan_del(trans, inode);
if (err)
btrfs_abort_transaction(trans, root, err);
btrfs_end_transaction(trans, root);
}
} }
return ret; return ret;
...@@ -7537,7 +7563,6 @@ static int btrfs_truncate(struct inode *inode) ...@@ -7537,7 +7563,6 @@ static int btrfs_truncate(struct inode *inode)
u64 min_size = btrfs_calc_trunc_metadata_size(root, 1); u64 min_size = btrfs_calc_trunc_metadata_size(root, 1);
btrfs_wait_ordered_range(inode, inode->i_size & (~mask), (u64)-1); btrfs_wait_ordered_range(inode, inode->i_size & (~mask), (u64)-1);
btrfs_ordered_update_i_size(inode, inode->i_size, NULL);
/* /*
* Yes ladies and gentelment, this is indeed ugly. The fact is we have * Yes ladies and gentelment, this is indeed ugly. The fact is we have
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment