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

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.comSigned-off-by: default avatarTheodore Ts'o <tytso@mit.edu>
parent a5991e53
......@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment