|
@@ -6482,6 +6482,7 @@ static int btrfs_truncate(struct inode *inode)
|
|
|
struct btrfs_trans_handle *trans;
|
|
|
unsigned long nr;
|
|
|
u64 mask = root->sectorsize - 1;
|
|
|
+ u64 min_size = btrfs_calc_trans_metadata_size(root, 2);
|
|
|
|
|
|
ret = btrfs_truncate_page(inode->i_mapping, inode->i_size);
|
|
|
if (ret)
|
|
@@ -6530,17 +6531,21 @@ static int btrfs_truncate(struct inode *inode)
|
|
|
if (!rsv)
|
|
|
return -ENOMEM;
|
|
|
|
|
|
- trans = btrfs_start_transaction(root, 4);
|
|
|
+ /*
|
|
|
+ * 2 for the truncate slack space
|
|
|
+ * 1 for the orphan item we're going to add
|
|
|
+ * 1 for the orphan item deletion
|
|
|
+ * 1 for updating the inode.
|
|
|
+ */
|
|
|
+ trans = btrfs_start_transaction(root, 5);
|
|
|
if (IS_ERR(trans)) {
|
|
|
err = PTR_ERR(trans);
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- /*
|
|
|
- * Reserve space for the truncate process. Truncate should be adding
|
|
|
- * space, but if there are snapshots it may end up using space.
|
|
|
- */
|
|
|
- ret = btrfs_truncate_reserve_metadata(trans, root, rsv);
|
|
|
+ /* Migrate the slack space for the truncate to our reserve */
|
|
|
+ ret = btrfs_block_rsv_migrate(&root->fs_info->trans_block_rsv, rsv,
|
|
|
+ min_size);
|
|
|
BUG_ON(ret);
|
|
|
|
|
|
ret = btrfs_orphan_add(trans, inode);
|
|
@@ -6549,21 +6554,6 @@ static int btrfs_truncate(struct inode *inode)
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- nr = trans->blocks_used;
|
|
|
- btrfs_end_transaction(trans, root);
|
|
|
- btrfs_btree_balance_dirty(root, nr);
|
|
|
-
|
|
|
- /*
|
|
|
- * Ok so we've already migrated our bytes over for the truncate, so here
|
|
|
- * just reserve the one slot we need for updating the inode.
|
|
|
- */
|
|
|
- trans = btrfs_start_transaction(root, 1);
|
|
|
- if (IS_ERR(trans)) {
|
|
|
- err = PTR_ERR(trans);
|
|
|
- goto out;
|
|
|
- }
|
|
|
- trans->block_rsv = rsv;
|
|
|
-
|
|
|
/*
|
|
|
* setattr is responsible for setting the ordered_data_close flag,
|
|
|
* but that is only tested during the last file release. That
|
|
@@ -6585,20 +6575,30 @@ static int btrfs_truncate(struct inode *inode)
|
|
|
btrfs_add_ordered_operation(trans, root, inode);
|
|
|
|
|
|
while (1) {
|
|
|
+ ret = btrfs_block_rsv_check(trans, root, rsv, min_size, 0);
|
|
|
+ if (ret) {
|
|
|
+ /*
|
|
|
+ * This can only happen with the original transaction we
|
|
|
+ * started above, every other time we shouldn't have a
|
|
|
+ * transaction started yet.
|
|
|
+ */
|
|
|
+ if (ret == -EAGAIN)
|
|
|
+ goto end_trans;
|
|
|
+ err = ret;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
if (!trans) {
|
|
|
- trans = btrfs_start_transaction(root, 3);
|
|
|
+ /* Just need the 1 for updating the inode */
|
|
|
+ trans = btrfs_start_transaction(root, 1);
|
|
|
if (IS_ERR(trans)) {
|
|
|
err = PTR_ERR(trans);
|
|
|
goto out;
|
|
|
}
|
|
|
-
|
|
|
- ret = btrfs_truncate_reserve_metadata(trans, root,
|
|
|
- rsv);
|
|
|
- BUG_ON(ret);
|
|
|
-
|
|
|
- trans->block_rsv = rsv;
|
|
|
}
|
|
|
|
|
|
+ trans->block_rsv = rsv;
|
|
|
+
|
|
|
ret = btrfs_truncate_inode_items(trans, root, inode,
|
|
|
inode->i_size,
|
|
|
BTRFS_EXTENT_DATA_KEY);
|
|
@@ -6613,7 +6613,7 @@ static int btrfs_truncate(struct inode *inode)
|
|
|
err = ret;
|
|
|
break;
|
|
|
}
|
|
|
-
|
|
|
+end_trans:
|
|
|
nr = trans->blocks_used;
|
|
|
btrfs_end_transaction(trans, root);
|
|
|
trans = NULL;
|