[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20211026114116.dowt2p3rgukhvrrx@andromeda.lan>
Date: Tue, 26 Oct 2021 13:41:16 +0200
From: Carlos Maiolino <cmaiolino@...hat.com>
To: Lukas Czerner <lczerner@...hat.com>
Cc: linux-ext4@...r.kernel.org, tytso@....edu,
linux-fsdevel@...r.kernel.org
Subject: Re: [PATCH v3 09/13] ext4: Completely separate options parsing and
sb setup
On Thu, Oct 21, 2021 at 01:45:04PM +0200, Lukas Czerner wrote:
> The new mount api separates option parsing and super block setup into
> two distinc steps and so we need to separate the options parsing out of
> the ext4_fill_super() and ext4_remount().
>
> In order to achieve this we have to create new ext4_fill_super() and
> ext4_remount() functions which will serve its purpose only until we
> actually do convert to the new api (as such they are only temporary for
> this patch series) and move the option parsing out of the old function
> which will now be renamed to __ext4_full_super() and __ext4_remount().
__ext4_fill_super() ?
>
> There is a small complication in the fact that while the mount option
> parsing is going to happen before we get to __ext4_fill_super(), the
> mount options stored in the super block itself needs to be applied
> first, before the user specified mount options.
>
> So with this patch we're going through the following sequence:
>
> - parse user provided options (including sb block)
> - initialize sbi and store s_sb_block if provided
> - in __ext4_fill_super()
> - read the super block
> - parse and apply options specified in s_mount_opts
> - check and apply user provided options stored in ctx
> - continue with the regular ext4_fill_super operation
>
> It's not exactly the most elegant solution, but if we still want to
> support s_mount_opts we have to do it in this order.
>
> Signed-off-by: Lukas Czerner <lczerner@...hat.com>
> ---
> fs/ext4/super.c | 399 ++++++++++++++++++++++++++++++++----------------
> 1 file changed, 264 insertions(+), 135 deletions(-)
>
> diff --git a/fs/ext4/super.c b/fs/ext4/super.c
> index 97addca438ad..fd48353e8259 100644
> --- a/fs/ext4/super.c
> +++ b/fs/ext4/super.c
> @@ -1952,29 +1952,6 @@ static const match_table_t tokens = {
> {Opt_err, NULL},
> };
>
> -static ext4_fsblk_t get_sb_block(void **data)
> -{
> - ext4_fsblk_t sb_block;
> - char *options = (char *) *data;
> -
> - if (!options || strncmp(options, "sb=", 3) != 0)
> - return 1; /* Default location */
> -
> - options += 3;
> - /* TODO: use simple_strtoll with >32bit ext4 */
> - sb_block = simple_strtoul(options, &options, 0);
> - if (*options && *options != ',') {
> - printk(KERN_ERR "EXT4-fs: Invalid sb specification: %s\n",
> - (char *) *data);
> - return 1;
> - }
> - if (*options == ',')
> - options++;
> - *data = (void *) options;
> -
> - return sb_block;
> -}
> -
> #define DEFAULT_JOURNAL_IOPRIO (IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 3))
> #define DEFAULT_MB_OPTIMIZE_SCAN (-1)
>
> @@ -2177,6 +2154,7 @@ static int ext4_set_test_dummy_encryption(struct super_block *sb, char *arg)
> #define EXT4_SPEC_s_resgid (1 << 15)
> #define EXT4_SPEC_s_commit_interval (1 << 16)
> #define EXT4_SPEC_s_fc_debug_max_replay (1 << 17)
> +#define EXT4_SPEC_s_sb_block (1 << 18)
>
> struct ext4_fs_context {
> char *s_qf_names[EXT4_MAXQUOTAS];
> @@ -2209,6 +2187,7 @@ struct ext4_fs_context {
> u32 s_min_batch_time;
> kuid_t s_resuid;
> kgid_t s_resgid;
> + ext4_fsblk_t s_sb_block;
> };
>
> #ifdef CONFIG_QUOTA
> @@ -2323,7 +2302,14 @@ static int handle_mount_opt(struct fs_context *fc, struct fs_parameter *param)
> ext4_msg(NULL, KERN_WARNING, deprecated_msg, param->key, "3.5");
> break;
> case Opt_sb:
> - return 1; /* handled by get_sb_block() */
> + if (fc->purpose == FS_CONTEXT_FOR_RECONFIGURE) {
> + ext4_msg(NULL, KERN_WARNING,
> + "Ignoring %s option on remount", param->key);
> + } else {
> + ctx->s_sb_block = result.uint_32;
> + ctx->spec |= EXT4_SPEC_s_sb_block;
> + }
> + return 1;
> case Opt_removed:
> ext4_msg(NULL, KERN_WARNING, "Ignoring removed %s option",
> param->key);
> @@ -2592,24 +2578,14 @@ static int handle_mount_opt(struct fs_context *fc, struct fs_parameter *param)
> return 1;
> }
>
> -static int parse_options(char *options, struct super_block *sb,
> - struct ext4_fs_context *ctx,
> - int is_remount)
> +static int parse_options(struct fs_context *fc, char *options)
> {
> struct fs_parameter param;
> - struct fs_context fc;
> int ret;
> char *key;
>
> if (!options)
> - return 1;
> -
> - memset(&fc, 0, sizeof(fc));
> - fc.fs_private = ctx;
> - fc.s_fs_info = EXT4_SB(sb);
> -
> - if (is_remount)
> - fc.purpose = FS_CONTEXT_FOR_RECONFIGURE;
> + return 0;
>
> while ((key = strsep(&options, ",")) != NULL) {
> if (*key) {
> @@ -2628,34 +2604,83 @@ static int parse_options(char *options, struct super_block *sb,
> param.string = kmemdup_nul(value, v_len,
> GFP_KERNEL);
> if (!param.string)
> - return 0;
> + return -ENOMEM;
> param.type = fs_value_is_string;
> }
>
> param.key = key;
> param.size = v_len;
>
> - ret = handle_mount_opt(&fc, ¶m);
> + ret = handle_mount_opt(fc, ¶m);
> if (param.string)
> kfree(param.string);
> if (ret < 0)
> - return 0;
> + return ret;
> }
> }
>
> - ret = ext4_validate_options(&fc);
> + ret = ext4_validate_options(fc);
> if (ret < 0)
> - return 0;
> + return ret;
>
> - ret = ext4_check_opt_consistency(&fc, sb);
> - if (ret < 0)
> + return 0;
> +}
> +
> +static int parse_apply_sb_mount_options(struct super_block *sb,
> + struct ext4_fs_context *m_ctx)
> +{
> + struct ext4_sb_info *sbi = EXT4_SB(sb);
> + char *s_mount_opts = NULL;
> + struct ext4_fs_context *s_ctx = NULL;
> + struct fs_context *fc = NULL;
> + int ret = -ENOMEM;
> +
> + if (!sbi->s_es->s_mount_opts[0])
> return 0;
>
> - ret = ext4_apply_options(&fc, sb);
> + s_mount_opts = kstrndup(sbi->s_es->s_mount_opts,
> + sizeof(sbi->s_es->s_mount_opts),
> + GFP_KERNEL);
> + if (!s_mount_opts)
> + return ret;
> +
> + fc = kzalloc(sizeof(struct fs_context), GFP_KERNEL);
> + if (!fc)
> + goto out_free;
> +
> + s_ctx = kzalloc(sizeof(struct ext4_fs_context), GFP_KERNEL);
> + if (!s_ctx)
> + goto out_free;
> +
> + fc->fs_private = s_ctx;
> + fc->s_fs_info = sbi;
> +
> + ret = parse_options(fc, s_mount_opts);
> if (ret < 0)
> - return 0;
> + goto parse_failed;
>
> - return 1;
> + ret = ext4_check_opt_consistency(fc, sb);
> + if (ret < 0) {
> +parse_failed:
> + ext4_msg(sb, KERN_WARNING,
> + "failed to parse options in superblock: %s",
> + s_mount_opts);
> + ret = 0;
> + goto out_free;
> + }
> +
> + if (s_ctx->spec & EXT4_SPEC_JOURNAL_DEV)
> + m_ctx->journal_devnum = s_ctx->journal_devnum;
> + if (s_ctx->spec & EXT4_SPEC_JOURNAL_IOPRIO)
> + m_ctx->journal_ioprio = s_ctx->journal_ioprio;
> +
> + ret = ext4_apply_options(fc, sb);
> +
> +out_free:
> + kfree(s_ctx);
> + kfree(fc);
> + kfree(s_mount_opts);
> + return ret;
> }
>
> static void ext4_apply_quota_options(struct fs_context *fc,
> @@ -4350,21 +4375,53 @@ static void ext4_setup_csum_trigger(struct super_block *sb,
> sbi->s_journal_triggers[type].tr_triggers.t_frozen = trigger;
> }
>
> -static int ext4_fill_super(struct super_block *sb, void *data, int silent)
> +static void ext4_free_sbi(struct ext4_sb_info *sbi)
> +{
> + if (!sbi)
> + return;
> +
> + kfree(sbi->s_blockgroup_lock);
> + fs_put_dax(sbi->s_daxdev);
> + kfree(sbi);
> +}
> +
> +static struct ext4_sb_info *ext4_alloc_sbi(struct super_block *sb)
> +{
> + struct ext4_sb_info *sbi;
> +
> + sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
> + if (!sbi)
> + return NULL;
> +
> + sbi->s_daxdev = fs_dax_get_by_bdev(sb->s_bdev);
> +
> + sbi->s_blockgroup_lock =
> + kzalloc(sizeof(struct blockgroup_lock), GFP_KERNEL);
> +
> + if (!sbi->s_blockgroup_lock)
> + goto err_out;
> +
> + sb->s_fs_info = sbi;
> + sbi->s_sb = sb;
> + return sbi;
> +err_out:
> + fs_put_dax(sbi->s_daxdev);
> + kfree(sbi);
> + return NULL;
> +}
> +
> +static int __ext4_fill_super(struct fs_context *fc, struct super_block *sb,
> + int silent)
> {
> - struct dax_device *dax_dev = fs_dax_get_by_bdev(sb->s_bdev);
> - char *orig_data = kstrdup(data, GFP_KERNEL);
> struct buffer_head *bh, **group_desc;
> struct ext4_super_block *es = NULL;
> - struct ext4_sb_info *sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
> + struct ext4_sb_info *sbi = EXT4_SB(sb);
> struct flex_groups **flex_groups;
> ext4_fsblk_t block;
> - ext4_fsblk_t sb_block = get_sb_block(&data);
> ext4_fsblk_t logical_sb_block;
> unsigned long offset = 0;
> unsigned long def_mount_opts;
> struct inode *root;
> - const char *descr;
> int ret = -ENOMEM;
> int blocksize, clustersize;
> unsigned int db_count;
> @@ -4373,32 +4430,16 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
> __u64 blocks_count;
> int err = 0;
> ext4_group_t first_not_zeroed;
> - struct ext4_fs_context parsed_opts = {0};
> + struct ext4_fs_context *ctx = fc->fs_private;
>
> /* Set defaults for the variables that will be set during parsing */
> - parsed_opts.journal_ioprio = DEFAULT_JOURNAL_IOPRIO;
> - parsed_opts.journal_devnum = 0;
> - parsed_opts.mb_optimize_scan = DEFAULT_MB_OPTIMIZE_SCAN;
> -
> - if ((data && !orig_data) || !sbi)
> - goto out_free_base;
> + ctx->journal_ioprio = DEFAULT_JOURNAL_IOPRIO;
> + ctx->mb_optimize_scan = DEFAULT_MB_OPTIMIZE_SCAN;
>
> - sbi->s_daxdev = dax_dev;
> - sbi->s_blockgroup_lock =
> - kzalloc(sizeof(struct blockgroup_lock), GFP_KERNEL);
> - if (!sbi->s_blockgroup_lock)
> - goto out_free_base;
> -
> - sb->s_fs_info = sbi;
> - sbi->s_sb = sb;
> sbi->s_inode_readahead_blks = EXT4_DEF_INODE_READAHEAD_BLKS;
> - sbi->s_sb_block = sb_block;
> sbi->s_sectors_written_start =
> part_stat_read(sb->s_bdev, sectors[STAT_WRITE]);
>
> - /* Cleanup superblock name */
> - strreplace(sb->s_id, '/', '!');
> -
> /* -EINVAL is default */
> ret = -EINVAL;
> blocksize = sb_min_blocksize(sb, EXT4_MIN_BLOCK_SIZE);
> @@ -4412,10 +4453,10 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
> * block sizes. We need to calculate the offset from buffer start.
> */
> if (blocksize != EXT4_MIN_BLOCK_SIZE) {
> - logical_sb_block = sb_block * EXT4_MIN_BLOCK_SIZE;
> + logical_sb_block = sbi->s_sb_block * EXT4_MIN_BLOCK_SIZE;
> offset = do_div(logical_sb_block, blocksize);
> } else {
> - logical_sb_block = sb_block;
> + logical_sb_block = sbi->s_sb_block;
> }
>
> bh = ext4_sb_bread_unmovable(sb, logical_sb_block);
> @@ -4620,21 +4661,18 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
> }
> }
>
> - if (sbi->s_es->s_mount_opts[0]) {
> - char *s_mount_opts = kstrndup(sbi->s_es->s_mount_opts,
> - sizeof(sbi->s_es->s_mount_opts),
> - GFP_KERNEL);
> - if (!s_mount_opts)
> - goto failed_mount;
> - if (!parse_options(s_mount_opts, sb, &parsed_opts, 0)) {
> - ext4_msg(sb, KERN_WARNING,
> - "failed to parse options in superblock: %s",
> - s_mount_opts);
> - }
> - kfree(s_mount_opts);
> - }
> + err = parse_apply_sb_mount_options(sb, ctx);
> + if (err < 0)
> + goto failed_mount;
> +
> sbi->s_def_mount_opt = sbi->s_mount_opt;
> - if (!parse_options((char *) data, sb, &parsed_opts, 0))
> +
> + err = ext4_check_opt_consistency(fc, sb);
> + if (err < 0)
> + goto failed_mount;
> +
> + err = ext4_apply_options(fc, sb);
> + if (err < 0)
> goto failed_mount;
>
> #ifdef CONFIG_UNICODE
> @@ -4773,7 +4811,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
> goto failed_mount;
> }
>
> - if (dax_supported(dax_dev, sb->s_bdev, blocksize, 0,
> + if (dax_supported(sbi->s_daxdev, sb->s_bdev, blocksize, 0,
> bdev_nr_sectors(sb->s_bdev)))
> set_bit(EXT4_FLAGS_BDEV_IS_DAX, &sbi->s_ext4_flags);
>
> @@ -4811,7 +4849,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
> goto failed_mount;
> }
>
> - logical_sb_block = sb_block * EXT4_MIN_BLOCK_SIZE;
> + 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)) {
> @@ -5127,7 +5165,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
> * root first: it may be modified in the journal!
> */
> if (!test_opt(sb, NOLOAD) && ext4_has_feature_journal(sb)) {
> - err = ext4_load_journal(sb, es, parsed_opts.journal_devnum);
> + err = ext4_load_journal(sb, es, ctx->journal_devnum);
> if (err)
> goto failed_mount3a;
> } else if (test_opt(sb, NOLOAD) && !sb_rdonly(sb) &&
> @@ -5227,7 +5265,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
> goto failed_mount_wq;
> }
>
> - set_task_ioprio(sbi->s_journal->j_task, parsed_opts.journal_ioprio);
> + set_task_ioprio(sbi->s_journal->j_task, ctx->journal_ioprio);
>
> sbi->s_journal->j_submit_inode_data_buffers =
> ext4_journal_submit_inode_data_buffers;
> @@ -5339,9 +5377,9 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
> * turned off by passing "mb_optimize_scan=0". This can also be
> * turned on forcefully by passing "mb_optimize_scan=1".
> */
> - if (parsed_opts.mb_optimize_scan == 1)
> + if (ctx->mb_optimize_scan == 1)
> set_opt2(sb, MB_OPTIMIZE_SCAN);
> - else if (parsed_opts.mb_optimize_scan == 0)
> + else if (ctx->mb_optimize_scan == 0)
> clear_opt2(sb, MB_OPTIMIZE_SCAN);
> else if (sbi->s_groups_count >= MB_DEFAULT_LINEAR_SCAN_THRESHOLD)
> set_opt2(sb, MB_OPTIMIZE_SCAN);
> @@ -5443,15 +5481,6 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
> if (err)
> goto failed_mount9;
> }
> - if (EXT4_SB(sb)->s_journal) {
> - if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA)
> - descr = " journalled data mode";
> - else if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA)
> - descr = " ordered data mode";
> - else
> - descr = " writeback data mode";
> - } else
> - descr = "out journal";
>
> if (test_opt(sb, DISCARD)) {
> struct request_queue *q = bdev_get_queue(sb->s_bdev);
> @@ -5461,14 +5490,6 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
> "the device does not support discard");
> }
>
> - if (___ratelimit(&ext4_mount_msg_ratelimit, "EXT4-fs mount"))
> - ext4_msg(sb, KERN_INFO, "mounted filesystem with%s. "
> - "Opts: %.*s%s%s. Quota mode: %s.", descr,
> - (int) sizeof(sbi->s_es->s_mount_opts),
> - sbi->s_es->s_mount_opts,
> - *sbi->s_es->s_mount_opts ? "; " : "", orig_data,
> - ext4_quota_mode(sb));
> -
> if (es->s_error_count)
> mod_timer(&sbi->s_err_report, jiffies + 300*HZ); /* 5 minutes */
>
> @@ -5479,7 +5500,6 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
> atomic_set(&sbi->s_warning_count, 0);
> atomic_set(&sbi->s_msg_count, 0);
>
> - kfree(orig_data);
> return 0;
>
> cantfind_ext4:
> @@ -5565,14 +5585,92 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
> ext4_blkdev_remove(sbi);
> out_fail:
> sb->s_fs_info = NULL;
> - kfree(sbi->s_blockgroup_lock);
> -out_free_base:
> - kfree(sbi);
> - kfree(orig_data);
> - fs_put_dax(dax_dev);
> return err ? err : ret;
> }
>
> +static void cleanup_ctx(struct ext4_fs_context *ctx)
> +{
> + int i;
> +
> + if (!ctx)
> + return;
> +
> + for (i = 0; i < EXT4_MAXQUOTAS; i++) {
> + kfree(ctx->s_qf_names[i]);
> + }
> +
> + kfree(ctx->test_dummy_enc_arg);
> +}
> +
> +static int ext4_fill_super(struct super_block *sb, void *data, int silent)
> +{
> + struct ext4_fs_context ctx;
> + struct ext4_sb_info *sbi;
> + struct fs_context fc;
> + const char *descr;
> + char *orig_data;
> + int ret = -ENOMEM;
> +
> + orig_data = kstrdup(data, GFP_KERNEL);
> + if (data && !orig_data)
> + return -ENOMEM;
> +
> + /* Cleanup superblock name */
> + strreplace(sb->s_id, '/', '!');
> +
> + memset(&fc, 0, sizeof(fc));
> + memset(&ctx, 0, sizeof(ctx));
> + fc.fs_private = &ctx;
> +
> + ret = parse_options(&fc, (char *) data);
> + if (ret < 0)
> + goto free_data;
> +
> + sbi = ext4_alloc_sbi(sb);
> + if (!sbi) {
> + ret = -ENOMEM;
> + goto free_data;
> + }
> +
> + fc.s_fs_info = sbi;
> +
> + sbi->s_sb_block = 1; /* Default super block location */
> + if (ctx.spec & EXT4_SPEC_s_sb_block)
> + sbi->s_sb_block = ctx.s_sb_block;
> +
> + ret = __ext4_fill_super(&fc, sb, silent);
> + if (ret < 0)
> + goto free_sbi;
> +
> + if (EXT4_SB(sb)->s_journal) {
> + if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA)
> + descr = " journalled data mode";
> + else if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA)
> + descr = " ordered data mode";
> + else
> + descr = " writeback data mode";
> + } else
> + descr = "out journal";
> +
> + if (___ratelimit(&ext4_mount_msg_ratelimit, "EXT4-fs mount"))
> + ext4_msg(sb, KERN_INFO, "mounted filesystem with%s. "
> + "Opts: %.*s%s%s. Quota mode: %s.", descr,
> + (int) sizeof(sbi->s_es->s_mount_opts),
> + sbi->s_es->s_mount_opts,
> + *sbi->s_es->s_mount_opts ? "; " : "", orig_data,
> + ext4_quota_mode(sb));
> +
> + kfree(orig_data);
> + cleanup_ctx(&ctx);
> + return 0;
> +free_sbi:
> + ext4_free_sbi(sbi);
> +free_data:
> + kfree(orig_data);
> + cleanup_ctx(&ctx);
> + return ret;
> +}
> +
> /*
> * Setup any per-fs journal parameters now. We'll do this both on
> * initial mount, once the journal has been initialised but before we've
> @@ -6201,8 +6299,10 @@ struct ext4_mount_options {
> #endif
> };
>
> -static int ext4_remount(struct super_block *sb, int *flags, char *data)
> +static int __ext4_remount(struct fs_context *fc, struct super_block *sb,
> + int *flags)
> {
> + struct ext4_fs_context *ctx = fc->fs_private;
> struct ext4_super_block *es;
> struct ext4_sb_info *sbi = EXT4_SB(sb);
> unsigned long old_sb_flags, vfs_flags;
> @@ -6214,14 +6314,8 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
> int i, j;
> char *to_free[EXT4_MAXQUOTAS];
> #endif
> - char *orig_data = kstrdup(data, GFP_KERNEL);
> - struct ext4_fs_context parsed_opts;
> -
> - parsed_opts.journal_ioprio = DEFAULT_JOURNAL_IOPRIO;
> - parsed_opts.journal_devnum = 0;
>
> - if (data && !orig_data)
> - return -ENOMEM;
> + ctx->journal_ioprio = DEFAULT_JOURNAL_IOPRIO;
>
> /* Store the original options */
> old_sb_flags = sb->s_flags;
> @@ -6242,14 +6336,13 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
> if (!old_opts.s_qf_names[i]) {
> for (j = 0; j < i; j++)
> kfree(old_opts.s_qf_names[j]);
> - kfree(orig_data);
> return -ENOMEM;
> }
> } else
> old_opts.s_qf_names[i] = NULL;
> #endif
> if (sbi->s_journal && sbi->s_journal->j_task->io_context)
> - parsed_opts.journal_ioprio =
> + ctx->journal_ioprio =
> sbi->s_journal->j_task->io_context->ioprio;
>
> /*
> @@ -6260,10 +6353,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
> vfs_flags = SB_LAZYTIME | SB_I_VERSION;
> sb->s_flags = (sb->s_flags & ~vfs_flags) | (*flags & vfs_flags);
>
> - if (!parse_options(data, sb, &parsed_opts, 1)) {
> - err = -EINVAL;
> - goto restore_opts;
> - }
> + ext4_apply_options(fc, sb);
>
> if ((old_opts.s_mount_opt & EXT4_MOUNT_JOURNAL_CHECKSUM) ^
> test_opt(sb, JOURNAL_CHECKSUM)) {
> @@ -6310,7 +6400,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
>
> if (sbi->s_journal) {
> ext4_init_journal_params(sb, sbi->s_journal);
> - set_task_ioprio(sbi->s_journal->j_task, parsed_opts.journal_ioprio);
> + set_task_ioprio(sbi->s_journal->j_task, ctx->journal_ioprio);
> }
>
> /* Flush outstanding errors before changing fs state */
> @@ -6475,9 +6565,6 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
> */
> *flags = (*flags & ~vfs_flags) | (sb->s_flags & vfs_flags);
>
> - ext4_msg(sb, KERN_INFO, "re-mounted. Opts: %s. Quota mode: %s.",
> - orig_data, ext4_quota_mode(sb));
> - kfree(orig_data);
> return 0;
>
> restore_opts:
> @@ -6503,10 +6590,52 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
> #endif
> if (!ext4_has_feature_mmp(sb) || sb_rdonly(sb))
> ext4_stop_mmpd(sbi);
> - kfree(orig_data);
> return err;
> }
>
> +static int ext4_remount(struct super_block *sb, int *flags, char *data)
> +{
> + struct ext4_sb_info *sbi = EXT4_SB(sb);
> + struct ext4_fs_context ctx;
> + struct fs_context fc;
> + char *orig_data;
> + int ret;
> +
> + orig_data = kstrdup(data, GFP_KERNEL);
> + if (data && !orig_data)
> + return -ENOMEM;
> +
> + memset(&fc, 0, sizeof(fc));
> + memset(&ctx, 0, sizeof(ctx));
> +
> + fc.fs_private = &ctx;
> + fc.purpose = FS_CONTEXT_FOR_RECONFIGURE;
> + fc.s_fs_info = sbi;
> +
> + ret = parse_options(&fc, (char *) data);
> + if (ret < 0)
> + goto err_out;
> +
> + ret = ext4_check_opt_consistency(&fc, sb);
> + if (ret < 0)
> + goto err_out;
> +
> + ret = __ext4_remount(&fc, sb, flags);
> + if (ret < 0)
> + goto err_out;
> +
> + ext4_msg(sb, KERN_INFO, "re-mounted. Opts: %s. Quota mode: %s.",
> + orig_data, ext4_quota_mode(sb));
> + cleanup_ctx(&ctx);
> + kfree(orig_data);
> + return 0;
> +
> +err_out:
> + cleanup_ctx(&ctx);
> + kfree(orig_data);
> + return ret;
> +}
> +
> #ifdef CONFIG_QUOTA
> static int ext4_statfs_project(struct super_block *sb,
> kprojid_t projid, struct kstatfs *buf)
> --
> 2.31.1
>
--
Carlos
Powered by blists - more mailing lists