aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/inode.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/inode.c')
-rw-r--r--fs/btrfs/inode.c111
1 files changed, 84 insertions, 27 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index e47bdf0fb75a..bc12ba23db5f 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -6591,6 +6591,7 @@ out:
6591static int btrfs_truncate(struct inode *inode) 6591static int btrfs_truncate(struct inode *inode)
6592{ 6592{
6593 struct btrfs_root *root = BTRFS_I(inode)->root; 6593 struct btrfs_root *root = BTRFS_I(inode)->root;
6594 struct btrfs_block_rsv *rsv;
6594 int ret; 6595 int ret;
6595 int err = 0; 6596 int err = 0;
6596 struct btrfs_trans_handle *trans; 6597 struct btrfs_trans_handle *trans;
@@ -6604,28 +6605,83 @@ static int btrfs_truncate(struct inode *inode)
6604 btrfs_wait_ordered_range(inode, inode->i_size & (~mask), (u64)-1); 6605 btrfs_wait_ordered_range(inode, inode->i_size & (~mask), (u64)-1);
6605 btrfs_ordered_update_i_size(inode, inode->i_size, NULL); 6606 btrfs_ordered_update_i_size(inode, inode->i_size, NULL);
6606 6607
6607 trans = btrfs_start_transaction(root, 5); 6608 /*
6608 if (IS_ERR(trans)) 6609 * Yes ladies and gentelment, this is indeed ugly. The fact is we have
6609 return PTR_ERR(trans); 6610 * 3 things going on here
6611 *
6612 * 1) We need to reserve space for our orphan item and the space to
6613 * delete our orphan item. Lord knows we don't want to have a dangling
6614 * orphan item because we didn't reserve space to remove it.
6615 *
6616 * 2) We need to reserve space to update our inode.
6617 *
6618 * 3) We need to have something to cache all the space that is going to
6619 * be free'd up by the truncate operation, but also have some slack
6620 * space reserved in case it uses space during the truncate (thank you
6621 * very much snapshotting).
6622 *
6623 * And we need these to all be seperate. The fact is we can use alot of
6624 * space doing the truncate, and we have no earthly idea how much space
6625 * we will use, so we need the truncate reservation to be seperate so it
6626 * doesn't end up using space reserved for updating the inode or
6627 * removing the orphan item. We also need to be able to stop the
6628 * transaction and start a new one, which means we need to be able to
6629 * update the inode several times, and we have no idea of knowing how
6630 * many times that will be, so we can't just reserve 1 item for the
6631 * entirety of the opration, so that has to be done seperately as well.
6632 * Then there is the orphan item, which does indeed need to be held on
6633 * to for the whole operation, and we need nobody to touch this reserved
6634 * space except the orphan code.
6635 *
6636 * So that leaves us with
6637 *
6638 * 1) root->orphan_block_rsv - for the orphan deletion.
6639 * 2) rsv - for the truncate reservation, which we will steal from the
6640 * transaction reservation.
6641 * 3) fs_info->trans_block_rsv - this will have 1 items worth left for
6642 * updating the inode.
6643 */
6644 rsv = btrfs_alloc_block_rsv(root);
6645 if (!rsv)
6646 return -ENOMEM;
6647 btrfs_add_durable_block_rsv(root->fs_info, rsv);
6648
6649 trans = btrfs_start_transaction(root, 4);
6650 if (IS_ERR(trans)) {
6651 err = PTR_ERR(trans);
6652 goto out;
6653 }
6610 6654
6611 btrfs_set_trans_block_group(trans, inode); 6655 btrfs_set_trans_block_group(trans, inode);
6612 6656
6657 /*
6658 * Reserve space for the truncate process. Truncate should be adding
6659 * space, but if there are snapshots it may end up using space.
6660 */
6661 ret = btrfs_truncate_reserve_metadata(trans, root, rsv);
6662 BUG_ON(ret);
6663
6613 ret = btrfs_orphan_add(trans, inode); 6664 ret = btrfs_orphan_add(trans, inode);
6614 if (ret) { 6665 if (ret) {
6615 btrfs_end_transaction(trans, root); 6666 btrfs_end_transaction(trans, root);
6616 return ret; 6667 goto out;
6617 } 6668 }
6618 6669
6619 nr = trans->blocks_used; 6670 nr = trans->blocks_used;
6620 btrfs_end_transaction(trans, root); 6671 btrfs_end_transaction(trans, root);
6621 btrfs_btree_balance_dirty(root, nr); 6672 btrfs_btree_balance_dirty(root, nr);
6622 6673
6623 /* Now start a transaction for the truncate */ 6674 /*
6624 trans = btrfs_start_transaction(root, 0); 6675 * Ok so we've already migrated our bytes over for the truncate, so here
6625 if (IS_ERR(trans)) 6676 * just reserve the one slot we need for updating the inode.
6626 return PTR_ERR(trans); 6677 */
6678 trans = btrfs_start_transaction(root, 1);
6679 if (IS_ERR(trans)) {
6680 err = PTR_ERR(trans);
6681 goto out;
6682 }
6627 btrfs_set_trans_block_group(trans, inode); 6683 btrfs_set_trans_block_group(trans, inode);
6628 trans->block_rsv = root->orphan_block_rsv; 6684 trans->block_rsv = rsv;
6629 6685
6630 /* 6686 /*
6631 * setattr is responsible for setting the ordered_data_close flag, 6687 * setattr is responsible for setting the ordered_data_close flag,
@@ -6649,24 +6705,18 @@ static int btrfs_truncate(struct inode *inode)
6649 6705
6650 while (1) { 6706 while (1) {
6651 if (!trans) { 6707 if (!trans) {
6652 trans = btrfs_start_transaction(root, 0); 6708 trans = btrfs_start_transaction(root, 3);
6653 if (IS_ERR(trans)) 6709 if (IS_ERR(trans)) {
6654 return PTR_ERR(trans); 6710 err = PTR_ERR(trans);
6655 btrfs_set_trans_block_group(trans, inode); 6711 goto out;
6656 trans->block_rsv = root->orphan_block_rsv; 6712 }
6657 }
6658 6713
6659 ret = btrfs_block_rsv_check(trans, root, 6714 ret = btrfs_truncate_reserve_metadata(trans, root,
6660 root->orphan_block_rsv, 0, 5); 6715 rsv);
6661 if (ret == -EAGAIN) { 6716 BUG_ON(ret);
6662 ret = btrfs_commit_transaction(trans, root); 6717
6663 if (ret) 6718 btrfs_set_trans_block_group(trans, inode);
6664 return ret; 6719 trans->block_rsv = rsv;
6665 trans = NULL;
6666 continue;
6667 } else if (ret) {
6668 err = ret;
6669 break;
6670 } 6720 }
6671 6721
6672 ret = btrfs_truncate_inode_items(trans, root, inode, 6722 ret = btrfs_truncate_inode_items(trans, root, inode,
@@ -6677,6 +6727,7 @@ static int btrfs_truncate(struct inode *inode)
6677 break; 6727 break;
6678 } 6728 }
6679 6729
6730 trans->block_rsv = &root->fs_info->trans_block_rsv;
6680 ret = btrfs_update_inode(trans, root, inode); 6731 ret = btrfs_update_inode(trans, root, inode);
6681 if (ret) { 6732 if (ret) {
6682 err = ret; 6733 err = ret;
@@ -6690,6 +6741,7 @@ static int btrfs_truncate(struct inode *inode)
6690 } 6741 }
6691 6742
6692 if (ret == 0 && inode->i_nlink > 0) { 6743 if (ret == 0 && inode->i_nlink > 0) {
6744 trans->block_rsv = root->orphan_block_rsv;
6693 ret = btrfs_orphan_del(trans, inode); 6745 ret = btrfs_orphan_del(trans, inode);
6694 if (ret) 6746 if (ret)
6695 err = ret; 6747 err = ret;
@@ -6701,15 +6753,20 @@ static int btrfs_truncate(struct inode *inode)
6701 ret = btrfs_orphan_del(NULL, inode); 6753 ret = btrfs_orphan_del(NULL, inode);
6702 } 6754 }
6703 6755
6756 trans->block_rsv = &root->fs_info->trans_block_rsv;
6704 ret = btrfs_update_inode(trans, root, inode); 6757 ret = btrfs_update_inode(trans, root, inode);
6705 if (ret && !err) 6758 if (ret && !err)
6706 err = ret; 6759 err = ret;
6707 6760
6708 nr = trans->blocks_used; 6761 nr = trans->blocks_used;
6709 ret = btrfs_end_transaction_throttle(trans, root); 6762 ret = btrfs_end_transaction_throttle(trans, root);
6763 btrfs_btree_balance_dirty(root, nr);
6764
6765out:
6766 btrfs_free_block_rsv(root, rsv);
6767
6710 if (ret && !err) 6768 if (ret && !err)
6711 err = ret; 6769 err = ret;
6712 btrfs_btree_balance_dirty(root, nr);
6713 6770
6714 return err; 6771 return err;
6715} 6772}