Commit a7a79c29 authored by Jason Yan's avatar Jason Yan Committed by Theodore Ts'o
Browse files

ext4: unify the ext4 super block loading operation



Now we load the super block from the disk in two steps. First we load
the super block with the default block size(EXT4_MIN_BLOCK_SIZE). Second
we load the super block with the real block size. The second step is a
little far from the first step. This patch move these two steps together
in a new function.

Signed-off-by: default avatarJason Yan <yanaijie@huawei.com>
Reviewed-by: default avatarJan Kara <jack@suse.cz>
Link: https://lore.kernel.org/r/20220916141527.1012715-15-yanaijie@huawei.com


Signed-off-by: default avatarTheodore Ts'o <tytso@mit.edu>
parent a5991e53
Loading
Loading
Loading
Loading
+106 −80
Original line number Diff line number Diff line
@@ -4920,39 +4920,21 @@ static int ext4_journal_data_mode_check(struct super_block *sb)
	return 0;
}

static int __ext4_fill_super(struct fs_context *fc, struct super_block *sb)
static int ext4_load_super(struct super_block *sb, ext4_fsblk_t *lsb,
			   int silent)
{
	struct buffer_head *bh;
	struct ext4_super_block *es = NULL;
	struct ext4_sb_info *sbi = EXT4_SB(sb);
	struct flex_groups **flex_groups;
	ext4_fsblk_t block;
	struct ext4_super_block *es;
	ext4_fsblk_t logical_sb_block;
	unsigned long offset = 0;
	struct inode *root;
	int ret = -ENOMEM;
	struct buffer_head *bh;
	int ret = -EINVAL;
	int blocksize;
	unsigned int i;
	int needs_recovery, has_huge_files;
	int err = 0;
	ext4_group_t first_not_zeroed;
	struct ext4_fs_context *ctx = fc->fs_private;
	int silent = fc->sb_flags & SB_SILENT;

	/* Set defaults for the variables that will be set during parsing */
	if (!(ctx->spec & EXT4_SPEC_JOURNAL_IOPRIO))
		ctx->journal_ioprio = DEFAULT_JOURNAL_IOPRIO;

	sbi->s_inode_readahead_blks = EXT4_DEF_INODE_READAHEAD_BLKS;
	sbi->s_sectors_written_start =
		part_stat_read(sb->s_bdev, sectors[STAT_WRITE]);

	/* -EINVAL is default */
	ret = -EINVAL;
	blocksize = sb_min_blocksize(sb, EXT4_MIN_BLOCK_SIZE);
	if (!blocksize) {
		ext4_msg(sb, KERN_ERR, "unable to set blocksize");
		goto out_fail;
		return -EINVAL;
	}

	/*
@@ -4969,8 +4951,7 @@ static int __ext4_fill_super(struct fs_context *fc, struct super_block *sb)
	bh = ext4_sb_bread_unmovable(sb, logical_sb_block);
	if (IS_ERR(bh)) {
		ext4_msg(sb, KERN_ERR, "unable to read superblock");
		ret = PTR_ERR(bh);
		goto out_fail;
		return PTR_ERR(bh);
	}
	/*
	 * Note: s_es must be initialized as soon as possible because
@@ -4982,9 +4963,106 @@ static int __ext4_fill_super(struct fs_context *fc, struct super_block *sb)
	if (sb->s_magic != EXT4_SUPER_MAGIC) {
		if (!silent)
			ext4_msg(sb, KERN_ERR, "VFS: Can't find ext4 filesystem");
		goto failed_mount;
		goto out;
	}

	if (le32_to_cpu(es->s_log_block_size) >
	    (EXT4_MAX_BLOCK_LOG_SIZE - EXT4_MIN_BLOCK_LOG_SIZE)) {
		ext4_msg(sb, KERN_ERR,
			 "Invalid log block size: %u",
			 le32_to_cpu(es->s_log_block_size));
		goto out;
	}
	if (le32_to_cpu(es->s_log_cluster_size) >
	    (EXT4_MAX_CLUSTER_LOG_SIZE - EXT4_MIN_BLOCK_LOG_SIZE)) {
		ext4_msg(sb, KERN_ERR,
			 "Invalid log cluster size: %u",
			 le32_to_cpu(es->s_log_cluster_size));
		goto out;
	}

	blocksize = EXT4_MIN_BLOCK_SIZE << le32_to_cpu(es->s_log_block_size);

	/*
	 * If the default block size is not the same as the real block size,
	 * we need to reload it.
	 */
	if (sb->s_blocksize == blocksize) {
		*lsb = logical_sb_block;
		sbi->s_sbh = bh;
		return 0;
	}

	/*
	 * bh must be released before kill_bdev(), otherwise
	 * it won't be freed and its page also. kill_bdev()
	 * is called by sb_set_blocksize().
	 */
	brelse(bh);
	/* Validate the filesystem blocksize */
	if (!sb_set_blocksize(sb, blocksize)) {
		ext4_msg(sb, KERN_ERR, "bad block size %d",
				blocksize);
		bh = NULL;
		goto out;
	}

	logical_sb_block = sbi->s_sb_block * EXT4_MIN_BLOCK_SIZE;
	offset = do_div(logical_sb_block, blocksize);
	bh = ext4_sb_bread_unmovable(sb, logical_sb_block);
	if (IS_ERR(bh)) {
		ext4_msg(sb, KERN_ERR, "Can't read superblock on 2nd try");
		ret = PTR_ERR(bh);
		bh = NULL;
		goto out;
	}
	es = (struct ext4_super_block *)(bh->b_data + offset);
	sbi->s_es = es;
	if (es->s_magic != cpu_to_le16(EXT4_SUPER_MAGIC)) {
		ext4_msg(sb, KERN_ERR, "Magic mismatch, very weird!");
		goto out;
	}
	*lsb = logical_sb_block;
	sbi->s_sbh = bh;
	return 0;
out:
	brelse(bh);
	return ret;
}

