summaryrefslogtreecommitdiff
path: root/fs/btrfs/send.c
diff options
context:
space:
mode:
authorJosef Bacik <josef@toxicpanda.com>2020-01-24 17:32:48 +0300
committerDavid Sterba <dsterba@suse.com>2020-03-23 19:01:31 +0300
commit6f9a3da5da9e7e59f3a5a5909aab5f680fe919c9 (patch)
tree98490b1ead38f5e3e29cdd1639ab421dc064f06e /fs/btrfs/send.c
parentfd79d43b347e12b3f7ededaadf6437c6538247c7 (diff)
downloadlinux-6f9a3da5da9e7e59f3a5a5909aab5f680fe919c9.tar.xz
btrfs: hold a ref on the root in btrfs_ioctl_send
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> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
Diffstat (limited to 'fs/btrfs/send.c')
-rw-r--r--fs/btrfs/send.c28
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);