diff options
-rw-r--r-- | fs/btrfs/send.c | 28 |
1 files changed, 24 insertions, 4 deletions
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index 27e580564e49..31495cdf1877 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -7201,10 +7201,16 @@ 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); + btrfs_put_fs_root(clone_root); srcu_read_unlock(&fs_info->subvol_srcu, index); ret = -EPERM; goto out; @@ -7212,6 +7218,7 @@ long btrfs_ioctl_send(struct file *mnt_file, struct btrfs_ioctl_send_args *arg) if (clone_root->dedupe_in_progress) { dedupe_in_progress_warn(clone_root); spin_unlock(&clone_root->root_item_lock); + btrfs_put_fs_root(clone_root); srcu_read_unlock(&fs_info->subvol_srcu, index); ret = -EAGAIN; goto out; @@ -7240,6 +7247,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++; @@ -7267,7 +7280,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, @@ -7352,18 +7366,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); |