Commit 18f687d538449373c37cbe52b03f5f3d42b7c7ed

Authored by Wang Shilong
Committed by Chris Mason
1 parent 896c14f97f

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

... ... @@ -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