On Fri, Sep 29, 2017 at 10:15:30PM +0300, Nikolay Borisov wrote:
> > Adding the transaction before the "if (flags & BTRFS_SUBVOL_RDONLY)"
> > condition makes it much worse. The "is subvolume in send" test is
> > supposed to be lightweight and should not shoot down the whole
> > filesystem. The usecase is explained in 2c68653787f91c62f8.
> > 
> > Also the received_uuid must be changed under the root_item_lock.
> > 
> > I think it should be fine to keep the transaction start where it is,
> > change the received_uuid eventually and let it commit. You can set the
> > transaction units to 2 unconditionally.
> 
> So what you are suggesting is to not move the transaction start before
> the if check? But then how would you structure the code to remove the
> uuid only if we are switchin RO->RW and not in send without duplicating
> the checks right before btrfs_update_root?

--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -1772,6 +1772,7 @@ static noinline int btrfs_ioctl_subvol_setflags(struct 
file *file,
        u64 root_flags;
        u64 flags;
        int ret = 0;
+       bool clear_received_uuid = false;

        if (!inode_owner_or_capable(inode))
                return -EPERM;
@@ -1820,6 +1821,7 @@ static noinline int btrfs_ioctl_subvol_setflags(struct 
file *file,
                        btrfs_set_root_flags(&root->root_item,
                                     root_flags & ~BTRFS_ROOT_SUBVOL_RDONLY);
                        spin_unlock(&root->root_item_lock);
+                       clear_received_uuid = true;
                } else {
                        spin_unlock(&root->root_item_lock);
                        btrfs_warn(fs_info,
@@ -1836,6 +1838,24 @@ static noinline int btrfs_ioctl_subvol_setflags(struct 
file *file,
                goto out_reset;
        }

+       if (clear_received_uuid) {
+               if (!btrfs_is_empty_uuid(root->root_item.received_uuid)) {
+                       ret = btrfs_uuid_tree_rem(trans, fs_info,
+                                       root->root_item.received_uuid,
+                                       BTRFS_UUID_KEY_RECEIVED_SUBVOL,
+                                       root->root_key.objectid);
+
+                       if (ret && ret != -ENOENT) {
+                               btrfs_abort_transaction(trans, ret);
+                               btrfs_end_transaction(trans);
+                               goto out_reset;
+                       }
+
+                       memset(root->root_item.received_uuid, 0,
+                                       BTRFS_UUID_SIZE);
+               }
+       }
+
        ret = btrfs_update_root(trans, fs_info->tree_root,
                                &root->root_key, &root->root_item);


--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to