aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWang Shilong <wangsl.fnst@cn.fujitsu.com>2014-01-07 04:25:19 -0500
committerChris Mason <clm@fb.com>2014-01-28 16:20:21 -0500
commit18f687d538449373c37cbe52b03f5f3d42b7c7ed (patch)
treeda340e3522b0e22516af99a7f3cb44d96cfdd6cf
parent896c14f97f700aec6565154f2451605d7c5ce3ed (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.c16
-rw-r--r--fs/btrfs/transaction.c13
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