We should gurantee that parent and clone root can not be destroyed
during send, for this we have two ideas.

1.by holding @subvol_sem, this might be a nightmare, because it will
block all subvolumes deletion for a long time.

2.Miao pointed out we can reuse @send_in_progress, that mean we will
skip snapshot deletion if root sending is in progress.

Here we adopt the second approach since it won't block other subvolumes
deletion for a long time.

Signed-off-by: Wang Shilong <[email protected]>
Reviewed-by: Miao Xie <[email protected]>
---
 fs/btrfs/ctree.h | 13 ++++++++++---
 fs/btrfs/send.c  | 17 +++++++++++++++++
 2 files changed, 27 insertions(+), 3 deletions(-)

diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 71e1fc7..ea19eff 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -3505,12 +3505,19 @@ static inline int btrfs_fs_closing(struct btrfs_fs_info 
*fs_info)
 }
 
 /*
- * If we remount the fs to be R/O or umount the fs, the cleaner needn't do
- * anything except sleeping. This function is used to check the status of
- * the fs.
+ * If we remount the fs to be R/O, umount the fs or we are sending a
+ * subvolume, the cleaner needn't do anything except sleeping. This
+ * function is used to check the status of the fs.
  */
 static inline int btrfs_need_cleaner_sleep(struct btrfs_root *root)
 {
+       spin_lock(&root->root_item_lock);
+       if (root->send_in_progress) {
+               spin_unlock(&root->root_item_lock);
+               return 1;
+       }
+       spin_unlock(&root->root_item_lock);
+
        return (root->fs_info->sb->s_flags & MS_RDONLY ||
                btrfs_fs_closing(root->fs_info));
 }
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
index 076b066..f9cdeb7 100644
--- a/fs/btrfs/send.c
+++ b/fs/btrfs/send.c
@@ -4752,6 +4752,7 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user 
*arg_)
        u32 i;
        u64 *clone_sources_tmp = NULL;
        int clone_sources_to_rollback = 0;
+       int index;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
@@ -4892,20 +4893,28 @@ long btrfs_ioctl_send(struct file *mnt_file, void 
__user *arg_)
                        key.objectid = clone_sources_tmp[i];
                        key.type = BTRFS_ROOT_ITEM_KEY;
                        key.offset = (u64)-1;
+
+                       index = srcu_read_lock(&fs_info->subvol_srcu);
+
                        clone_root = btrfs_read_fs_root_no_name(fs_info, &key);
                        if (IS_ERR(clone_root)) {
+                               srcu_read_unlock(&fs_info->subvol_srcu, index);
                                ret = PTR_ERR(clone_root);
                                goto out;
                        }
                        clone_sources_to_rollback = i + 1;
+
                        spin_lock(&clone_root->root_item_lock);
                        clone_root->send_in_progress++;
                        if (!btrfs_root_readonly(clone_root)) {
                                spin_unlock(&clone_root->root_item_lock);
+                               srcu_read_unlock(&fs_info->subvol_srcu, index);
                                ret = -EPERM;
                                goto out;
                        }
                        spin_unlock(&clone_root->root_item_lock);
+                       srcu_read_unlock(&fs_info->subvol_srcu, index);
+
                        sctx->clone_roots[i].root = clone_root;
                }
                clone_sources_to_rollback--;
@@ -4917,19 +4926,27 @@ long btrfs_ioctl_send(struct file *mnt_file, void 
__user *arg_)
                key.objectid = arg->parent_root;
                key.type = BTRFS_ROOT_ITEM_KEY;
                key.offset = (u64)-1;
+
+               index = srcu_read_lock(&fs_info->subvol_srcu);
+
                sctx->parent_root = btrfs_read_fs_root_no_name(fs_info, &key);
                if (IS_ERR(sctx->parent_root)) {
+                       srcu_read_unlock(&fs_info->subvol_srcu, index);
                        ret = PTR_ERR(sctx->parent_root);
                        goto out;
                }
+
                spin_lock(&sctx->parent_root->root_item_lock);
                sctx->parent_root->send_in_progress++;
                if (!btrfs_root_readonly(sctx->parent_root)) {
                        spin_unlock(&sctx->parent_root->root_item_lock);
+                       srcu_read_unlock(&fs_info->subvol_srcu, index);
                        ret = -EPERM;
                        goto out;
                }
                spin_unlock(&sctx->parent_root->root_item_lock);
+
+               srcu_read_unlock(&fs_info->subvol_srcu, index);
        }
 
        /*
-- 
1.8.3.1

--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to