btrfs: Fix lock release order
[sfrench/cifs-2.6.git] / fs / btrfs / extent-tree.c
index e2f16b68fcbf4d2a941a9e988b9505820edd280e..cd2f5220577fbb466c3926dd12222e899c94c5f4 100644 (file)
@@ -744,12 +744,12 @@ static struct btrfs_space_info *__find_space_info(struct btrfs_fs_info *info,
 }
 
 static void add_pinned_bytes(struct btrfs_fs_info *fs_info, s64 num_bytes,
-                            u64 owner, u64 root_objectid)
+                            bool metadata, u64 root_objectid)
 {
        struct btrfs_space_info *space_info;
        u64 flags;
 
-       if (owner < BTRFS_FIRST_FREE_OBJECTID) {
+       if (metadata) {
                if (root_objectid == BTRFS_CHUNK_TREE_OBJECTID)
                        flags = BTRFS_BLOCK_GROUP_SYSTEM;
                else
@@ -2200,8 +2200,11 @@ int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
                                                 &old_ref_mod, &new_ref_mod);
        }
 
-       if (ret == 0 && old_ref_mod < 0 && new_ref_mod >= 0)
-               add_pinned_bytes(fs_info, -num_bytes, owner, root_objectid);
+       if (ret == 0 && old_ref_mod < 0 && new_ref_mod >= 0) {
+               bool metadata = owner < BTRFS_FIRST_FREE_OBJECTID;
+
+               add_pinned_bytes(fs_info, -num_bytes, metadata, root_objectid);
+       }
 
        return ret;
 }
@@ -2594,8 +2597,8 @@ static int cleanup_ref_head(struct btrfs_trans_handle *trans,
        delayed_refs->num_heads--;
        rb_erase(&head->href_node, &delayed_refs->href_root);
        RB_CLEAR_NODE(&head->href_node);
-       spin_unlock(&delayed_refs->lock);
        spin_unlock(&head->lock);
+       spin_unlock(&delayed_refs->lock);
        atomic_dec(&delayed_refs->num_entries);
 
        trace_run_delayed_ref_head(fs_info, head, 0);
@@ -2710,7 +2713,7 @@ static noinline int __btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
                ref = select_delayed_ref(locked_ref);
 
                if (ref && ref->seq &&
-                   btrfs_check_delayed_seq(fs_info, delayed_refs, ref->seq)) {
+                   btrfs_check_delayed_seq(fs_info, ref->seq)) {
                        spin_unlock(&locked_ref->lock);
                        unselect_delayed_ref_head(delayed_refs, locked_ref);
                        locked_ref = NULL;
@@ -3142,7 +3145,11 @@ static noinline int check_delayed_ref(struct btrfs_root *root,
        struct rb_node *node;
        int ret = 0;
 
+       spin_lock(&root->fs_info->trans_lock);
        cur_trans = root->fs_info->running_transaction;
+       if (cur_trans)
+               refcount_inc(&cur_trans->use_count);
+       spin_unlock(&root->fs_info->trans_lock);
        if (!cur_trans)
                return 0;
 
@@ -3151,6 +3158,7 @@ static noinline int check_delayed_ref(struct btrfs_root *root,
        head = btrfs_find_delayed_ref_head(delayed_refs, bytenr);
        if (!head) {
                spin_unlock(&delayed_refs->lock);
+               btrfs_put_transaction(cur_trans);
                return 0;
        }
 
@@ -3167,6 +3175,7 @@ static noinline int check_delayed_ref(struct btrfs_root *root,
                mutex_lock(&head->mutex);
                mutex_unlock(&head->mutex);
                btrfs_put_delayed_ref_head(head);
+               btrfs_put_transaction(cur_trans);
                return -EAGAIN;
        }
        spin_unlock(&delayed_refs->lock);
@@ -3199,6 +3208,7 @@ static noinline int check_delayed_ref(struct btrfs_root *root,
        }
        spin_unlock(&head->lock);
        mutex_unlock(&head->mutex);
+       btrfs_put_transaction(cur_trans);
        return ret;
 }
 
@@ -7259,7 +7269,7 @@ void btrfs_free_tree_block(struct btrfs_trans_handle *trans,
        }
 out:
        if (pin)
-               add_pinned_bytes(fs_info, buf->len, btrfs_header_level(buf),
+               add_pinned_bytes(fs_info, buf->len, true,
                                 root->root_key.objectid);
 
        if (last_ref) {
@@ -7313,8 +7323,11 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans,
                                                 &old_ref_mod, &new_ref_mod);
        }
 
-       if (ret == 0 && old_ref_mod >= 0 && new_ref_mod < 0)
-               add_pinned_bytes(fs_info, num_bytes, owner, root_objectid);
+       if (ret == 0 && old_ref_mod >= 0 && new_ref_mod < 0) {
+               bool metadata = owner < BTRFS_FIRST_FREE_OBJECTID;
+
+               add_pinned_bytes(fs_info, num_bytes, metadata, root_objectid);
+       }
 
        return ret;
 }