diff options
author | Filipe Manana <fdmanana@suse.com> | 2024-11-06 11:32:09 +0100 |
---|---|---|
committer | David Sterba <dsterba@suse.com> | 2024-11-11 14:34:23 +0100 |
commit | dc058f5fda091abcdccc2487b48dbbc1cdde98d0 (patch) | |
tree | 133812c25ea6567ad00d17d9c26b0a02b698e1f6 /fs/btrfs | |
parent | btrfs: remove check for NULL fs_info at btrfs_folio_end_lock_bitmap() (diff) | |
download | linux-dc058f5fda091abcdccc2487b48dbbc1cdde98d0.tar.xz linux-dc058f5fda091abcdccc2487b48dbbc1cdde98d0.zip |
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>
Diffstat (limited to 'fs/btrfs')
-rw-r--r-- | fs/btrfs/send.c | 17 |
1 files changed, 8 insertions, 9 deletions
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index cadb945bb345..3fcc8113641d 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -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) { |