Commit 2936a6ac authored by Qu Wenruo's avatar Qu Wenruo Committed by David Sterba
Browse files

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: default avatarQu Wenruo <wqu@suse.com>
Reviewed-by: default avatarDavid Sterba <dsterba@suse.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent 35ea448b
Loading
Loading
Loading
Loading
+20 −9
Original line number Diff line number Diff line
@@ -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;