* Takes the number of bytes to be csumm'ed and figures out how many leaves it
  * would require to store the csums for that many bytes.
  */
-static u64 csum_bytes_to_leaves(struct btrfs_root *root, u64 csum_bytes)
+u64 btrfs_csum_bytes_to_leaves(struct btrfs_root *root, u64 csum_bytes)
 {
        u64 csum_size;
        u64 num_csums_per_leaf;
        if (num_heads > 1)
                num_bytes += (num_heads - 1) * root->nodesize;
        num_bytes <<= 1;
-       num_bytes += csum_bytes_to_leaves(root, csum_bytes) * root->nodesize;
+       num_bytes += btrfs_csum_bytes_to_leaves(root, csum_bytes) * root->nodesize;
        global_rsv = &root->fs_info->global_block_rsv;
 
        /*
            BTRFS_I(inode)->csum_bytes == 0)
                return 0;
 
-       old_csums = csum_bytes_to_leaves(root, BTRFS_I(inode)->csum_bytes);
-
+       old_csums = btrfs_csum_bytes_to_leaves(root, BTRFS_I(inode)->csum_bytes);
        if (reserve)
                BTRFS_I(inode)->csum_bytes += num_bytes;
        else
                BTRFS_I(inode)->csum_bytes -= num_bytes;
-       num_csums = csum_bytes_to_leaves(root, BTRFS_I(inode)->csum_bytes);
+       num_csums = btrfs_csum_bytes_to_leaves(root, BTRFS_I(inode)->csum_bytes);
 
        /* No change, no need to reserve more */
        if (old_csums == num_csums)
 
        return err;
 }
 
+static int truncate_space_check(struct btrfs_trans_handle *trans,
+                               struct btrfs_root *root,
+                               u64 bytes_deleted)
+{
+       int ret;
+
+       bytes_deleted = btrfs_csum_bytes_to_leaves(root, bytes_deleted);
+       ret = btrfs_block_rsv_add(root, &root->fs_info->trans_block_rsv,
+                                 bytes_deleted, BTRFS_RESERVE_NO_FLUSH);
+       if (!ret)
+               trans->bytes_reserved += bytes_deleted;
+       return ret;
+
+}
+
 /*
  * this can truncate away extent items, csum items and directory items.
  * It starts at a high offset and removes keys until it can't find
        u64 bytes_deleted = 0;
        bool be_nice = 0;
        bool should_throttle = 0;
+       bool should_end = 0;
 
        BUG_ON(new_size > 0 && min_type != BTRFS_EXTENT_DATA_KEY);
 
                } else {
                        break;
                }
+               should_throttle = 0;
+
                if (found_extent &&
                    (test_bit(BTRFS_ROOT_REF_COWS, &root->state) ||
                     root == root->fs_info->tree_root)) {
                        if (btrfs_should_throttle_delayed_refs(trans, root))
                                btrfs_async_run_delayed_refs(root,
                                        trans->delayed_ref_updates * 2, 0);
+                       if (be_nice) {
+                               if (truncate_space_check(trans, root,
+                                                        extent_num_bytes)) {
+                                       should_end = 1;
+                               }
+                               if (btrfs_should_throttle_delayed_refs(trans,
+                                                                      root)) {
+                                       should_throttle = 1;
+                               }
+                       }
                }
 
                if (found_type == BTRFS_INODE_ITEM_KEY)
                        break;
 
-               should_throttle =
-                       btrfs_should_throttle_delayed_refs(trans, root);
-
                if (path->slots[0] == 0 ||
                    path->slots[0] != pending_del_slot ||
-                   (be_nice && should_throttle)) {
+                   should_throttle || should_end) {
                        if (pending_del_nr) {
                                ret = btrfs_del_items(trans, root, path,
                                                pending_del_slot,
                                pending_del_nr = 0;
                        }
                        btrfs_release_path(path);
-                       if (be_nice && should_throttle) {
+                       if (should_throttle) {
                                unsigned long updates = trans->delayed_ref_updates;
                                if (updates) {
                                        trans->delayed_ref_updates = 0;
                                                err = ret;
                                }
                        }
+                       /*
+                        * if we failed to refill our space rsv, bail out
+                        * and let the transaction restart
+                        */
+                       if (should_end) {
+                               err = -EAGAIN;
+                               goto error;
+                       }
                        goto search_again;
                } else {
                        path->slots[0]--;
 
        btrfs_free_path(path);
 
-       if (be_nice && btrfs_should_throttle_delayed_refs(trans, root)) {
+       if (be_nice && bytes_deleted > 32 * 1024 * 1024) {
                unsigned long updates = trans->delayed_ref_updates;
                if (updates) {
                        trans->delayed_ref_updates = 0;