]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
btrfs: get rid of re-entering of btrfs_get_tree()
authorQu Wenruo <wqu@suse.com>
Thu, 12 Jun 2025 05:44:35 +0000 (15:14 +0930)
committerDavid Sterba <dsterba@suse.com>
Mon, 21 Jul 2025 22:06:19 +0000 (00:06 +0200)
[EXISTING PROBLEM]
Currently btrfs mount is split into two parts:

- btrfs_get_tree_subvol()
  Which sets up the very basic fs_info, and eventually calls
  mount_subvol() to mount the target subvolume.

- btrfs_get_tree_super()
  This is the part doing super block allocation and if there is no
  existing super block, do the real open_ctree() to open the fs.

However currently we're doing this in a complex re-entering way:

vfs_get_tree()
|- btrfs_get_tree()
   |- btrfs_get_tree_subvol()
      |- vfs_get_tree()
      |  |- btrfs_get_tree()
      |     |- btrfs_get_tree_super()
      |- mount_subvol()

This is definitely not that easy to grasp.

[ENHANCEMENT]
The function vfs_get_tree() is only doing the following work:

- Call get_tree() call back
- Call super_wake()
- Call security_sb_set_mnt_opts()

In our case, super_wake() can be skipped, as after
btrfs_get_tree_subvol() finishes, vfs_get_tree() will call super_wake()
on the super block we got anyway.

The same applies to security_sb_set_mnt_opts(), as long as we do not
free the security from our original fc in btrfs_get_tree_subvol(), the
first vfs_get_tree() call will handle the security correctly.

So here we only need to:

- Replace vfs_get_tree() call with btrfs_get_tree_super()

- Keep the existing fc->security for vfs_get_tree() to handle the
  security

This will remove the re-entering behavior and make thing much easier to
follow.

Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/super.c

index b9e08a59da4e334a8e473eeb96826f3926a31fd4..d977d2da985ee479a1f979208372b6101d912e2c 100644 (file)
@@ -2046,15 +2046,7 @@ static int btrfs_get_tree_subvol(struct fs_context *fc)
         */
        dup_fc->s_fs_info = fs_info;
 
-       /*
-        * We'll do the security settings in our btrfs_get_tree_super() mount
-        * loop, they were duplicated into dup_fc, we can drop the originals
-        * here.
-        */
-       security_free_mnt_opts(&fc->security);
-       fc->security = NULL;
-
-       ret = vfs_get_tree(dup_fc);
+       ret = btrfs_get_tree_super(dup_fc);
        if (ret)
                goto error;
 
@@ -2086,21 +2078,8 @@ error:
 
 static int btrfs_get_tree(struct fs_context *fc)
 {
-       /*
-        * Since we use mount_subtree to mount the default/specified subvol, we
-        * have to do mounts in two steps.
-        *
-        * First pass through we call btrfs_get_tree_subvol(), this is just a
-        * wrapper around fc_mount() to call back into here again, and this time
-        * we'll call btrfs_get_tree_super().  This will do the open_ctree() and
-        * everything to open the devices and file system.  Then we return back
-        * with a fully constructed vfsmount in btrfs_get_tree_subvol(), and
-        * from there we can do our mount_subvol() call, which will lookup
-        * whichever subvol we're mounting and setup this fc with the
-        * appropriate dentry for the subvol.
-        */
-       if (fc->s_fs_info)
-               return btrfs_get_tree_super(fc);
+       ASSERT(fc->s_fs_info == NULL);
+
        return btrfs_get_tree_subvol(fc);
 }