If we fail to setup a ->reloc_root in a different thread that path will
error out, however it still leaves root->reloc_root NULL but would still
appear set up in the transaction.  Subsequent calls to
btrfs_record_root_in_transaction would succeed without attempting to
create the reloc root, as the transid has already been update.  Handle
this case by making sure we have a root->reloc_root set after a
btrfs_record_root_in_transaction call so we don't end up deref'ing a
NULL pointer.

Reported-by: Zygo Blaxell <ce3g8...@umail.furryterror.org>
Signed-off-by: Josef Bacik <jo...@toxicpanda.com>
---
 fs/btrfs/relocation.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c
index df26d6055cc6..4022649e2365 100644
--- a/fs/btrfs/relocation.c
+++ b/fs/btrfs/relocation.c
@@ -2081,6 +2081,13 @@ struct btrfs_root *select_reloc_root(struct 
btrfs_trans_handle *trans,
                        return ERR_PTR(ret);
                root = root->reloc_root;
 
+               /*
+                * We could have raced with another thread which failed, so
+                * ->reloc_root may not be set, return -ENOENT in this case.
+                */
+               if (!root)
+                       return ERR_PTR(-ENOENT);
+
                if (next->new_bytenr != root->node->start) {
                        /*
                         * We just created the reloc root, so we shouldn't have
@@ -2578,6 +2585,14 @@ static int relocate_tree_block(struct btrfs_trans_handle 
*trans,
                        ret = btrfs_record_root_in_trans(trans, root);
                        if (ret)
                                goto out;
+                       /*
+                        * Another thread could have failed, need to check if we
+                        * have ->reloc_root actually set.
+                        */
+                       if (!root->reloc_root) {
+                               ret = -ENOENT;
+                               goto out;
+                       }
                        root = root->reloc_root;
                        node->new_bytenr = root->node->start;
                        btrfs_put_root(node->root);
-- 
2.26.2

Reply via email to