mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-04-10 20:38:50 -04:00
btrfs: send: check for dead send root under critical section
We're checking if the send root is dead without the protection of the root's root_item_lock spinlock, which is what protects the root's flags. The inverse, setting the dead flag on a root, is done under the protection of that lock, at btrfs_delete_subvolume(). Also checking and updating the root's send_in_progress counter is supposed to be done in the same critical section as checking for or setting the root dead flag, so that these operations are done atomically as a single step (which is correctly done by btrfs_delete_subvolume()). So fix this by checking if the send root is dead in the same critical section that updates the send_in_progress counter, which is protected by the root's root_item_lock spinlock. Signed-off-by: Filipe Manana <fdmanana@suse.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
committed by
David Sterba
parent
722d343f12
commit
dc058f5fda
@@ -8125,6 +8125,14 @@ long btrfs_ioctl_send(struct btrfs_inode *inode, const struct btrfs_ioctl_send_a
|
||||
* making it RW. This also protects against deletion.
|
||||
*/
|
||||
spin_lock(&send_root->root_item_lock);
|
||||
/*
|
||||
* Unlikely but possible, if the subvolume is marked for deletion but
|
||||
* is slow to remove the directory entry, send can still be started.
|
||||
*/
|
||||
if (btrfs_root_dead(send_root)) {
|
||||
spin_unlock(&send_root->root_item_lock);
|
||||
return -EPERM;
|
||||
}
|
||||
if (btrfs_root_readonly(send_root) && send_root->dedupe_in_progress) {
|
||||
dedupe_in_progress_warn(send_root);
|
||||
spin_unlock(&send_root->root_item_lock);
|
||||
@@ -8207,15 +8215,6 @@ long btrfs_ioctl_send(struct btrfs_inode *inode, const struct btrfs_ioctl_send_a
|
||||
}
|
||||
|
||||
sctx->send_root = send_root;
|
||||
/*
|
||||
* Unlikely but possible, if the subvolume is marked for deletion but
|
||||
* is slow to remove the directory entry, send can still be started
|
||||
*/
|
||||
if (btrfs_root_dead(sctx->send_root)) {
|
||||
ret = -EPERM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
sctx->clone_roots_cnt = arg->clone_sources_count;
|
||||
|
||||
if (sctx->proto >= 2) {
|
||||
|
||||
Reference in New Issue
Block a user