btrfs: run delayed items before dropping the snapshot
[sfrench/cifs-2.6.git] / fs / btrfs / extent-tree.c
index b32ccdbcc0bc9e812d21110c6710ddedfb4f8302..8a9ce33dfdbc4046d8717d7934ce69a1db7b12fc 100644 (file)
@@ -2424,25 +2424,82 @@ static void unselect_delayed_ref_head(struct btrfs_delayed_ref_root *delayed_ref
        btrfs_delayed_ref_unlock(head);
 }
 
-static int cleanup_extent_op(struct btrfs_trans_handle *trans,
-                            struct btrfs_delayed_ref_head *head)
+static struct btrfs_delayed_extent_op *cleanup_extent_op(
+                               struct btrfs_delayed_ref_head *head)
 {
        struct btrfs_delayed_extent_op *extent_op = head->extent_op;
-       int ret;
 
        if (!extent_op)
-               return 0;
-       head->extent_op = NULL;
+               return NULL;
+
        if (head->must_insert_reserved) {
+               head->extent_op = NULL;
                btrfs_free_delayed_extent_op(extent_op);
-               return 0;
+               return NULL;
        }
+       return extent_op;
+}
+
+static int run_and_cleanup_extent_op(struct btrfs_trans_handle *trans,
+                                    struct btrfs_delayed_ref_head *head)
+{
+       struct btrfs_delayed_extent_op *extent_op;
+       int ret;
+
+       extent_op = cleanup_extent_op(head);
+       if (!extent_op)
+               return 0;
+       head->extent_op = NULL;
        spin_unlock(&head->lock);
        ret = run_delayed_extent_op(trans, head, extent_op);
        btrfs_free_delayed_extent_op(extent_op);
        return ret ? ret : 1;
 }
 
