]> git.hungrycats.org Git - linux/commitdiff
btrfs: hold a ref on the root in build_backref_tree
authorJosef Bacik <josef@toxicpanda.com>
Wed, 20 Nov 2019 19:42:34 +0000 (11:42 -0800)
committerJosef Bacik <josef@toxicpanda.com>
Fri, 6 Dec 2019 16:34:48 +0000 (08:34 -0800)
This is trickier than the previous conversions.  We have backref_node's
that need to hold onto their root for their lifetime.  Do the read of
the root and grab the ref.  If at any point we don't use the root we
discard it, however if we use it in our backref node we don't free it
until we free the backref node.  Any time we switch the root's for the
backref node we need to drop our ref on the old root and grab the ref on
the new root, and if we dupe a node we need to get a ref on the root
there as well.

Signed-off-by: Josef Bacik <josef@toxicpanda.com>
fs/btrfs/relocation.c

index 3f11491e01eb66601677c9a06fbf571c174714cc..473bbbd58d31be80077f22bf385bf94417b3a275 100644 (file)
@@ -256,6 +256,8 @@ static void free_backref_node(struct backref_cache *cache,
 {
        if (node) {
                cache->nr_nodes--;
+               if (node->root)
+                       btrfs_put_fs_root(node->root);
                kfree(node);
        }
 }
@@ -859,6 +861,10 @@ again:
                        err = PTR_ERR(root);
                        goto out;
                }
+               if (!btrfs_grab_fs_root(root)) {
+                       err = -ENOENT;
+                       goto out;
+               }
 
                if (!test_bit(BTRFS_ROOT_REF_COWS, &root->state))
                        cur->cowonly = 1;
@@ -867,10 +873,12 @@ again:
                        /* tree root */
                        ASSERT(btrfs_root_bytenr(&root->root_item) ==
                               cur->bytenr);
-                       if (should_ignore_root(root))
+                       if (should_ignore_root(root)) {
+                               btrfs_put_fs_root(root);
                                list_add(&cur->list, &useless);
-                       else
+                       } else {
                                cur->root = root;
+                       }
                        break;
                }
 
@@ -883,6 +891,7 @@ again:
                ret = btrfs_search_slot(NULL, root, node_key, path2, 0, 0);
                path2->lowest_level = 0;
                if (ret < 0) {
+                       btrfs_put_fs_root(root);
                        err = ret;
                        goto out;
                }
@@ -898,6 +907,7 @@ again:
                                  root->root_key.objectid,
                                  node_key->objectid, node_key->type,
                                  node_key->offset);
+                       btrfs_put_fs_root(root);
                        err = -ENOENT;
                        goto out;
                }
@@ -909,15 +919,18 @@ again:
                        if (!path2->nodes[level]) {
                                ASSERT(btrfs_root_bytenr(&root->root_item) ==
                                       lower->bytenr);
-                               if (should_ignore_root(root))
+                               if (should_ignore_root(root)) {
+                                       btrfs_put_fs_root(root);
                                        list_add(&lower->list, &useless);
-                               else
+                               } else {
                                        lower->root = root;
+                               }
                                break;
                        }
 
                        edge = alloc_backref_edge(cache);
                        if (!edge) {
+                               btrfs_put_fs_root(root);
                                err = -ENOMEM;
                                goto out;
                        }
@@ -927,6 +940,7 @@ again:
                        if (!rb_node) {
                                upper = alloc_backref_node(cache);
                                if (!upper) {
+                                       btrfs_put_fs_root(root);
                                        free_backref_edge(cache, edge);
                                        err = -ENOMEM;
                                        goto out;
@@ -974,8 +988,10 @@ again:
                        edge->node[LOWER] = lower;
                        edge->node[UPPER] = upper;
 
-                       if (rb_node)
+                       if (rb_node) {
+                               btrfs_put_fs_root(root);
                                break;
+                       }
                        lower = upper;
                        upper = NULL;
                }
@@ -1212,7 +1228,8 @@ static int clone_backref_node(struct btrfs_trans_handle *trans,
        new_node->level = node->level;
        new_node->lowest = node->lowest;
        new_node->checked = 1;
-       new_node->root = dest;
+       new_node->root = btrfs_grab_fs_root(dest);
+       ASSERT(new_node->root);
 
        if (!node->lowest) {
                list_for_each_entry(edge, &node->lower, list[UPPER]) {
@@ -2581,7 +2598,9 @@ struct btrfs_root *select_reloc_root(struct btrfs_trans_handle *trans,
                        BUG_ON(next->new_bytenr);
                        BUG_ON(!list_empty(&next->list));
                        next->new_bytenr = root->node->start;
-                       next->root = root;
+                       btrfs_put_fs_root(next->root);
+                       next->root = btrfs_grab_fs_root(root);
+                       ASSERT(next->root);
                        list_add_tail(&next->list,
                                      &rc->backref_cache.changed);
                        __mark_block_processed(rc, next);
@@ -3053,7 +3072,9 @@ static int relocate_tree_block(struct btrfs_trans_handle *trans,
                        btrfs_record_root_in_trans(trans, root);
                        root = root->reloc_root;
                        node->new_bytenr = root->node->start;
-                       node->root = root;
+                       btrfs_put_fs_root(node->root);
+                       node->root = btrfs_grab_fs_root(root);
+                       ASSERT(node->root);
                        list_add_tail(&node->list, &rc->backref_cache.changed);
                } else {
                        path->lowest_level = node->level;