Skip to content

Commit ddfae63

Browse files
josefbacikkdave
authored andcommitted
btrfs: move btrfs_truncate_block out of trans handle
Since we do a delalloc reserve in btrfs_truncate_block we can deadlock with freeze. If somebody else is trying to allocate metadata for this inode and it gets stuck in start_delalloc_inodes because of freeze we will deadlock. Be safe and move this outside of a trans handle. This also has a side-effect of making sure that we're not leaving stale data behind in the other_encoding or encryption case. Not an issue now since nobody uses it, but it would be a problem in the future. Signed-off-by: Josef Bacik <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent ce8ea7c commit ddfae63

File tree

1 file changed

+45
-75
lines changed

1 file changed

+45
-75
lines changed

fs/btrfs/inode.c

Lines changed: 45 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -4360,47 +4360,11 @@ static int truncate_space_check(struct btrfs_trans_handle *trans,
43604360

43614361
}
43624362

4363-
static int truncate_inline_extent(struct inode *inode,
4364-
struct btrfs_path *path,
4365-
struct btrfs_key *found_key,
4366-
const u64 item_end,
4367-
const u64 new_size)
4368-
{
4369-
struct extent_buffer *leaf = path->nodes[0];
4370-
int slot = path->slots[0];
4371-
struct btrfs_file_extent_item *fi;
4372-
u32 size = (u32)(new_size - found_key->offset);
4373-
struct btrfs_root *root = BTRFS_I(inode)->root;
4374-
4375-
fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item);
4376-
4377-
if (btrfs_file_extent_compression(leaf, fi) != BTRFS_COMPRESS_NONE) {
4378-
loff_t offset = new_size;
4379-
loff_t page_end = ALIGN(offset, PAGE_SIZE);
4380-
4381-
/*
4382-
* Zero out the remaining of the last page of our inline extent,
4383-
* instead of directly truncating our inline extent here - that
4384-
* would be much more complex (decompressing all the data, then
4385-
* compressing the truncated data, which might be bigger than
4386-
* the size of the inline extent, resize the extent, etc).
4387-
* We release the path because to get the page we might need to
4388-
* read the extent item from disk (data not in the page cache).
4389-
*/
4390-
btrfs_release_path(path);
4391-
return btrfs_truncate_block(inode, offset, page_end - offset,
4392-
0);
4393-
}
4394-
4395-
btrfs_set_file_extent_ram_bytes(leaf, fi, size);
4396-
size = btrfs_file_extent_calc_inline_size(size);
4397-
btrfs_truncate_item(root->fs_info, path, size, 1);
4398-
4399-
if (test_bit(BTRFS_ROOT_REF_COWS, &root->state))
4400-
inode_sub_bytes(inode, item_end + 1 - new_size);
4401-
4402-
return 0;
4403-
}
4363+
/*
4364+
* Return this if we need to call truncate_block for the last bit of the
4365+
* truncate.
4366+
*/
4367+
#define NEED_TRUNCATE_BLOCK 1
44044368

