btrfs: add assertions to make super block creation more clear

When calling sget_fc(), there are 3 different situations:

a) Critical error
   No super block created.

b) A new super block is created
   The fc->s_fs_info is transferred to the super block, and fc->s_fs_info
   is reset to NULL.

   In this case sb->s_root should still be NULL, and needs to be properly
   initialized later by btrfs_fill_super().

c) An existing super block is returned
   The fc->s_fs_info is untouched, and anything related to that fs_info
   should be properly cleaned up.

This is not obvious even with the extra comments at sget_fc().

Enhance the situation by:

- Add comments for case b) and c)
  Especially for case c), the fs_info and fs_devices cleanup happens at
  different timing, thus needs extra explanation.

- Move the comments closer to case b) and case c)

Signed-off-by: Qu Wenruo <wqu@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
Qu Wenruo 2025-06-16 08:14:25 +09:30 committed by David Sterba
parent 35ea448b75
commit 2936a6ac8d

View File

@ -1876,15 +1876,6 @@ static int btrfs_get_tree_super(struct fs_context *fc)
bdev = fs_devices->latest_dev->bdev;
/*
* From now on the error handling is not straightforward.
*
* If successful, this will transfer the fs_info into the super block,
* and fc->s_fs_info will be NULL. However if there's an existing
* super, we'll still have fc->s_fs_info populated. If we error
* completely out it'll be cleaned up when we drop the fs_context,
* otherwise it's tied to the lifetime of the super_block.
*/
sb = sget_fc(fc, btrfs_fc_test_super, set_anon_super_fc);
if (IS_ERR(sb)) {
ret = PTR_ERR(sb);
@ -1894,6 +1885,19 @@ static int btrfs_get_tree_super(struct fs_context *fc)
set_device_specific_options(fs_info);
if (sb->s_root) {
/*
* Not the first mount of the fs thus got an existing super block.
* Will reuse the returned super block, fs_info and fs_devices.
*/
ASSERT(fc->s_fs_info == fs_info);
/*
* fc->s_fs_info is not touched and will be later freed by
* put_fs_context() through btrfs_free_fs_context().
*
* But we have opened fs_devices at the beginning of the
* function, thus still need to close them manually.
*/
btrfs_close_devices(fs_devices);
/*
* At this stage we may have RO flag mismatch between
@ -1902,6 +1906,13 @@ static int btrfs_get_tree_super(struct fs_context *fc)
* needed.
*/
} else {
/*
* The first mount of the fs thus a new superblock, fc->s_fs_info
* must be NULL, and the ownership of our fs_info and fs_devices is
* transferred to the super block.
*/
ASSERT(fc->s_fs_info == NULL);
snprintf(sb->s_id, sizeof(sb->s_id), "%pg", bdev);
shrinker_debugfs_rename(sb->s_shrink, "sb-btrfs:%s", sb->s_id);
btrfs_sb(sb)->bdev_holder = &btrfs_fs_type;