static int __ext4_fill_super(struct fs_context *fc, struct super_block *sb)
{
	struct ext4_super_block *es = NULL;
	struct ext4_sb_info *sbi = EXT4_SB(sb);
	struct flex_groups **flex_groups;
	ext4_fsblk_t block;
	ext4_fsblk_t logical_sb_block;
	struct inode *root;
	int ret = -ENOMEM;
	int blocksize;
	unsigned int i;
	int needs_recovery, has_huge_files;
	int err = 0;
	ext4_group_t first_not_zeroed;
	struct ext4_fs_context *ctx = fc->fs_private;
	int silent = fc->sb_flags & SB_SILENT;

	/* Set defaults for the variables that will be set during parsing */
	if (!(ctx->spec & EXT4_SPEC_JOURNAL_IOPRIO))
		ctx->journal_ioprio = DEFAULT_JOURNAL_IOPRIO;

	sbi->s_inode_readahead_blks = EXT4_DEF_INODE_READAHEAD_BLKS;
	sbi->s_sectors_written_start =
		part_stat_read(sb->s_bdev, sectors[STAT_WRITE]);

	/* -EINVAL is default */
	ret = -EINVAL;
	err = ext4_load_super(sb, &logical_sb_block, silent);
	if (err)
		goto out_fail;

	es = sbi->s_es;
	blocksize = sb->s_blocksize;
	sbi->s_kbytes_written = le64_to_cpu(es->s_kbytes_written);

	err = ext4_init_metadata_csum(sb, es);
@@ -5005,23 +5083,6 @@ static int __ext4_fill_super(struct fs_context *fc, struct super_block *sb)
	 */
	sbi->s_li_wait_mult = EXT4_DEF_LI_WAIT_MULT;

	if (le32_to_cpu(es->s_log_block_size) >
	    (EXT4_MAX_BLOCK_LOG_SIZE - EXT4_MIN_BLOCK_LOG_SIZE)) {
		ext4_msg(sb, KERN_ERR,
			 "Invalid log block size: %u",
			 le32_to_cpu(es->s_log_block_size));
		goto failed_mount;
	}
	if (le32_to_cpu(es->s_log_cluster_size) >
	    (EXT4_MAX_CLUSTER_LOG_SIZE - EXT4_MIN_BLOCK_LOG_SIZE)) {
		ext4_msg(sb, KERN_ERR,
			 "Invalid log cluster size: %u",
			 le32_to_cpu(es->s_log_cluster_size));
		goto failed_mount;
	}

	blocksize = EXT4_MIN_BLOCK_SIZE << le32_to_cpu(es->s_log_block_size);

	if (blocksize == PAGE_SIZE)
		set_opt(sb, DIOREAD_NOLOCK);

@@ -5088,40 +5149,6 @@ static int __ext4_fill_super(struct fs_context *fc, struct super_block *sb)
		goto failed_mount;
	}

	if (sb->s_blocksize != blocksize) {
		/*
		 * bh must be released before kill_bdev(), otherwise
		 * it won't be freed and its page also. kill_bdev()
		 * is called by sb_set_blocksize().
		 */
		brelse(bh);
		/* Validate the filesystem blocksize */
		if (!sb_set_blocksize(sb, blocksize)) {
			ext4_msg(sb, KERN_ERR, "bad block size %d",
					blocksize);
			bh = NULL;
			goto failed_mount;
		}

		logical_sb_block = sbi->s_sb_block * EXT4_MIN_BLOCK_SIZE;
		offset = do_div(logical_sb_block, blocksize);
		bh = ext4_sb_bread_unmovable(sb, logical_sb_block);
		if (IS_ERR(bh)) {
			ext4_msg(sb, KERN_ERR,
			       "Can't read superblock on 2nd try");
			ret = PTR_ERR(bh);
			bh = NULL;
			goto failed_mount;
		}
		es = (struct ext4_super_block *)(bh->b_data + offset);
		sbi->s_es = es;
		if (es->s_magic != cpu_to_le16(EXT4_SUPER_MAGIC)) {
			ext4_msg(sb, KERN_ERR,
			       "Magic mismatch, very weird!");
			goto failed_mount;
		}
	}

	has_huge_files = ext4_has_feature_huge_file(sb);
	sbi->s_bitmap_maxbytes = ext4_max_bitmap_size(sb->s_blocksize_bits,
						      has_huge_files);
@@ -5158,7 +5185,6 @@ static int __ext4_fill_super(struct fs_context *fc, struct super_block *sb)
	sbi->s_itb_per_group = sbi->s_inodes_per_group /
					sbi->s_inodes_per_block;
	sbi->s_desc_per_block = blocksize / EXT4_DESC_SIZE(sb);
	sbi->s_sbh = bh;
	sbi->s_mount_state = le16_to_cpu(es->s_state) & ~EXT4_FC_REPLAY;
	sbi->s_addr_per_block_bits = ilog2(EXT4_ADDR_PER_BLOCK(sb));
	sbi->s_desc_per_block_bits = ilog2(EXT4_DESC_PER_BLOCK(sb));
@@ -5595,7 +5621,7 @@ static int __ext4_fill_super(struct fs_context *fc, struct super_block *sb)
#endif
	fscrypt_free_dummy_policy(&sbi->s_dummy_enc_policy);
	/* ext4_blkdev_remove() calls kill_bdev(), release bh before it. */
	brelse(bh);
	brelse(sbi->s_sbh);
	ext4_blkdev_remove(sbi);
out_fail:
	sb->s_fs_info = NULL;