44054369
/*
44064370
* this can truncate away extent items, csum items and directory items.
@@ -4561,11 +4525,6 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
45614525
if (found_type != BTRFS_EXTENT_DATA_KEY)
45624526
goto delete;
45634527

4564-
if (del_item)
4565-
last_size = found_key.offset;
4566-
else
4567-
last_size = new_size;
4568-
45694528
if (extent_type != BTRFS_FILE_EXTENT_INLINE) {
45704529
u64 num_dec;
45714530
extent_start = btrfs_file_extent_disk_bytenr(leaf, fi);
@@ -4607,40 +4566,30 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
46074566
*/
46084567
if (!del_item &&
46094568
btrfs_file_extent_encryption(leaf, fi) == 0 &&
4610-
btrfs_file_extent_other_encoding(leaf, fi) == 0) {
4611-
4569+
btrfs_file_extent_other_encoding(leaf, fi) == 0 &&
4570+
btrfs_file_extent_compression(leaf, fi) == 0) {
4571+
u32 size = (u32)(new_size - found_key.offset);
4572+
4573+
btrfs_set_file_extent_ram_bytes(leaf, fi, size);
4574+
size = btrfs_file_extent_calc_inline_size(size);
4575+
btrfs_truncate_item(root->fs_info, path, size, 1);
4576+
} else if (!del_item) {
46124577
/*
4613-
* Need to release path in order to truncate a
4614-
* compressed extent. So delete any accumulated
4615-
* extent items so far.
4578+
* We have to bail so the last_size is set to
4579+
* just before this extent.
46164580
*/
4617-
if (btrfs_file_extent_compression(leaf, fi) !=
4618-
BTRFS_COMPRESS_NONE && pending_del_nr) {
4619-
err = btrfs_del_items(trans, root, path,
4620-
pending_del_slot,
4621-
pending_del_nr);
4622-
if (err) {
4623-
btrfs_abort_transaction(trans,
4624-
err);
4625-
goto error;
4626-
}
4627-
pending_del_nr = 0;
4628-
}
4581+
err = NEED_TRUNCATE_BLOCK;
4582+
break;
4583+
}
46294584

4630-
err = truncate_inline_extent(inode, path,
4631-
&found_key,
4632-
item_end,
4633-
new_size);
4634-
if (err) {
4635-
btrfs_abort_transaction(trans, err);
4636-
goto error;
4637-
}
4638-
} else if (test_bit(BTRFS_ROOT_REF_COWS,
4639-
&root->state)) {
4585+
if (test_bit(BTRFS_ROOT_REF_COWS, &root->state))
46404586
inode_sub_bytes(inode, item_end + 1 - new_size);
4641-
}
46424587
}
46434588
delete:
4589+
if (del_item)
4590+
last_size = found_key.offset;
4591+
else
4592+
last_size = new_size;
46444593
if (del_item) {
46454594
if (!pending_del_nr) {
46464595
/* no pending yet, add ourselves */
@@ -9338,12 +9287,12 @@ static int btrfs_truncate(struct inode *inode)
93389287
ret = btrfs_truncate_inode_items(trans, root, inode,
93399288
inode->i_size,
93409289
BTRFS_EXTENT_DATA_KEY);
9290+
trans->block_rsv = &fs_info->trans_block_rsv;
93419291
if (ret != -ENOSPC && ret != -EAGAIN) {
93429292
err = ret;
93439293
break;
93449294
}
93459295

9346-
trans->block_rsv = &fs_info->trans_block_rsv;
93479296
ret = btrfs_update_inode(trans, root, inode);
93489297
if (ret) {
93499298
err = ret;
@@ -9367,6 +9316,27 @@ static int btrfs_truncate(struct inode *inode)
93679316
trans->block_rsv = rsv;
93689317
}
93699318

9319+
/*
9320+
* We can't call btrfs_truncate_block inside a trans handle as we could
9321+
* deadlock with freeze, if we got NEED_TRUNCATE_BLOCK then we know
9322+
* we've truncated everything except the last little bit, and can do
9323+
* btrfs_truncate_block and then update the disk_i_size.
9324+
*/
9325+
if (ret == NEED_TRUNCATE_BLOCK) {
9326+
btrfs_end_transaction(trans);
9327+
btrfs_btree_balance_dirty(fs_info);
9328+
9329+
ret = btrfs_truncate_block(inode, inode->i_size, 0, 0);
9330+
if (ret)
9331+
goto out;
9332+
trans = btrfs_start_transaction(root, 1);
9333+
if (IS_ERR(trans)) {
9334+
ret = PTR_ERR(trans);
9335+
goto out;
9336+
}
9337+
btrfs_ordered_update_i_size(inode, inode->i_size, NULL);
9338+
}
9339+
93709340
if (ret == 0 && inode->i_nlink > 0) {
93719341
trans->block_rsv = root->orphan_block_rsv;
93729342
ret = btrfs_orphan_del(trans, BTRFS_I(inode));

0 commit comments

Comments
 (0)