]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
btrfs: send: check for read-only send root under critical section
authorFilipe Manana <fdmanana@suse.com>
Wed, 6 Nov 2024 11:26:07 +0000 (11:26 +0000)
committerDavid Sterba <dsterba@suse.com>
Mon, 11 Nov 2024 13:34:23 +0000 (14:34 +0100)
We're checking if the send root is read-only without being under the
protection of the root's root_item_lock spinlock, which is what protects
the root's flags when clearing the read-only flag, done at
btrfs_ioctl_subvol_setflags(). Furthermore, it should be done in the
same critical section that increments the root's send_in_progress counter,
as btrfs_ioctl_subvol_setflags() clears the read-only flag in the same
critical section that checks the counter's value.

So fix this by moving the read-only check under the critical section
delimited by the root's root_item_lock which also increments the root's
send_in_progress counter.

Signed-off-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/send.c

index 3fcc8113641dd4309a0aa20353ea1071ccf007eb..7254279c3cc92c76cd3ebceabe9455ca38c67163 100644 (file)
@@ -8133,7 +8133,12 @@ long btrfs_ioctl_send(struct btrfs_inode *inode, const struct btrfs_ioctl_send_a
                spin_unlock(&send_root->root_item_lock);
                return -EPERM;
        }
-       if (btrfs_root_readonly(send_root) && send_root->dedupe_in_progress) {
+       /* Userspace tools do the checks and warn the user if it's not RO. */
+       if (!btrfs_root_readonly(send_root)) {
+               spin_unlock(&send_root->root_item_lock);
+               return -EPERM;
+       }
+       if (send_root->dedupe_in_progress) {
                dedupe_in_progress_warn(send_root);
                spin_unlock(&send_root->root_item_lock);
                return -EAGAIN;
@@ -8141,15 +8146,6 @@ long btrfs_ioctl_send(struct btrfs_inode *inode, const struct btrfs_ioctl_send_a
        send_root->send_in_progress++;
        spin_unlock(&send_root->root_item_lock);
 
-       /*
-        * Userspace tools do the checks and warn the user if it's
-        * not RO.
-        */
-       if (!btrfs_root_readonly(send_root)) {
-               ret = -EPERM;
-               goto out;
-       }
-
        /*
         * Check that we don't overflow at later allocations, we request
         * clone_sources_count + 1 items, and compare to unsigned long inside