Commit 18f687d538449373c37cbe52b03f5f3d42b7c7ed
Committed by
Chris Mason
1 parent
896c14f97f
Exists in
master
and in
16 other branches
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>
Showing 2 changed files with 29 additions and 0 deletions Side-by-side Diff
fs/btrfs/send.c
... | ... | @@ -4753,6 +4753,7 @@ |
4753 | 4753 | u64 *clone_sources_tmp = NULL; |
4754 | 4754 | int clone_sources_to_rollback = 0; |
4755 | 4755 | int sort_clone_roots = 0; |
4756 | + int index; | |
4756 | 4757 | |
4757 | 4758 | if (!capable(CAP_SYS_ADMIN)) |
4758 | 4759 | return -EPERM; |
4759 | 4760 | |
... | ... | @@ -4893,8 +4894,12 @@ |
4893 | 4894 | key.objectid = clone_sources_tmp[i]; |
4894 | 4895 | key.type = BTRFS_ROOT_ITEM_KEY; |
4895 | 4896 | key.offset = (u64)-1; |
4897 | + | |
4898 | + index = srcu_read_lock(&fs_info->subvol_srcu); | |
4899 | + | |
4896 | 4900 | clone_root = btrfs_read_fs_root_no_name(fs_info, &key); |
4897 | 4901 | if (IS_ERR(clone_root)) { |
4902 | + srcu_read_unlock(&fs_info->subvol_srcu, index); | |
4898 | 4903 | ret = PTR_ERR(clone_root); |
4899 | 4904 | goto out; |
4900 | 4905 | } |
4901 | 4906 | |
... | ... | @@ -4903,10 +4908,13 @@ |
4903 | 4908 | clone_root->send_in_progress++; |
4904 | 4909 | if (!btrfs_root_readonly(clone_root)) { |
4905 | 4910 | spin_unlock(&clone_root->root_item_lock); |
4911 | + srcu_read_unlock(&fs_info->subvol_srcu, index); | |
4906 | 4912 | ret = -EPERM; |
4907 | 4913 | goto out; |
4908 | 4914 | } |
4909 | 4915 | spin_unlock(&clone_root->root_item_lock); |
4916 | + srcu_read_unlock(&fs_info->subvol_srcu, index); | |
4917 | + | |
4910 | 4918 | sctx->clone_roots[i].root = clone_root; |
4911 | 4919 | } |
4912 | 4920 | vfree(clone_sources_tmp); |
4913 | 4921 | |
4914 | 4922 | |
4915 | 4923 | |
4916 | 4924 | |
... | ... | @@ -4917,19 +4925,27 @@ |
4917 | 4925 | key.objectid = arg->parent_root; |
4918 | 4926 | key.type = BTRFS_ROOT_ITEM_KEY; |
4919 | 4927 | key.offset = (u64)-1; |
4928 | + | |
4929 | + index = srcu_read_lock(&fs_info->subvol_srcu); | |
4930 | + | |
4920 | 4931 | sctx->parent_root = btrfs_read_fs_root_no_name(fs_info, &key); |
4921 | 4932 | if (IS_ERR(sctx->parent_root)) { |
4933 | + srcu_read_unlock(&fs_info->subvol_srcu, index); | |
4922 | 4934 | ret = PTR_ERR(sctx->parent_root); |
4923 | 4935 | goto out; |
4924 | 4936 | } |
4937 | + | |
4925 | 4938 | spin_lock(&sctx->parent_root->root_item_lock); |
4926 | 4939 | sctx->parent_root->send_in_progress++; |
4927 | 4940 | if (!btrfs_root_readonly(sctx->parent_root)) { |
4928 | 4941 | spin_unlock(&sctx->parent_root->root_item_lock); |
4942 | + srcu_read_unlock(&fs_info->subvol_srcu, index); | |
4929 | 4943 | ret = -EPERM; |
4930 | 4944 | goto out; |
4931 | 4945 | } |
4932 | 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 | /* |
fs/btrfs/transaction.c
... | ... | @@ -1972,6 +1972,19 @@ |
1972 | 1972 | } |
1973 | 1973 | root = list_first_entry(&fs_info->dead_roots, |
1974 | 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 | 1988 | list_del_init(&root->root_list); |
1976 | 1989 | spin_unlock(&fs_info->trans_lock); |
1977 | 1990 |
-
mentioned in commit 521e05
-
mentioned in commit 521e05
-
mentioned in commit 521e05
-
mentioned in commit 521e05
-
mentioned in commit 521e05
-
mentioned in commit 521e05
-
mentioned in commit 521e05
-
mentioned in commit 521e05
-
mentioned in commit 521e05
-
mentioned in commit 521e05
-
mentioned in commit 521e05
-
mentioned in commit 521e05
-
mentioned in commit 521e05