Skip to content

Commit

Permalink
btrfs: send: check for dead send root under critical section
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Filipe Manana authored and David Sterba committed Nov 11, 2024
1 parent 722d343 commit dc058f5
Showing 1 changed file with 8 additions and 9 deletions.
17 changes: 8 additions & 9 deletions fs/btrfs/send.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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) {
Expand Down

0 comments on commit dc058f5

Please sign in to comment.