Wang Shilong
2014-Jan-06 09:25 UTC
[PATCH 2/4] Btrfs: fix protection between send and root deletion
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 <wangsl.fnst@cn.fujitsu.com>
Reviewed-by: Miao Xie <miaox@cn.fujitsu.com>
---
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 majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html