btrfs: Remove redundant extent_buffer_get in get_old_root
[sfrench/cifs-2.6.git] / fs / btrfs / ctree.c
index 2ee43b6a4f0995367ca5497f87d343674b319553..0c5ece3fe74124e58c546c08e19bfd2e45159dc8 100644 (file)
@@ -1014,9 +1014,26 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
        if ((root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) && parent)
                parent_start = parent->start;
 
+       /*
+        * If we are COWing a node/leaf from the extent, chunk or device trees,
+        * make sure that we do not finish block group creation of pending block
+        * groups. We do this to avoid a deadlock.
+        * COWing can result in allocation of a new chunk, and flushing pending
+        * block groups (btrfs_create_pending_block_groups()) can be triggered
+        * when finishing allocation of a new chunk. Creation of a pending block
+        * group modifies the extent, chunk and device trees, therefore we could
+        * deadlock with ourselves since we are holding a lock on an extent
+        * buffer that btrfs_create_pending_block_groups() may try to COW later.
+        */
+       if (root == fs_info->extent_root ||
+           root == fs_info->chunk_root ||
+           root == fs_info->dev_root)
+               trans->can_flush_pending_bgs = false;
+
        cow = btrfs_alloc_tree_block(trans, root, parent_start,
                        root->root_key.objectid, &disk_key, level,
                        search_start, empty_size);
+       trans->can_flush_pending_bgs = true;
        if (IS_ERR(cow))
                return PTR_ERR(cow);
 
@@ -1345,7 +1362,6 @@ get_old_root(struct btrfs_root *root, u64 time_seq)
 
        if (!eb)
                return NULL;
-       extent_buffer_get(eb);
        btrfs_tree_read_lock(eb);
        if (old_root) {
                btrfs_set_header_bytenr(eb, eb->start);