btrfs: get rid of re-entering of btrfs_get_tree()

[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>
This commit is contained in:
Qu Wenruo 2025-06-12 15:14:35 +09:30 committed by David Sterba
parent ae818824a2
commit 35ea448b75

View 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 @@ static int btrfs_get_tree_subvol(struct fs_context *fc)
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);
}