+static void cleanup_ref_head_accounting(struct btrfs_trans_handle *trans,
+                                       struct btrfs_delayed_ref_head *head)
+{
+       struct btrfs_fs_info *fs_info = trans->fs_info;
+       struct btrfs_delayed_ref_root *delayed_refs =
+               &trans->transaction->delayed_refs;
+       int nr_items = 1;       /* Dropping this ref head update. */
+
+       if (head->total_ref_mod < 0) {
+               struct btrfs_space_info *space_info;
+               u64 flags;
+
+               if (head->is_data)
+                       flags = BTRFS_BLOCK_GROUP_DATA;
+               else if (head->is_system)
+                       flags = BTRFS_BLOCK_GROUP_SYSTEM;
+               else
+                       flags = BTRFS_BLOCK_GROUP_METADATA;
+               space_info = __find_space_info(fs_info, flags);
+               ASSERT(space_info);
+               percpu_counter_add_batch(&space_info->total_bytes_pinned,
+                                  -head->num_bytes,
+                                  BTRFS_TOTAL_BYTES_PINNED_BATCH);
+
+               /*
+                * We had csum deletions accounted for in our delayed refs rsv,
+                * we need to drop the csum leaves for this update from our
+                * delayed_refs_rsv.
+                */
+               if (head->is_data) {
+                       spin_lock(&delayed_refs->lock);
+                       delayed_refs->pending_csums -= head->num_bytes;
+                       spin_unlock(&delayed_refs->lock);
+                       nr_items += btrfs_csum_bytes_to_leaves(fs_info,
+                               head->num_bytes);
+               }
+       }
+
+       /* Also free its reserved qgroup space */
+       btrfs_qgroup_free_delayed_ref(fs_info, head->qgroup_ref_root,
+                                     head->qgroup_reserved);
+       btrfs_delayed_refs_rsv_release(fs_info, nr_items);
+}
+
 static int cleanup_ref_head(struct btrfs_trans_handle *trans,
                            struct btrfs_delayed_ref_head *head)
 {
@@ -2453,7 +2510,7 @@ static int cleanup_ref_head(struct btrfs_trans_handle *trans,
 
        delayed_refs = &trans->transaction->delayed_refs;
 
-       ret = cleanup_extent_op(trans, head);
+       ret = run_and_cleanup_extent_op(trans, head);
        if (ret < 0) {
                unselect_delayed_ref_head(delayed_refs, head);
                btrfs_debug(fs_info, "run_delayed_extent_op returned %d", ret);
@@ -2474,37 +2531,9 @@ static int cleanup_ref_head(struct btrfs_trans_handle *trans,
                spin_unlock(&delayed_refs->lock);
                return 1;
        }
-       delayed_refs->num_heads--;
-       rb_erase_cached(&head->href_node, &delayed_refs->href_root);
-       RB_CLEAR_NODE(&head->href_node);
+       btrfs_delete_ref_head(delayed_refs, head);
        spin_unlock(&head->lock);
        spin_unlock(&delayed_refs->lock);
-       atomic_dec(&delayed_refs->num_entries);
-
-       trace_run_delayed_ref_head(fs_info, head, 0);
-
-       if (head->total_ref_mod < 0) {
-               struct btrfs_space_info *space_info;
-               u64 flags;
-
-               if (head->is_data)
-                       flags = BTRFS_BLOCK_GROUP_DATA;
-               else if (head->is_system)
-                       flags = BTRFS_BLOCK_GROUP_SYSTEM;
-               else
-                       flags = BTRFS_BLOCK_GROUP_METADATA;
-               space_info = __find_space_info(fs_info, flags);
-               ASSERT(space_info);
-               percpu_counter_add_batch(&space_info->total_bytes_pinned,
-                                  -head->num_bytes,
-                                  BTRFS_TOTAL_BYTES_PINNED_BATCH);
-
-               if (head->is_data) {
-                       spin_lock(&delayed_refs->lock);
-                       delayed_refs->pending_csums -= head->num_bytes;
-                       spin_unlock(&delayed_refs->lock);
-               }
-       }
 
        if (head->must_insert_reserved) {
                btrfs_pin_extent(fs_info, head->bytenr,
@@ -2515,9 +2544,9 @@ static int cleanup_ref_head(struct btrfs_trans_handle *trans,
                }
        }
 
-       /* Also free its reserved qgroup space */
-       btrfs_qgroup_free_delayed_ref(fs_info, head->qgroup_ref_root,
-                                     head->qgroup_reserved);
+       cleanup_ref_head_accounting(trans, head);
+
+       trace_run_delayed_ref_head(fs_info, head, 0);
        btrfs_delayed_ref_unlock(head);
        btrfs_put_delayed_ref_head(head);
        return 0;
@@ -2810,40 +2839,28 @@ u64 btrfs_csum_bytes_to_leaves(struct btrfs_fs_info *fs_info, u64 csum_bytes)
        return num_csums;
 }
 
-int btrfs_check_space_for_delayed_refs(struct btrfs_trans_handle *trans)
+bool btrfs_check_space_for_delayed_refs(struct btrfs_fs_info *fs_info)
 {
-       struct btrfs_fs_info *fs_info = trans->fs_info;
-       struct btrfs_block_rsv *global_rsv;
-       u64 num_heads = trans->transaction->delayed_refs.num_heads_ready;
-       u64 csum_bytes = trans->transaction->delayed_refs.pending_csums;
-       unsigned int num_dirty_bgs = trans->transaction->num_dirty_bgs;
-       u64 num_bytes, num_dirty_bgs_bytes;
-       int ret = 0;
+       struct btrfs_block_rsv *delayed_refs_rsv = &fs_info->delayed_refs_rsv;
+       struct btrfs_block_rsv *global_rsv = &fs_info->global_block_rsv;
+       bool ret = false;
+       u64 reserved;
 
-       num_bytes = btrfs_calc_trans_metadata_size(fs_info, 1);
-       num_heads = heads_to_leaves(fs_info, num_heads);
-       if (num_heads > 1)
-               num_bytes += (num_heads - 1) * fs_info->nodesize;
-       num_bytes <<= 1;
-       num_bytes += btrfs_csum_bytes_to_leaves(fs_info, csum_bytes) *
-                                                       fs_info->nodesize;
-       num_dirty_bgs_bytes = btrfs_calc_trans_metadata_size(fs_info,
-                                                            num_dirty_bgs);
-       global_rsv = &fs_info->global_block_rsv;
+       spin_lock(&global_rsv->lock);
+       reserved = global_rsv->reserved;
+       spin_unlock(&global_rsv->lock);
 
        /*
-        * If we can't allocate any more chunks lets make sure we have _lots_ of
-        * wiggle room since running delayed refs can create more delayed refs.
+        * Since the global reserve is just kind of magic we don't really want
+        * to rely on it to save our bacon, so if our size is more than the
+        * delayed_refs_rsv and the global rsv then it's time to think about
+        * bailing.
         */
-       if (global_rsv->space_info->full) {
-               num_dirty_bgs_bytes <<= 1;
-               num_bytes <<= 1;
-       }
-
-       spin_lock(&global_rsv->lock);
-       if (global_rsv->reserved <= num_bytes + num_dirty_bgs_bytes)
-               ret = 1;
-       spin_unlock(&global_rsv->lock);
+       spin_lock(&delayed_refs_rsv->lock);
+       reserved += delayed_refs_rsv->reserved;
+       if (delayed_refs_rsv->size >= reserved)
+               ret = true;
+       spin_unlock(&delayed_refs_rsv->lock);
        return ret;
 }
 
@@ -2862,7 +2879,7 @@ int btrfs_should_throttle_delayed_refs(struct btrfs_trans_handle *trans)
        if (val >= NSEC_PER_SEC / 2)
                return 2;
 
-       return btrfs_check_space_for_delayed_refs(trans);
+       return btrfs_check_space_for_delayed_refs(trans->fs_info);
 }
 
 struct async_delayed_refs {
@@ -3606,6 +3623,8 @@ again:
         */
        mutex_lock(&trans->transaction->cache_write_mutex);
        while (!list_empty(&dirty)) {
+               bool drop_reserve = true;
+
                cache = list_first_entry(&dirty,
                                         struct btrfs_block_group_cache,
                                         dirty_list);
@@ -3678,6 +3697,7 @@ again:
                                        list_add_tail(&cache->dirty_list,
                                                      &cur_trans->dirty_bgs);
                                        btrfs_get_block_group(cache);
+                                       drop_reserve = false;
                                }
                                spin_unlock(&cur_trans->dirty_bgs_lock);
                        } else if (ret) {
@@ -3688,6 +3708,8 @@ again:
                /* if its not on the io list, we need to put the block group */
                if (should_put)
                        btrfs_put_block_group(cache);
+               if (drop_reserve)
+                       btrfs_delayed_refs_rsv_release(fs_info, 1);
 
                if (ret)
                        break;
@@ -3836,6 +3858,7 @@ int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans,
                /* if its not on the io list, we need to put the block group */
                if (should_put)
                        btrfs_put_block_group(cache);
+               btrfs_delayed_refs_rsv_release(fs_info, 1);
                spin_lock(&cur_trans->dirty_bgs_lock);
        }
        spin_unlock(&cur_trans->dirty_bgs_lock);
@@ -4808,8 +4831,10 @@ static int may_commit_transaction(struct btrfs_fs_info *fs_info,
 {
        struct reserve_ticket *ticket = NULL;
        struct btrfs_block_rsv *delayed_rsv = &fs_info->delayed_block_rsv;
+       struct btrfs_block_rsv *delayed_refs_rsv = &fs_info->delayed_refs_rsv;
        struct btrfs_trans_handle *trans;
-       u64 bytes;
+       u64 bytes_needed;
+       u64 reclaim_bytes = 0;
 
        trans = (struct btrfs_trans_handle *)current->journal_info;
        if (trans)
@@ -4822,15 +4847,15 @@ static int may_commit_transaction(struct btrfs_fs_info *fs_info,
        else if (!list_empty(&space_info->tickets))
                ticket = list_first_entry(&space_info->tickets,
                                          struct reserve_ticket, list);
-       bytes = (ticket) ? ticket->bytes : 0;
+       bytes_needed = (ticket) ? ticket->bytes : 0;
        spin_unlock(&space_info->lock);
 
-       if (!bytes)
+       if (!bytes_needed)
                return 0;
 
        /* See if there is enough pinned space to make this reservation */
        if (__percpu_counter_compare(&space_info->total_bytes_pinned,
-                                  bytes,
+                                  bytes_needed,
                                   BTRFS_TOTAL_BYTES_PINNED_BATCH) >= 0)
                goto commit;
 
@@ -4842,14 +4867,18 @@ static int may_commit_transaction(struct btrfs_fs_info *fs_info,
                return -ENOSPC;
 
        spin_lock(&delayed_rsv->lock);
-       if (delayed_rsv->size > bytes)
-               bytes = 0;
-       else
-               bytes -= delayed_rsv->size;
+       reclaim_bytes += delayed_rsv->reserved;
        spin_unlock(&delayed_rsv->lock);
 
+       spin_lock(&delayed_refs_rsv->lock);
+       reclaim_bytes += delayed_refs_rsv->reserved;
+       spin_unlock(&delayed_refs_rsv->lock);
+       if (reclaim_bytes >= bytes_needed)
+               goto commit;
+       bytes_needed -= reclaim_bytes;
+
        if (__percpu_counter_compare(&space_info->total_bytes_pinned,
-                                  bytes,
+                                  bytes_needed,
                                   BTRFS_TOTAL_BYTES_PINNED_BATCH) < 0) {
                return -ENOSPC;
        }
@@ -4897,6 +4926,20 @@ static void flush_space(struct btrfs_fs_info *fs_info,
                shrink_delalloc(fs_info, num_bytes * 2, num_bytes,
                                state == FLUSH_DELALLOC_WAIT);
                break;
+       case FLUSH_DELAYED_REFS_NR:
+       case FLUSH_DELAYED_REFS:
+               trans = btrfs_join_transaction(root);
+               if (IS_ERR(trans)) {
+                       ret = PTR_ERR(trans);
+                       break;
+               }
+               if (state == FLUSH_DELAYED_REFS_NR)
+                       nr = calc_reclaim_items_nr(fs_info, num_bytes);
+               else
+                       nr = 0;
+               btrfs_run_delayed_refs(trans, nr);
+               btrfs_end_transaction(trans);
+               break;
        case ALLOC_CHUNK:
                trans = btrfs_join_transaction(root);
                if (IS_ERR(trans)) {
@@ -5369,6 +5412,90 @@ int btrfs_cond_migrate_bytes(struct btrfs_fs_info *fs_info,
        return 0;
 }
 
+/**
+ * btrfs_migrate_to_delayed_refs_rsv - transfer bytes to our delayed refs rsv.
+ * @fs_info - the fs info for our fs.
+ * @src - the source block rsv to transfer from.
+ * @num_bytes - the number of bytes to transfer.
+ *
+ * This transfers up to the num_bytes amount from the src rsv to the
+ * delayed_refs_rsv.  Any extra bytes are returned to the space info.
+ */
+void btrfs_migrate_to_delayed_refs_rsv(struct btrfs_fs_info *fs_info,
+                                      struct btrfs_block_rsv *src,
+                                      u64 num_bytes)
+{
+       struct btrfs_block_rsv *delayed_refs_rsv = &fs_info->delayed_refs_rsv;
+       u64 to_free = 0;
+
+       spin_lock(&src->lock);
+       src->reserved -= num_bytes;
+       src->size -= num_bytes;
+       spin_unlock(&src->lock);
+
+       spin_lock(&delayed_refs_rsv->lock);
+       if (delayed_refs_rsv->size > delayed_refs_rsv->reserved) {
+               u64 delta = delayed_refs_rsv->size -
+                       delayed_refs_rsv->reserved;
+               if (num_bytes > delta) {
+                       to_free = num_bytes - delta;
+                       num_bytes = delta;
+               }
+       } else {
+               to_free = num_bytes;
+               num_bytes = 0;
+       }
+
+       if (num_bytes)
+               delayed_refs_rsv->reserved += num_bytes;
+       if (delayed_refs_rsv->reserved >= delayed_refs_rsv->size)
+               delayed_refs_rsv->full = 1;
+       spin_unlock(&delayed_refs_rsv->lock);
+
+       if (num_bytes)
+               trace_btrfs_space_reservation(fs_info, "delayed_refs_rsv",
+                                             0, num_bytes, 1);
+       if (to_free)
+               space_info_add_old_bytes(fs_info, delayed_refs_rsv->space_info,
+                                        to_free);
+}
+
+/**
+ * btrfs_delayed_refs_rsv_refill - refill based on our delayed refs usage.
+ * @fs_info - the fs_info for our fs.
+ * @flush - control how we can flush for this reservation.
+ *
+ * This will refill the delayed block_rsv up to 1 items size worth of space and
+ * will return -ENOSPC if we can't make the reservation.
+ */
+int btrfs_delayed_refs_rsv_refill(struct btrfs_fs_info *fs_info,
+                                 enum btrfs_reserve_flush_enum flush)
+{
+       struct btrfs_block_rsv *block_rsv = &fs_info->delayed_refs_rsv;
+       u64 limit = btrfs_calc_trans_metadata_size(fs_info, 1);
+       u64 num_bytes = 0;
+       int ret = -ENOSPC;
+
+       spin_lock(&block_rsv->lock);
+       if (block_rsv->reserved < block_rsv->size) {
+               num_bytes = block_rsv->size - block_rsv->reserved;
+               num_bytes = min(num_bytes, limit);
+       }
+       spin_unlock(&block_rsv->lock);
+
+       if (!num_bytes)
+               return 0;
+
+       ret = reserve_metadata_bytes(fs_info->extent_root, block_rsv,
+                                    num_bytes, flush);
+       if (ret)
+               return ret;
+       block_rsv_add_bytes(block_rsv, num_bytes, 0);
+       trace_btrfs_space_reservation(fs_info, "delayed_refs_rsv",
+                                     0, num_bytes, 1);
+       return 0;
+}
+
 /*
  * This is for space we already have accounted in space_info->bytes_may_use, so
  * basically when we're returning space from block_rsv's.
@@ -5689,6 +5816,31 @@ static int btrfs_inode_rsv_refill(struct btrfs_inode *inode,
        return ret;
 }
 
+static u64 __btrfs_block_rsv_release(struct btrfs_fs_info *fs_info,
+                                    struct btrfs_block_rsv *block_rsv,
+                                    u64 num_bytes, u64 *qgroup_to_release)
+{
+       struct btrfs_block_rsv *global_rsv = &fs_info->global_block_rsv;
+       struct btrfs_block_rsv *delayed_rsv = &fs_info->delayed_refs_rsv;
+       struct btrfs_block_rsv *target = delayed_rsv;
+
+       if (target->full || target == block_rsv)
+               target = global_rsv;
+
+       if (block_rsv->space_info != target->space_info)
+               target = NULL;
+
+       return block_rsv_release_bytes(fs_info, block_rsv, target, num_bytes,
+                                      qgroup_to_release);
+}
+
+void btrfs_block_rsv_release(struct btrfs_fs_info *fs_info,
+                            struct btrfs_block_rsv *block_rsv,
+                            u64 num_bytes)
+{
+       __btrfs_block_rsv_release(fs_info, block_rsv, num_bytes, NULL);
+}
+
 /**
  * btrfs_inode_rsv_release - release any excessive reservation.
  * @inode - the inode we need to release from.
@@ -5703,7 +5855,6 @@ static int btrfs_inode_rsv_refill(struct btrfs_inode *inode,
 static void btrfs_inode_rsv_release(struct btrfs_inode *inode, bool qgroup_free)
 {
        struct btrfs_fs_info *fs_info = inode->root->fs_info;
-       struct btrfs_block_rsv *global_rsv = &fs_info->global_block_rsv;
        struct btrfs_block_rsv *block_rsv = &inode->block_rsv;
        u64 released = 0;
        u64 qgroup_to_release = 0;
@@ -5713,8 +5864,8 @@ static void btrfs_inode_rsv_release(struct btrfs_inode *inode, bool qgroup_free)
         * are releasing 0 bytes, and then we'll just get the reservation over
         * the size free'd.
         */
-       released = block_rsv_release_bytes(fs_info, block_rsv, global_rsv, 0,
-                                          &qgroup_to_release);
+       released = __btrfs_block_rsv_release(fs_info, block_rsv, 0,
+                                            &qgroup_to_release);
        if (released > 0)
                trace_btrfs_space_reservation(fs_info, "delalloc",
                                              btrfs_ino(inode), released, 0);
@@ -5725,16 +5876,26 @@ static void btrfs_inode_rsv_release(struct btrfs_inode *inode, bool qgroup_free)
                                                   qgroup_to_release);
 }
 
-void btrfs_block_rsv_release(struct btrfs_fs_info *fs_info,
-                            struct btrfs_block_rsv *block_rsv,
-                            u64 num_bytes)
+/**
+ * btrfs_delayed_refs_rsv_release - release a ref head's reservation.
+ * @fs_info - the fs_info for our fs.
+ * @nr - the number of items to drop.
+ *
+ * This drops the delayed ref head's count from the delayed refs rsv and frees
+ * any excess reservation we had.
+ */
+void btrfs_delayed_refs_rsv_release(struct btrfs_fs_info *fs_info, int nr)
 {
+       struct btrfs_block_rsv *block_rsv = &fs_info->delayed_refs_rsv;
        struct btrfs_block_rsv *global_rsv = &fs_info->global_block_rsv;
+       u64 num_bytes = btrfs_calc_trans_metadata_size(fs_info, nr);
+       u64 released = 0;
 
-       if (global_rsv == block_rsv ||
-           block_rsv->space_info != global_rsv->space_info)
-               global_rsv = NULL;
-       block_rsv_release_bytes(fs_info, block_rsv, global_rsv, num_bytes, NULL);
+       released = block_rsv_release_bytes(fs_info, block_rsv, global_rsv,
+                                          num_bytes, NULL);
+       if (released)
+               trace_btrfs_space_reservation(fs_info, "delayed_refs_rsv",
+                                             0, released, 0);
 }
 
 static void update_global_block_rsv(struct btrfs_fs_info *fs_info)
@@ -5799,9 +5960,10 @@ static void init_global_block_rsv(struct btrfs_fs_info *fs_info)
        fs_info->trans_block_rsv.space_info = space_info;
        fs_info->empty_block_rsv.space_info = space_info;
        fs_info->delayed_block_rsv.space_info = space_info;
+       fs_info->delayed_refs_rsv.space_info = space_info;
 
-       fs_info->extent_root->block_rsv = &fs_info->global_block_rsv;
-       fs_info->csum_root->block_rsv = &fs_info->global_block_rsv;
+       fs_info->extent_root->block_rsv = &fs_info->delayed_refs_rsv;
+       fs_info->csum_root->block_rsv = &fs_info->delayed_refs_rsv;
        fs_info->dev_root->block_rsv = &fs_info->global_block_rsv;
        fs_info->tree_root->block_rsv = &fs_info->global_block_rsv;
        if (fs_info->quota_root)
@@ -5821,8 +5983,34 @@ static void release_global_block_rsv(struct btrfs_fs_info *fs_info)
        WARN_ON(fs_info->chunk_block_rsv.reserved > 0);
        WARN_ON(fs_info->delayed_block_rsv.size > 0);
        WARN_ON(fs_info->delayed_block_rsv.reserved > 0);
+       WARN_ON(fs_info->delayed_refs_rsv.reserved > 0);
+       WARN_ON(fs_info->delayed_refs_rsv.size > 0);
 }
 
+/*
+ * btrfs_update_delayed_refs_rsv - adjust the size of the delayed refs rsv
+ * @trans - the trans that may have generated delayed refs
+ *
+ * This is to be called anytime we may have adjusted trans->delayed_ref_updates,
+ * it'll calculate the additional size and add it to the delayed_refs_rsv.
+ */
+void btrfs_update_delayed_refs_rsv(struct btrfs_trans_handle *trans)
+{
+       struct btrfs_fs_info *fs_info = trans->fs_info;
+       struct btrfs_block_rsv *delayed_rsv = &fs_info->delayed_refs_rsv;
+       u64 num_bytes;
+
+       if (!trans->delayed_ref_updates)
+               return;
+
+       num_bytes = btrfs_calc_trans_metadata_size(fs_info,
+                                                  trans->delayed_ref_updates);
+       spin_lock(&delayed_rsv->lock);
+       delayed_rsv->size += num_bytes;
+       delayed_rsv->full = 0;
+       spin_unlock(&delayed_rsv->lock);
+       trans->delayed_ref_updates = 0;
+}
 
 /*
  * To be called after all the new block groups attached to the transaction
@@ -6115,6 +6303,7 @@ static int update_block_group(struct btrfs_trans_handle *trans,
        u64 old_val;
        u64 byte_in_group;
        int factor;
+       int ret = 0;
 
        /* block accounting for super block */
        spin_lock(&info->delalloc_root_lock);
@@ -6128,8 +6317,10 @@ static int update_block_group(struct btrfs_trans_handle *trans,
 
        while (total) {
                cache = btrfs_lookup_block_group(info, bytenr);
-               if (!cache)
-                       return -ENOENT;
+               if (!cache) {
+                       ret = -ENOENT;
+                       break;
+               }
                factor = btrfs_bg_type_to_factor(cache->flags);
 
                /*
@@ -6188,6 +6379,7 @@ static int update_block_group(struct btrfs_trans_handle *trans,
                        list_add_tail(&cache->dirty_list,
                                      &trans->transaction->dirty_bgs);
                        trans->transaction->num_dirty_bgs++;
+                       trans->delayed_ref_updates++;
                        btrfs_get_block_group(cache);
                }
                spin_unlock(&trans->transaction->dirty_bgs_lock);
@@ -6205,7 +6397,10 @@ static int update_block_group(struct btrfs_trans_handle *trans,
                total -= num_bytes;
                bytenr += num_bytes;
        }
-       return 0;
+
+       /* Modified block groups are accounted for in the delayed_refs_rsv. */
+       btrfs_update_delayed_refs_rsv(trans);
+       return ret;
 }
 
 static u64 first_logical_byte(struct btrfs_fs_info *fs_info, u64 search_start)
@@ -6973,12 +7168,8 @@ static noinline int check_ref_cleanup(struct btrfs_trans_handle *trans,
        if (!RB_EMPTY_ROOT(&head->ref_tree.rb_root))
                goto out;
 
-       if (head->extent_op) {
-               if (!head->must_insert_reserved)
-                       goto out;
-               btrfs_free_delayed_extent_op(head->extent_op);
-               head->extent_op = NULL;
-       }
+       if (cleanup_extent_op(head) != NULL)
+               goto out;
 
        /*
         * waiting for the lock here would deadlock.  If someone else has it
@@ -6987,22 +7178,9 @@ static noinline int check_ref_cleanup(struct btrfs_trans_handle *trans,
        if (!mutex_trylock(&head->mutex))
                goto out;
 
-       /*
-        * at this point we have a head with no other entries.  Go
-        * ahead and process it.
-        */
-       rb_erase_cached(&head->href_node, &delayed_refs->href_root);
-       RB_CLEAR_NODE(&head->href_node);
-       atomic_dec(&delayed_refs->num_entries);
-
-       /*
-        * we don't take a ref on the node because we're removing it from the
-        * tree, so we just steal the ref the tree was holding.
-        */
-       delayed_refs->num_heads--;
-       if (head->processing == 0)
-               delayed_refs->num_heads_ready--;
+       btrfs_delete_ref_head(delayed_refs, head);
        head->processing = 0;
+
        spin_unlock(&head->lock);
        spin_unlock(&delayed_refs->lock);
 
@@ -7010,6 +7188,7 @@ static noinline int check_ref_cleanup(struct btrfs_trans_handle *trans,
        if (head->must_insert_reserved)
                ret = 1;
 
+       cleanup_ref_head_accounting(trans, head);
        mutex_unlock(&head->mutex);
        btrfs_put_delayed_ref_head(head);
        return ret;
@@ -8367,7 +8546,12 @@ again:
                goto again;
        }
 
-       if (btrfs_test_opt(fs_info, ENOSPC_DEBUG)) {
+       /*
+        * The global reserve still exists to save us from ourselves, so don't
+        * warn_on if we are short on our delayed refs reserve.
+        */
+       if (block_rsv->type != BTRFS_BLOCK_RSV_DELREFS &&
+           btrfs_test_opt(fs_info, ENOSPC_DEBUG)) {
                static DEFINE_RATELIMIT_STATE(_rs,
                                DEFAULT_RATELIMIT_INTERVAL * 10,
                                /*DEFAULT_RATELIMIT_BURST*/ 1);
@@ -8690,7 +8874,6 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans,
        u64 bytenr;
        u64 generation;
        u64 parent;
-       u32 blocksize;
        struct btrfs_key key;
        struct btrfs_key first_key;
        struct extent_buffer *next;
@@ -8715,7 +8898,6 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans,
        bytenr = btrfs_node_blockptr(path->nodes[level], path->slots[level]);
        btrfs_node_key_to_cpu(path->nodes[level], &first_key,
                              path->slots[level]);
-       blocksize = fs_info->nodesize;
 
        next = find_extent_buffer(fs_info, bytenr);
        if (!next) {
@@ -8839,7 +9021,7 @@ skip:
                                             ret);
                        }
                }
-               ret = btrfs_free_extent(trans, root, bytenr, blocksize,
+               ret = btrfs_free_extent(trans, root, bytenr, fs_info->nodesize,
                                        parent, root->root_key.objectid,
                                        level - 1, 0);
                if (ret)
@@ -9090,9 +9272,22 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
                goto out_free;
        }
 
+       err = btrfs_run_delayed_items(trans);
+       if (err)
+               goto out_end_trans;
+
        if (block_rsv)
                trans->block_rsv = block_rsv;
 
+       /*
+        * This will help us catch people modifying the fs tree while we're
+        * dropping it.  It is unsafe to mess with the fs tree while it's being
+        * dropped as we unlock the root node and parent nodes as we walk down
+        * the tree, assuming nothing will change.  If something does change
+        * then we'll have stale information and drop references to blocks we've
+        * already dropped.
+        */
+       set_bit(BTRFS_ROOT_DELETING, &root->state);
        if (btrfs_disk_key_objectid(&root_item->drop_progress) == 0) {
                level = btrfs_header_level(root->node);
                path->nodes[level] = btrfs_lock_root_node(root);
@@ -10300,6 +10495,7 @@ void btrfs_create_pending_block_groups(struct btrfs_trans_handle *trans)
                add_block_group_free_space(trans, block_group);
                /* already aborted the transaction if it failed. */
 next:
+               btrfs_delayed_refs_rsv_release(fs_info, 1);
                list_del_init(&block_group->bg_list);
        }
        btrfs_trans_release_chunk_metadata(trans);
@@ -10377,6 +10573,8 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans, u64 bytes_used,
        link_block_group(cache);
 
        list_add_tail(&cache->bg_list, &trans->new_bgs);
+       trans->delayed_ref_updates++;
+       btrfs_update_delayed_refs_rsv(trans);
 
        set_avail_alloc_bits(fs_info, type);
        return 0;
@@ -10414,6 +10612,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
        int factor;
        struct btrfs_caching_control *caching_ctl = NULL;
        bool remove_em;
+       bool remove_rsv = false;
 
        block_group = btrfs_lookup_block_group(fs_info, group_start);
        BUG_ON(!block_group);
@@ -10478,6 +10677,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
 
        if (!list_empty(&block_group->dirty_list)) {
                list_del_init(&block_group->dirty_list);
+               remove_rsv = true;
                btrfs_put_block_group(block_group);
        }
        spin_unlock(&trans->transaction->dirty_bgs_lock);
@@ -10687,6 +10887,8 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
 
        ret = btrfs_del_item(trans, root, path);
 out:
+       if (remove_rsv)
+               btrfs_delayed_refs_rsv_release(fs_info, 1);
        btrfs_free_path(path);
        return ret;
 }