diff options
author | Wang Shilong <wangsl.fnst@cn.fujitsu.com> | 2014-01-07 04:25:19 -0500 |
---|---|---|
committer | Chris Mason <clm@fb.com> | 2014-01-28 16:20:21 -0500 |
commit | 18f687d538449373c37cbe52b03f5f3d42b7c7ed (patch) | |
tree | da340e3522b0e22516af99a7f3cb44d96cfdd6cf | |
parent | 896c14f97f700aec6565154f2451605d7c5ce3ed (diff) |
Btrfs: fix protection between send and root deletion
We should gurantee that parent and clone roots 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.
Besides in btrfs_clean_one_deleted_snapshot(), we only check first root
, if this root is involved in send, we return directly rather than
continue to check.There are several reasons about it:
1.this case happen seldomly.
2.after sending,cleaner thread can continue to drop that root.
3.make code simple
Cc: David Sterba <dsterba@suse.cz>
Signed-off-by: Wang Shilong <wangsl.fnst@cn.fujitsu.com>
Reviewed-by: Miao Xie <miaox@cn.fujitsu.com>
Signed-off-by: Josef Bacik <jbacik@fb.com>
Signed-off-by: Chris Mason <clm@fb.com>
-rw-r--r-- | fs/btrfs/send.c | 16 | ||||
-rw-r--r-- | fs/btrfs/transaction.c | 13 |
2 files changed, 29 insertions, 0 deletions
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index 5b6978516461..4e2461b857f3 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c | |||
@@ -4753,6 +4753,7 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_) | |||
4753 | u64 *clone_sources_tmp = NULL; | 4753 | u64 *clone_sources_tmp = NULL; |
4754 | int clone_sources_to_rollback = 0; | 4754 | int clone_sources_to_rollback = 0; |
4755 | int sort_clone_roots = 0; | 4755 | int sort_clone_roots = 0; |
4756 | int index; | ||
4756 | 4757 | ||
4757 | if (!capable(CAP_SYS_ADMIN)) | 4758 | if (!capable(CAP_SYS_ADMIN)) |
4758 | return -EPERM; | 4759 | return -EPERM; |
@@ -4893,8 +4894,12 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_) | |||
4893 | key.objectid = clone_sources_tmp[i]; | 4894 | key.objectid = clone_sources_tmp[i]; |
4894 | key.type = BTRFS_ROOT_ITEM_KEY; | 4895 | key.type = BTRFS_ROOT_ITEM_KEY; |
4895 | key.offset = (u64)-1; | 4896 | key.offset = (u64)-1; |
4897 | |||
4898 | index = srcu_read_lock(&fs_info->subvol_srcu); | ||
4899 | |||
4896 | clone_root = btrfs_read_fs_root_no_name(fs_info, &key); | 4900 | clone_root = btrfs_read_fs_root_no_name(fs_info, &key); |
4897 | if (IS_ERR(clone_root)) { | 4901 | if (IS_ERR(clone_root)) { |
4902 | srcu_read_unlock(&fs_info->subvol_srcu, index); | ||
4898 | ret = PTR_ERR(clone_root); | 4903 | ret = PTR_ERR(clone_root); |
4899 | goto out; | 4904 | goto out; |
4900 | } | 4905 | } |
@@ -4903,10 +4908,13 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_) | |||
4903 | clone_root->send_in_progress++; | 4908 | clone_root->send_in_progress++; |
4904 | if (!btrfs_root_readonly(clone_root)) { | 4909 | if (!btrfs_root_readonly(clone_root)) { |
4905 | spin_unlock(&clone_root->root_item_lock); | 4910 | spin_unlock(&clone_root->root_item_lock); |
4911 | srcu_read_unlock(&fs_info->subvol_srcu, index); | ||
4906 | ret = -EPERM; | 4912 | ret = -EPERM; |
4907 | goto out; | 4913 | goto out; |
4908 | } | 4914 | } |
4909 | spin_unlock(&clone_root->root_item_lock); | 4915 | spin_unlock(&clone_root->root_item_lock); |
4916 | srcu_read_unlock(&fs_info->subvol_srcu, index); | ||
4917 | |||
4910 | sctx->clone_roots[i].root = clone_root; | 4918 | sctx->clone_roots[i].root = clone_root; |
4911 | } | 4919 | } |
4912 | vfree(clone_sources_tmp); | 4920 | vfree(clone_sources_tmp); |
@@ -4917,19 +4925,27 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_) | |||
4917 | key.objectid = arg->parent_root; | 4925 | key.objectid = arg->parent_root; |
4918 | key.type = BTRFS_ROOT_ITEM_KEY; | 4926 | key.type = BTRFS_ROOT_ITEM_KEY; |
4919 | key.offset = (u64)-1; | 4927 | key.offset = (u64)-1; |
4928 | |||
4929 | index = srcu_read_lock(&fs_info->subvol_srcu); | ||
4930 | |||
4920 | sctx->parent_root = btrfs_read_fs_root_no_name(fs_info, &key); | 4931 | sctx->parent_root = btrfs_read_fs_root_no_name(fs_info, &key); |
4921 | if (IS_ERR(sctx->parent_root)) { | 4932 | if (IS_ERR(sctx->parent_root)) { |
4933 | srcu_read_unlock(&fs_info->subvol_srcu, index); | ||
4922 | ret = PTR_ERR(sctx->parent_root); | 4934 | ret = PTR_ERR(sctx->parent_root); |
4923 | goto out; | 4935 | goto out; |
4924 | } | 4936 | } |
4937 | |||
4925 | spin_lock(&sctx->parent_root->root_item_lock); | 4938 | spin_lock(&sctx->parent_root->root_item_lock); |
4926 | sctx->parent_root->send_in_progress++; | 4939 | sctx->parent_root->send_in_progress++; |
4927 | if (!btrfs_root_readonly(sctx->parent_root)) { | 4940 | if (!btrfs_root_readonly(sctx->parent_root)) { |
4928 | spin_unlock(&sctx->parent_root->root_item_lock); | 4941 | spin_unlock(&sctx->parent_root->root_item_lock); |
4942 | srcu_read_unlock(&fs_info->subvol_srcu, index); | ||
4929 | ret = -EPERM; | 4943 | ret = -EPERM; |
4930 | goto out; | 4944 | goto out; |
4931 | } | 4945 | } |
4932 | spin_unlock(&sctx->parent_root->root_item_lock); | 4946 | spin_unlock(&sctx->parent_root->root_item_lock); |
4947 | |||
4948 | srcu_read_unlock(&fs_info->subvol_srcu, index); | ||
4933 | } | 4949 | } |
4934 | 4950 | ||
4935 | /* | 4951 | /* |
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index e5fe801659ba..da2ac4c6d78b 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -1972,6 +1972,19 @@ int btrfs_clean_one_deleted_snapshot(struct btrfs_root *root) | |||
1972 | } | 1972 | } |
1973 | root = list_first_entry(&fs_info->dead_roots, | 1973 | root = list_first_entry(&fs_info->dead_roots, |
1974 | struct btrfs_root, root_list); | 1974 | struct btrfs_root, root_list); |
1975 | /* | ||
1976 | * Make sure root is not involved in send, | ||
1977 | * if we fail with first root, we return | ||
1978 | * directly rather than continue. | ||
1979 | */ | ||
1980 | spin_lock(&root->root_item_lock); | ||
1981 | if (root->send_in_progress) { | ||
1982 | spin_unlock(&fs_info->trans_lock); | ||
1983 | spin_unlock(&root->root_item_lock); | ||
1984 | return 0; | ||
1985 | } | ||
1986 | spin_unlock(&root->root_item_lock); | ||
1987 | |||
1975 | list_del_init(&root->root_list); | 1988 | list_del_init(&root->root_list); |
1976 | spin_unlock(&fs_info->trans_lock); | 1989 | spin_unlock(&fs_info->trans_lock); |
1977 | 1990 | ||