Commit 0b530bc5 authored by Josef Bacik's avatar Josef Bacik Committed by David Sterba

btrfs: hold a ref on the root in build_backref_tree

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: default avatarJosef Bacik <josef@toxicpanda.com>
Reviewed-by: default avatarDavid Sterba <dsterba@suse.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent 2a2b5d62
...@@ -303,6 +303,7 @@ static void free_backref_node(struct backref_cache *cache, ...@@ -303,6 +303,7 @@ static void free_backref_node(struct backref_cache *cache,
{ {
if (node) { if (node) {
cache->nr_nodes--; cache->nr_nodes--;
btrfs_put_fs_root(node->root);
kfree(node); kfree(node);
} }
} }
...@@ -636,7 +637,7 @@ static struct btrfs_root *find_reloc_root(struct reloc_control *rc, ...@@ -636,7 +637,7 @@ static struct btrfs_root *find_reloc_root(struct reloc_control *rc,
root = (struct btrfs_root *)node->data; root = (struct btrfs_root *)node->data;
} }
spin_unlock(&rc->reloc_root_tree.lock); spin_unlock(&rc->reloc_root_tree.lock);
return root; return btrfs_grab_fs_root(root);
} }
static int is_cowonly_root(u64 root_objectid) static int is_cowonly_root(u64 root_objectid)
...@@ -938,6 +939,10 @@ struct backref_node *build_backref_tree(struct reloc_control *rc, ...@@ -938,6 +939,10 @@ struct backref_node *build_backref_tree(struct reloc_control *rc,
err = PTR_ERR(root); err = PTR_ERR(root);
goto out; goto out;
} }
if (!btrfs_grab_fs_root(root)) {
err = -ENOENT;
goto out;
}
if (!test_bit(BTRFS_ROOT_REF_COWS, &root->state)) if (!test_bit(BTRFS_ROOT_REF_COWS, &root->state))
cur->cowonly = 1; cur->cowonly = 1;
...@@ -946,10 +951,12 @@ struct backref_node *build_backref_tree(struct reloc_control *rc, ...@@ -946,10 +951,12 @@ struct backref_node *build_backref_tree(struct reloc_control *rc,
/* tree root */ /* tree root */
ASSERT(btrfs_root_bytenr(&root->root_item) == ASSERT(btrfs_root_bytenr(&root->root_item) ==
cur->bytenr); cur->bytenr);
if (should_ignore_root(root)) if (should_ignore_root(root)) {
btrfs_put_fs_root(root);
list_add(&cur->list, &useless); list_add(&cur->list, &useless);
else } else {
cur->root = root; cur->root = root;
}
break; break;
} }
...@@ -962,6 +969,7 @@ struct backref_node *build_backref_tree(struct reloc_control *rc, ...@@ -962,6 +969,7 @@ struct backref_node *build_backref_tree(struct reloc_control *rc,
ret = btrfs_search_slot(NULL, root, node_key, path2, 0, 0); ret = btrfs_search_slot(NULL, root, node_key, path2, 0, 0);
path2->lowest_level = 0; path2->lowest_level = 0;
if (ret < 0) { if (ret < 0) {
btrfs_put_fs_root(root);
err = ret; err = ret;
goto out; goto out;
} }
...@@ -977,6 +985,7 @@ struct backref_node *build_backref_tree(struct reloc_control *rc, ...@@ -977,6 +985,7 @@ struct backref_node *build_backref_tree(struct reloc_control *rc,
root->root_key.objectid, root->root_key.objectid,
node_key->objectid, node_key->type, node_key->objectid, node_key->type,
node_key->offset); node_key->offset);
btrfs_put_fs_root(root);
err = -ENOENT; err = -ENOENT;
goto out; goto out;
} }
...@@ -988,15 +997,18 @@ struct backref_node *build_backref_tree(struct reloc_control *rc, ...@@ -988,15 +997,18 @@ struct backref_node *build_backref_tree(struct reloc_control *rc,
if (!path2->nodes[level]) { if (!path2->nodes[level]) {
ASSERT(btrfs_root_bytenr(&root->root_item) == ASSERT(btrfs_root_bytenr(&root->root_item) ==
lower->bytenr); lower->bytenr);
if (should_ignore_root(root)) if (should_ignore_root(root)) {
btrfs_put_fs_root(root);
list_add(&lower->list, &useless); list_add(&lower->list, &useless);
else } else {
lower->root = root; lower->root = root;
}
break; break;
} }
edge = alloc_backref_edge(cache); edge = alloc_backref_edge(cache);
if (!edge) { if (!edge) {
btrfs_put_fs_root(root);
err = -ENOMEM; err = -ENOMEM;
goto out; goto out;
} }
...@@ -1006,6 +1018,7 @@ struct backref_node *build_backref_tree(struct reloc_control *rc, ...@@ -1006,6 +1018,7 @@ struct backref_node *build_backref_tree(struct reloc_control *rc,
if (!rb_node) { if (!rb_node) {
upper = alloc_backref_node(cache); upper = alloc_backref_node(cache);
if (!upper) { if (!upper) {
btrfs_put_fs_root(root);
free_backref_edge(cache, edge); free_backref_edge(cache, edge);
err = -ENOMEM; err = -ENOMEM;
goto out; goto out;
...@@ -1053,8 +1066,10 @@ struct backref_node *build_backref_tree(struct reloc_control *rc, ...@@ -1053,8 +1066,10 @@ struct backref_node *build_backref_tree(struct reloc_control *rc,
edge->node[LOWER] = lower; edge->node[LOWER] = lower;
edge->node[UPPER] = upper; edge->node[UPPER] = upper;
if (rb_node) if (rb_node) {
btrfs_put_fs_root(root);
break; break;
}
lower = upper; lower = upper;
upper = NULL; upper = NULL;
} }
...@@ -1291,7 +1306,8 @@ static int clone_backref_node(struct btrfs_trans_handle *trans, ...@@ -1291,7 +1306,8 @@ static int clone_backref_node(struct btrfs_trans_handle *trans,
new_node->level = node->level; new_node->level = node->level;
new_node->lowest = node->lowest; new_node->lowest = node->lowest;
new_node->checked = 1; new_node->checked = 1;
new_node->root = dest; new_node->root = btrfs_grab_fs_root(dest);
ASSERT(new_node->root);
if (!node->lowest) { if (!node->lowest) {
list_for_each_entry(edge, &node->lower, list[UPPER]) { list_for_each_entry(edge, &node->lower, list[UPPER]) {
...@@ -2669,7 +2685,9 @@ struct btrfs_root *select_reloc_root(struct btrfs_trans_handle *trans, ...@@ -2669,7 +2685,9 @@ struct btrfs_root *select_reloc_root(struct btrfs_trans_handle *trans,
BUG_ON(next->new_bytenr); BUG_ON(next->new_bytenr);
BUG_ON(!list_empty(&next->list)); BUG_ON(!list_empty(&next->list));
next->new_bytenr = root->node->start; 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, list_add_tail(&next->list,
&rc->backref_cache.changed); &rc->backref_cache.changed);
__mark_block_processed(rc, next); __mark_block_processed(rc, next);
...@@ -3141,7 +3159,9 @@ static int relocate_tree_block(struct btrfs_trans_handle *trans, ...@@ -3141,7 +3159,9 @@ static int relocate_tree_block(struct btrfs_trans_handle *trans,
btrfs_record_root_in_trans(trans, root); btrfs_record_root_in_trans(trans, root);
root = root->reloc_root; root = root->reloc_root;
node->new_bytenr = root->node->start; 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); list_add_tail(&node->list, &rc->backref_cache.changed);
} else { } else {
path->lowest_level = node->level; path->lowest_level = node->level;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment