]> git.hungrycats.org Git - linux/commitdiff
btrfs: hold a ref on the root in btrfs_ioctl_send
authorJosef Bacik <josef@toxicpanda.com>
Wed, 20 Nov 2019 20:22:04 +0000 (12:22 -0800)
committerJosef Bacik <josef@toxicpanda.com>
Fri, 6 Dec 2019 16:34:48 +0000 (08:34 -0800)
We lookup all the clone roots and the parent root for send, so we need
to hold refs on all of these roots while we're processing them.

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

index 73e2e350f4a1c900cb14de74898ad017c690b761..a82201e6979ec14edd94d626f25c3b8f2a7c23b7 100644 (file)
@@ -7206,11 +7206,17 @@ long btrfs_ioctl_send(struct file *mnt_file, struct btrfs_ioctl_send_args *arg)
                                ret = PTR_ERR(clone_root);
                                goto out;
                        }
+                       if (!btrfs_grab_fs_root(clone_root)) {
+                               srcu_read_unlock(&fs_info->subvol_srcu, index);
+                               ret = -ENOENT;
+                               goto out;
+                       }
                        spin_lock(&clone_root->root_item_lock);
                        if (!btrfs_root_readonly(clone_root) ||
                            btrfs_root_dead(clone_root)) {
                                spin_unlock(&clone_root->root_item_lock);
                                srcu_read_unlock(&fs_info->subvol_srcu, index);
+                               btrfs_put_fs_root(clone_root);
                                ret = -EPERM;
                                goto out;
                        }
@@ -7218,6 +7224,7 @@ long btrfs_ioctl_send(struct file *mnt_file, struct btrfs_ioctl_send_args *arg)
                                dedupe_in_progress_warn(clone_root);
                                spin_unlock(&clone_root->root_item_lock);
                                srcu_read_unlock(&fs_info->subvol_srcu, index);
+                               btrfs_put_fs_root(clone_root);
                                ret = -EAGAIN;
                                goto out;
                        }
@@ -7245,6 +7252,12 @@ long btrfs_ioctl_send(struct file *mnt_file, struct btrfs_ioctl_send_args *arg)
                        ret = PTR_ERR(sctx->parent_root);
                        goto out;
                }
+               if (!btrfs_grab_fs_root(sctx->parent_root)) {
+                       srcu_read_unlock(&fs_info->subvol_srcu, index);
+                       ret = -ENOENT;
+                       sctx->parent_root = ERR_PTR(ret);
+                       goto out;
+               }
 
                spin_lock(&sctx->parent_root->root_item_lock);
                sctx->parent_root->send_in_progress++;
@@ -7272,7 +7285,8 @@ long btrfs_ioctl_send(struct file *mnt_file, struct btrfs_ioctl_send_args *arg)
         * is behind the current send position. This is checked while searching
         * for possible clone sources.
         */
-       sctx->clone_roots[sctx->clone_roots_cnt++].root = sctx->send_root;
+       sctx->clone_roots[sctx->clone_roots_cnt++].root =
+               btrfs_grab_fs_root(sctx->send_root);
 
        /* We do a bsearch later */
        sort(sctx->clone_roots, sctx->clone_roots_cnt,
@@ -7357,18 +7371,24 @@ out:
        }
 
        if (sort_clone_roots) {
-               for (i = 0; i < sctx->clone_roots_cnt; i++)
+               for (i = 0; i < sctx->clone_roots_cnt; i++) {
                        btrfs_root_dec_send_in_progress(
                                        sctx->clone_roots[i].root);
+                       btrfs_put_fs_root(sctx->clone_roots[i].root);
+               }
        } else {
-               for (i = 0; sctx && i < clone_sources_to_rollback; i++)
+               for (i = 0; sctx && i < clone_sources_to_rollback; i++) {
                        btrfs_root_dec_send_in_progress(
                                        sctx->clone_roots[i].root);
+                       btrfs_put_fs_root(sctx->clone_roots[i].root);
+               }
 
                btrfs_root_dec_send_in_progress(send_root);
        }
-       if (sctx && !IS_ERR_OR_NULL(sctx->parent_root))
+       if (sctx && !IS_ERR_OR_NULL(sctx->parent_root)) {
                btrfs_root_dec_send_in_progress(sctx->parent_root);
+               btrfs_put_fs_root(sctx->parent_root);
+       }
 
        kvfree(clone_sources_tmp);