Skip to content

Commit

Permalink
Btrfs: fix protection between send and root deletion
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Wang Shilong <[email protected]>
Reviewed-by: Miao Xie <[email protected]>
Signed-off-by: Josef Bacik <[email protected]>
Signed-off-by: Chris Mason <[email protected]>
  • Loading branch information
Wang Shilong authored and masoncl committed Jan 28, 2014
1 parent 896c14f commit 18f687d
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 0 deletions.
16 changes: 16 additions & 0 deletions fs/btrfs/send.c
Original file line number Diff line number Diff line change
Expand Up @@ -4753,6 +4753,7 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_)
u64 *clone_sources_tmp = NULL;
int clone_sources_to_rollback = 0;
int sort_clone_roots = 0;
int index;

if (!capable(CAP_SYS_ADMIN))
return -EPERM;
Expand Down Expand Up @@ -4893,8 +4894,12 @@ 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;
}
Expand All @@ -4903,10 +4908,13 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_)
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;
}
vfree(clone_sources_tmp);
Expand All @@ -4917,19 +4925,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);
}

/*
Expand Down
13 changes: 13 additions & 0 deletions fs/btrfs/transaction.c
Original file line number Diff line number Diff line change
Expand Up @@ -1972,6 +1972,19 @@ int btrfs_clean_one_deleted_snapshot(struct btrfs_root *root)
}
root = list_first_entry(&fs_info->dead_roots,
struct btrfs_root, root_list);
/*
* Make sure root is not involved in send,
* if we fail with first root, we return
* directly rather than continue.
*/
spin_lock(&root->root_item_lock);
if (root->send_in_progress) {
spin_unlock(&fs_info->trans_lock);
spin_unlock(&root->root_item_lock);
return 0;
}
spin_unlock(&root->root_item_lock);

list_del_init(&root->root_list);
spin_unlock(&fs_info->trans_lock);

Expand Down

0 comments on commit 18f687d

Please sign in to comment.