linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Chao Yu <chao@kernel.org>
To: Eric Sandeen <sandeen@redhat.com>,
	linux-f2fs-devel@lists.sourceforge.net
Cc: chao@kernel.org, linux-fsdevel@vger.kernel.org,
	jaegeuk@kernel.org, lihongbo22@huawei.com
Subject: Re: [PATCH 2/7] f2fs: move the option parser into handle_mount_opt
Date: Wed, 7 May 2025 19:26:31 +0800	[thread overview]
Message-ID: <2e354373-9f00-4499-8812-bcb7f00a6dbc@kernel.org> (raw)
In-Reply-To: <20250420154647.1233033-3-sandeen@redhat.com>

On 4/20/25 23:25, Eric Sandeen wrote:
> From: Hongbo Li <lihongbo22@huawei.com>
> 
> In handle_mount_opt, we use fs_parameter to parse each option.
> However we're still using the old API to get the options string.
> Using fsparams parse_options allows us to remove many of the Opt_
> enums, so remove them.
> 
> The checkpoint disable cap (or percent) involves rather complex
> parsing; we retain the old match_table mechanism for this, which
> handles it well.
> 
> There are some changes about parsing options:
>   1. For `active_logs`, `inline_xattr_size` and `fault_injection`,
>      we use s32 type according the internal structure to record the
>      option's value.

We'd better to use u32 type for these options, as they should never
be negative.

Can you please update based on below patch?

https://lore.kernel.org/linux-f2fs-devel/20250507112425.939246-1-chao@kernel.org

Thanks,

> 
> Signed-off-by: Hongbo Li <lihongbo22@huawei.com>
> [sandeen: forward port, minor fixes and updates]
> Signed-off-by: Eric Sandeen <sandeen@redhat.com>
> ---
>  fs/f2fs/super.c | 1063 ++++++++++++++++++-----------------------------
>  1 file changed, 407 insertions(+), 656 deletions(-)
> 
> diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
> index c3623e052cde..8343dc2a515d 100644
> --- a/fs/f2fs/super.c
> +++ b/fs/f2fs/super.c
> @@ -27,6 +27,7 @@
>  #include <linux/part_stat.h>
>  #include <linux/zstd.h>
>  #include <linux/lz4.h>
> +#include <linux/ctype.h>
>  #include <linux/fs_parser.h>
>  
>  #include "f2fs.h"
> @@ -122,29 +123,20 @@ enum {
>  	Opt_disable_roll_forward,
>  	Opt_norecovery,
>  	Opt_discard,
> -	Opt_nodiscard,
>  	Opt_noheap,
>  	Opt_heap,
>  	Opt_user_xattr,
> -	Opt_nouser_xattr,
>  	Opt_acl,
> -	Opt_noacl,
>  	Opt_active_logs,
>  	Opt_disable_ext_identify,
>  	Opt_inline_xattr,
> -	Opt_noinline_xattr,
>  	Opt_inline_xattr_size,
>  	Opt_inline_data,
>  	Opt_inline_dentry,
> -	Opt_noinline_dentry,
>  	Opt_flush_merge,
> -	Opt_noflush_merge,
>  	Opt_barrier,
> -	Opt_nobarrier,
>  	Opt_fastboot,
>  	Opt_extent_cache,
> -	Opt_noextent_cache,
> -	Opt_noinline_data,
>  	Opt_data_flush,
>  	Opt_reserve_root,
>  	Opt_resgid,
> @@ -153,21 +145,13 @@ enum {
>  	Opt_fault_injection,
>  	Opt_fault_type,
>  	Opt_lazytime,
> -	Opt_nolazytime,
>  	Opt_quota,
> -	Opt_noquota,
>  	Opt_usrquota,
>  	Opt_grpquota,
>  	Opt_prjquota,
>  	Opt_usrjquota,
>  	Opt_grpjquota,
>  	Opt_prjjquota,
> -	Opt_offusrjquota,
> -	Opt_offgrpjquota,
> -	Opt_offprjjquota,
> -	Opt_jqfmt_vfsold,
> -	Opt_jqfmt_vfsv0,
> -	Opt_jqfmt_vfsv1,
>  	Opt_alloc,
>  	Opt_fsync,
>  	Opt_test_dummy_encryption,
> @@ -177,17 +161,15 @@ enum {
>  	Opt_checkpoint_disable_cap_perc,
>  	Opt_checkpoint_enable,
>  	Opt_checkpoint_merge,
> -	Opt_nocheckpoint_merge,
>  	Opt_compress_algorithm,
>  	Opt_compress_log_size,
> -	Opt_compress_extension,
>  	Opt_nocompress_extension,
> +	Opt_compress_extension,
>  	Opt_compress_chksum,
>  	Opt_compress_mode,
>  	Opt_compress_cache,
>  	Opt_atgc,
>  	Opt_gc_merge,
> -	Opt_nogc_merge,
>  	Opt_discard_unit,
>  	Opt_memory_mode,
>  	Opt_age_extent_cache,
> @@ -317,83 +299,12 @@ static const struct fs_parameter_spec f2fs_param_specs[] = {
>  	{}
>  };
>  
> -static match_table_t f2fs_tokens = {
> -	{Opt_gc_background, "background_gc=%s"},
> -	{Opt_disable_roll_forward, "disable_roll_forward"},
> -	{Opt_norecovery, "norecovery"},
> -	{Opt_discard, "discard"},
> -	{Opt_nodiscard, "nodiscard"},
> -	{Opt_noheap, "no_heap"},
> -	{Opt_heap, "heap"},
> -	{Opt_user_xattr, "user_xattr"},
> -	{Opt_nouser_xattr, "nouser_xattr"},
> -	{Opt_acl, "acl"},
> -	{Opt_noacl, "noacl"},
> -	{Opt_active_logs, "active_logs=%u"},
> -	{Opt_disable_ext_identify, "disable_ext_identify"},
> -	{Opt_inline_xattr, "inline_xattr"},
> -	{Opt_noinline_xattr, "noinline_xattr"},
> -	{Opt_inline_xattr_size, "inline_xattr_size=%u"},
> -	{Opt_inline_data, "inline_data"},
> -	{Opt_inline_dentry, "inline_dentry"},
> -	{Opt_noinline_dentry, "noinline_dentry"},
> -	{Opt_flush_merge, "flush_merge"},
> -	{Opt_noflush_merge, "noflush_merge"},
> -	{Opt_barrier, "barrier"},
> -	{Opt_nobarrier, "nobarrier"},
> -	{Opt_fastboot, "fastboot"},
> -	{Opt_extent_cache, "extent_cache"},
> -	{Opt_noextent_cache, "noextent_cache"},
> -	{Opt_noinline_data, "noinline_data"},
> -	{Opt_data_flush, "data_flush"},
> -	{Opt_reserve_root, "reserve_root=%u"},
> -	{Opt_resgid, "resgid=%u"},
> -	{Opt_resuid, "resuid=%u"},
> -	{Opt_mode, "mode=%s"},
> -	{Opt_fault_injection, "fault_injection=%u"},
> -	{Opt_fault_type, "fault_type=%u"},
> -	{Opt_lazytime, "lazytime"},
> -	{Opt_nolazytime, "nolazytime"},
> -	{Opt_quota, "quota"},
> -	{Opt_noquota, "noquota"},
> -	{Opt_usrquota, "usrquota"},
> -	{Opt_grpquota, "grpquota"},
> -	{Opt_prjquota, "prjquota"},
> -	{Opt_usrjquota, "usrjquota=%s"},
> -	{Opt_grpjquota, "grpjquota=%s"},
> -	{Opt_prjjquota, "prjjquota=%s"},
> -	{Opt_offusrjquota, "usrjquota="},
> -	{Opt_offgrpjquota, "grpjquota="},
> -	{Opt_offprjjquota, "prjjquota="},
> -	{Opt_jqfmt_vfsold, "jqfmt=vfsold"},
> -	{Opt_jqfmt_vfsv0, "jqfmt=vfsv0"},
> -	{Opt_jqfmt_vfsv1, "jqfmt=vfsv1"},
> -	{Opt_alloc, "alloc_mode=%s"},
> -	{Opt_fsync, "fsync_mode=%s"},
> -	{Opt_test_dummy_encryption, "test_dummy_encryption=%s"},
> -	{Opt_test_dummy_encryption, "test_dummy_encryption"},
> -	{Opt_inlinecrypt, "inlinecrypt"},
> -	{Opt_checkpoint_disable, "checkpoint=disable"},
> -	{Opt_checkpoint_disable_cap, "checkpoint=disable:%u"},
> -	{Opt_checkpoint_disable_cap_perc, "checkpoint=disable:%u%%"},
> -	{Opt_checkpoint_enable, "checkpoint=enable"},
> -	{Opt_checkpoint_merge, "checkpoint_merge"},
> -	{Opt_nocheckpoint_merge, "nocheckpoint_merge"},
> -	{Opt_compress_algorithm, "compress_algorithm=%s"},
> -	{Opt_compress_log_size, "compress_log_size=%u"},
> -	{Opt_compress_extension, "compress_extension=%s"},
> -	{Opt_nocompress_extension, "nocompress_extension=%s"},
> -	{Opt_compress_chksum, "compress_chksum"},
> -	{Opt_compress_mode, "compress_mode=%s"},
> -	{Opt_compress_cache, "compress_cache"},
> -	{Opt_atgc, "atgc"},
> -	{Opt_gc_merge, "gc_merge"},
> -	{Opt_nogc_merge, "nogc_merge"},
> -	{Opt_discard_unit, "discard_unit=%s"},
> -	{Opt_memory_mode, "memory=%s"},
> -	{Opt_age_extent_cache, "age_extent_cache"},
> -	{Opt_errors, "errors=%s"},
> -	{Opt_nat_bits, "nat_bits"},
> +/* Resort to a match_table for this interestingly formatted option */
> +static match_table_t f2fs_checkpoint_tokens = {
> +	{Opt_checkpoint_disable, "disable"},
> +	{Opt_checkpoint_disable_cap, "disable:%u"},
> +	{Opt_checkpoint_disable_cap_perc, "disable:%u%%"},
> +	{Opt_checkpoint_enable, "enable"},
>  	{Opt_err, NULL},
>  };
>  
> @@ -509,7 +420,7 @@ static void init_once(void *foo)
>  static const char * const quotatypes[] = INITQFNAMES;
>  #define QTYPE2NAME(t) (quotatypes[t])
>  static int f2fs_set_qf_name(struct f2fs_sb_info *sbi, int qtype,
> -							substring_t *args)
> +			    struct fs_parameter *param)
>  {
>  	struct super_block *sb = sbi->sb;
>  	char *qname;
> @@ -524,7 +435,7 @@ static int f2fs_set_qf_name(struct f2fs_sb_info *sbi, int qtype,
>  		return 0;
>  	}
>  
> -	qname = match_strdup(args);
> +	qname = kmemdup_nul(param->string, param->size, GFP_KERNEL);
>  	if (!qname) {
>  		f2fs_err(sbi, "Not enough memory for storing quotafile name");
>  		return -ENOMEM;
> @@ -609,14 +520,9 @@ static int f2fs_check_quota_options(struct f2fs_sb_info *sbi)
>  #endif
>  
>  static int f2fs_set_test_dummy_encryption(struct f2fs_sb_info *sbi,
> -					  const char *opt,
> -					  const substring_t *arg,
> +					  const struct fs_parameter *param,
>  					  bool is_remount)
>  {
> -	struct fs_parameter param = {
> -		.type = fs_value_is_string,
> -		.string = arg->from ? arg->from : "",
> -	};
>  	struct fscrypt_dummy_policy *policy =
>  		&F2FS_OPTION(sbi).dummy_enc_policy;
>  	int err;
> @@ -642,17 +548,17 @@ static int f2fs_set_test_dummy_encryption(struct f2fs_sb_info *sbi,
>  		return -EINVAL;
>  	}
>  
> -	err = fscrypt_parse_test_dummy_encryption(&param, policy);
> +	err = fscrypt_parse_test_dummy_encryption(param, policy);
>  	if (err) {
>  		if (err == -EEXIST)
>  			f2fs_warn(sbi,
>  				  "Can't change test_dummy_encryption on remount");
>  		else if (err == -EINVAL)
>  			f2fs_warn(sbi, "Value of option \"%s\" is unrecognized",
> -				  opt);
> +				  param->key);
>  		else
>  			f2fs_warn(sbi, "Error processing option \"%s\" [%d]",
> -				  opt, err);
> +				  param->key, err);
>  		return -EINVAL;
>  	}
>  	f2fs_warn(sbi, "Test dummy encryption mode enabled");
> @@ -795,373 +701,263 @@ static int f2fs_set_zstd_level(struct f2fs_sb_info *sbi, const char *str)
>  #endif
>  #endif
>  
> -static int parse_options(struct f2fs_sb_info *sbi, char *options, bool is_remount)
> +static int handle_mount_opt(struct fs_context *fc, struct fs_parameter *param)
>  {
> -	substring_t args[MAX_OPT_ARGS];
> +	struct f2fs_sb_info *sbi = fc->s_fs_info;
>  #ifdef CONFIG_F2FS_FS_COMPRESSION
>  	unsigned char (*ext)[F2FS_EXTENSION_LEN];
>  	unsigned char (*noext)[F2FS_EXTENSION_LEN];
>  	int ext_cnt, noext_cnt;
>  #endif
> -	char *p, *name;
> -	int arg = 0;
> -	kuid_t uid;
> -	kgid_t gid;
> -	int ret;
> +	substring_t args[MAX_OPT_ARGS];
> +	struct fs_parse_result result;
> +	int is_remount;
> +	char *name;
> +	int token, ret, arg;
>  
> -	if (!options)
> -		return 0;
> +	token = fs_parse(fc, f2fs_param_specs, param, &result);
> +	if (token < 0)
> +		return token;
>  
> -	while ((p = strsep(&options, ",")) != NULL) {
> -		int token;
> +	is_remount = fc->purpose == FS_CONTEXT_FOR_RECONFIGURE;
>  
> -		if (!*p)
> -			continue;
> -		/*
> -		 * Initialize args struct so we know whether arg was
> -		 * found; some options take optional arguments.
> -		 */
> -		args[0].to = args[0].from = NULL;
> -		token = match_token(p, f2fs_tokens, args);
> -
> -		switch (token) {
> -		case Opt_gc_background:
> -			name = match_strdup(&args[0]);
> -
> -			if (!name)
> -				return -ENOMEM;
> -			if (!strcmp(name, "on")) {
> -				F2FS_OPTION(sbi).bggc_mode = BGGC_MODE_ON;
> -			} else if (!strcmp(name, "off")) {
> -				if (f2fs_sb_has_blkzoned(sbi)) {
> -					f2fs_warn(sbi, "zoned devices need bggc");
> -					kfree(name);
> -					return -EINVAL;
> -				}
> -				F2FS_OPTION(sbi).bggc_mode = BGGC_MODE_OFF;
> -			} else if (!strcmp(name, "sync")) {
> -				F2FS_OPTION(sbi).bggc_mode = BGGC_MODE_SYNC;
> -			} else {
> -				kfree(name);
> +	switch (token) {
> +	case Opt_gc_background:
> +		F2FS_OPTION(sbi).bggc_mode = result.uint_32;
> +		break;
> +	case Opt_disable_roll_forward:
> +		set_opt(sbi, DISABLE_ROLL_FORWARD);
> +		break;
> +	case Opt_norecovery:
> +		/* requires ro mount, checked in f2fs_validate_options */
> +		set_opt(sbi, NORECOVERY);
> +		break;
> +	case Opt_discard:
> +		if (result.negated) {
> +			if (f2fs_hw_should_discard(sbi)) {
> +				f2fs_warn(sbi, "discard is required for zoned block devices");
>  				return -EINVAL;
>  			}
> -			kfree(name);
> -			break;
> -		case Opt_disable_roll_forward:
> -			set_opt(sbi, DISABLE_ROLL_FORWARD);
> -			break;
> -		case Opt_norecovery:
> -			/* requires ro mount, checked in f2fs_default_check */
> -			set_opt(sbi, NORECOVERY);
> -			break;
> -		case Opt_discard:
> +			clear_opt(sbi, DISCARD);
> +		} else {
>  			if (!f2fs_hw_support_discard(sbi)) {
>  				f2fs_warn(sbi, "device does not support discard");
>  				break;
>  			}
>  			set_opt(sbi, DISCARD);
> -			break;
> -		case Opt_nodiscard:
> -			if (f2fs_hw_should_discard(sbi)) {
> -				f2fs_warn(sbi, "discard is required for zoned block devices");
> -				return -EINVAL;
> -			}
> -			clear_opt(sbi, DISCARD);
> -			break;
> -		case Opt_noheap:
> -		case Opt_heap:
> -			f2fs_warn(sbi, "heap/no_heap options were deprecated");
> -			break;
> +		}
> +		break;
> +	case Opt_noheap:
> +	case Opt_heap:
> +		f2fs_warn(sbi, "heap/no_heap options were deprecated");
> +		break;
>  #ifdef CONFIG_F2FS_FS_XATTR
> -		case Opt_user_xattr:
> -			set_opt(sbi, XATTR_USER);
> -			break;
> -		case Opt_nouser_xattr:
> +	case Opt_user_xattr:
> +		if (result.negated)
>  			clear_opt(sbi, XATTR_USER);
> -			break;
> -		case Opt_inline_xattr:
> -			set_opt(sbi, INLINE_XATTR);
> -			break;
> -		case Opt_noinline_xattr:
> +		else
> +			set_opt(sbi, XATTR_USER);
> +		break;
> +	case Opt_inline_xattr:
> +		if (result.negated)
>  			clear_opt(sbi, INLINE_XATTR);
> -			break;
> -		case Opt_inline_xattr_size:
> -			if (args->from && match_int(args, &arg))
> -				return -EINVAL;
> -			set_opt(sbi, INLINE_XATTR_SIZE);
> -			F2FS_OPTION(sbi).inline_xattr_size = arg;
> -			break;
> +		else
> +			set_opt(sbi, INLINE_XATTR);
> +		break;
> +	case Opt_inline_xattr_size:
> +		set_opt(sbi, INLINE_XATTR_SIZE);
> +		F2FS_OPTION(sbi).inline_xattr_size = result.int_32;
> +		break;
>  #else
> -		case Opt_user_xattr:
> -		case Opt_nouser_xattr:
> -		case Opt_inline_xattr:
> -		case Opt_noinline_xattr:
> -		case Opt_inline_xattr_size:
> -			f2fs_info(sbi, "xattr options not supported");
> -			break;
> +	case Opt_user_xattr:
> +	case Opt_inline_xattr:
> +	case Opt_inline_xattr_size:
> +		f2fs_info(sbi, "%s options not supported", param->key);
> +		break;
>  #endif
>  #ifdef CONFIG_F2FS_FS_POSIX_ACL
> -		case Opt_acl:
> -			set_opt(sbi, POSIX_ACL);
> -			break;
> -		case Opt_noacl:
> +	case Opt_acl:
> +		if (result.negated)
>  			clear_opt(sbi, POSIX_ACL);
> -			break;
> +		else
> +			set_opt(sbi, POSIX_ACL);
> +		break;
>  #else
> -		case Opt_acl:
> -		case Opt_noacl:
> -			f2fs_info(sbi, "acl options not supported");
> -			break;
> +	case Opt_acl:
> +		f2fs_info(sbi, "%s options not supported", param->key);
> +		break;
>  #endif
> -		case Opt_active_logs:
> -			if (args->from && match_int(args, &arg))
> -				return -EINVAL;
> -			if (arg != 2 && arg != 4 &&
> -				arg != NR_CURSEG_PERSIST_TYPE)
> -				return -EINVAL;
> -			F2FS_OPTION(sbi).active_logs = arg;
> -			break;
> -		case Opt_disable_ext_identify:
> -			set_opt(sbi, DISABLE_EXT_IDENTIFY);
> -			break;
> -		case Opt_inline_data:
> +	case Opt_active_logs:
> +		if (result.int_32 != 2 && result.int_32 != 4 &&
> +			result.int_32 != NR_CURSEG_PERSIST_TYPE)
> +			return -EINVAL;
> +		F2FS_OPTION(sbi).active_logs = result.int_32;
> +		break;
> +	case Opt_disable_ext_identify:
> +		set_opt(sbi, DISABLE_EXT_IDENTIFY);
> +		break;
> +	case Opt_inline_data:
> +		if (result.negated)
> +			clear_opt(sbi, INLINE_DATA);
> +		else
>  			set_opt(sbi, INLINE_DATA);
> -			break;
> -		case Opt_inline_dentry:
> -			set_opt(sbi, INLINE_DENTRY);
> -			break;
> -		case Opt_noinline_dentry:
> +		break;
> +	case Opt_inline_dentry:
> +		if (result.negated)
>  			clear_opt(sbi, INLINE_DENTRY);
> -			break;
> -		case Opt_flush_merge:
> -			set_opt(sbi, FLUSH_MERGE);
> -			break;
> -		case Opt_noflush_merge:
> +		else
> +			set_opt(sbi, INLINE_DENTRY);
> +		break;
> +	case Opt_flush_merge:
> +		if (result.negated)
>  			clear_opt(sbi, FLUSH_MERGE);
> -			break;
> -		case Opt_nobarrier:
> +		else
> +			set_opt(sbi, FLUSH_MERGE);
> +		break;
> +	case Opt_barrier:
> +		if (result.negated)
>  			set_opt(sbi, NOBARRIER);
> -			break;
> -		case Opt_barrier:
> +		else
>  			clear_opt(sbi, NOBARRIER);
> -			break;
> -		case Opt_fastboot:
> -			set_opt(sbi, FASTBOOT);
> -			break;
> -		case Opt_extent_cache:
> -			set_opt(sbi, READ_EXTENT_CACHE);
> -			break;
> -		case Opt_noextent_cache:
> +		break;
> +	case Opt_fastboot:
> +		set_opt(sbi, FASTBOOT);
> +		break;
> +	case Opt_extent_cache:
> +		if (result.negated) {
>  			if (f2fs_sb_has_device_alias(sbi)) {
>  				f2fs_err(sbi, "device aliasing requires extent cache");
>  				return -EINVAL;
>  			}
>  			clear_opt(sbi, READ_EXTENT_CACHE);
> -			break;
> -		case Opt_noinline_data:
> -			clear_opt(sbi, INLINE_DATA);
> -			break;
> -		case Opt_data_flush:
> -			set_opt(sbi, DATA_FLUSH);
> -			break;
> -		case Opt_reserve_root:
> -			if (args->from && match_int(args, &arg))
> -				return -EINVAL;
> -			if (test_opt(sbi, RESERVE_ROOT)) {
> -				f2fs_info(sbi, "Preserve previous reserve_root=%u",
> -					  F2FS_OPTION(sbi).root_reserved_blocks);
> -			} else {
> -				F2FS_OPTION(sbi).root_reserved_blocks = arg;
> -				set_opt(sbi, RESERVE_ROOT);
> -			}
> -			break;
> -		case Opt_resuid:
> -			if (args->from && match_int(args, &arg))
> -				return -EINVAL;
> -			uid = make_kuid(current_user_ns(), arg);
> -			if (!uid_valid(uid)) {
> -				f2fs_err(sbi, "Invalid uid value %d", arg);
> -				return -EINVAL;
> -			}
> -			F2FS_OPTION(sbi).s_resuid = uid;
> -			break;
> -		case Opt_resgid:
> -			if (args->from && match_int(args, &arg))
> -				return -EINVAL;
> -			gid = make_kgid(current_user_ns(), arg);
> -			if (!gid_valid(gid)) {
> -				f2fs_err(sbi, "Invalid gid value %d", arg);
> -				return -EINVAL;
> -			}
> -			F2FS_OPTION(sbi).s_resgid = gid;
> -			break;
> -		case Opt_mode:
> -			name = match_strdup(&args[0]);
> -
> -			if (!name)
> -				return -ENOMEM;
> -			if (!strcmp(name, "adaptive")) {
> -				F2FS_OPTION(sbi).fs_mode = FS_MODE_ADAPTIVE;
> -			} else if (!strcmp(name, "lfs")) {
> -				F2FS_OPTION(sbi).fs_mode = FS_MODE_LFS;
> -			} else if (!strcmp(name, "fragment:segment")) {
> -				F2FS_OPTION(sbi).fs_mode = FS_MODE_FRAGMENT_SEG;
> -			} else if (!strcmp(name, "fragment:block")) {
> -				F2FS_OPTION(sbi).fs_mode = FS_MODE_FRAGMENT_BLK;
> -			} else {
> -				kfree(name);
> -				return -EINVAL;
> -			}
> -			kfree(name);
> -			break;
> +		} else
> +			set_opt(sbi, READ_EXTENT_CACHE);
> +		break;
> +	case Opt_data_flush:
> +		set_opt(sbi, DATA_FLUSH);
> +		break;
> +	case Opt_reserve_root:
> +		if (test_opt(sbi, RESERVE_ROOT)) {
> +			f2fs_info(sbi, "Preserve previous reserve_root=%u",
> +				  F2FS_OPTION(sbi).root_reserved_blocks);
> +		} else {
> +			F2FS_OPTION(sbi).root_reserved_blocks = result.int_32;
> +			set_opt(sbi, RESERVE_ROOT);
> +		}
> +		break;
> +	case Opt_resuid:
> +		F2FS_OPTION(sbi).s_resuid = result.uid;
> +		break;
> +	case Opt_resgid:
> +		F2FS_OPTION(sbi).s_resgid = result.gid;
> +		break;
> +	case Opt_mode:
> +		F2FS_OPTION(sbi).fs_mode = result.uint_32;
> +		break;
>  #ifdef CONFIG_F2FS_FAULT_INJECTION
> -		case Opt_fault_injection:
> -			if (args->from && match_int(args, &arg))
> -				return -EINVAL;
> -			if (f2fs_build_fault_attr(sbi, arg,
> -					F2FS_ALL_FAULT_TYPE))
> -				return -EINVAL;
> -			set_opt(sbi, FAULT_INJECTION);
> -			break;
> +	case Opt_fault_injection:
> +		if (f2fs_build_fault_attr(sbi, result.int_32,
> +				F2FS_ALL_FAULT_TYPE))
> +			return -EINVAL;
> +		set_opt(sbi, FAULT_INJECTION);
> +		break;
>  
> -		case Opt_fault_type:
> -			if (args->from && match_int(args, &arg))
> -				return -EINVAL;
> -			if (f2fs_build_fault_attr(sbi, 0, arg))
> -				return -EINVAL;
> -			set_opt(sbi, FAULT_INJECTION);
> -			break;
> +	case Opt_fault_type:
> +		if (f2fs_build_fault_attr(sbi, 0, result.int_32))
> +			return -EINVAL;
> +		set_opt(sbi, FAULT_INJECTION);
> +		break;
>  #else
> -		case Opt_fault_injection:
> -		case Opt_fault_type:
> -			f2fs_info(sbi, "fault injection options not supported");
> -			break;
> +	case Opt_fault_injection:
> +	case Opt_fault_type:
> +		f2fs_info(sbi, "%s options not supported", param->key);
> +		break;
>  #endif
> -		case Opt_lazytime:
> -			set_opt(sbi, LAZYTIME);
> -			break;
> -		case Opt_nolazytime:
> +	case Opt_lazytime:
> +		if (result.negated)
>  			clear_opt(sbi, LAZYTIME);
> -			break;
> +		else
> +			set_opt(sbi, LAZYTIME);
> +		break;
>  #ifdef CONFIG_QUOTA
> -		case Opt_quota:
> -		case Opt_usrquota:
> -			set_opt(sbi, USRQUOTA);
> -			break;
> -		case Opt_grpquota:
> -			set_opt(sbi, GRPQUOTA);
> -			break;
> -		case Opt_prjquota:
> -			set_opt(sbi, PRJQUOTA);
> -			break;
> -		case Opt_usrjquota:
> -			ret = f2fs_set_qf_name(sbi, USRQUOTA, &args[0]);
> -			if (ret)
> -				return ret;
> -			break;
> -		case Opt_grpjquota:
> -			ret = f2fs_set_qf_name(sbi, GRPQUOTA, &args[0]);
> -			if (ret)
> -				return ret;
> -			break;
> -		case Opt_prjjquota:
> -			ret = f2fs_set_qf_name(sbi, PRJQUOTA, &args[0]);
> -			if (ret)
> -				return ret;
> -			break;
> -		case Opt_offusrjquota:
> -			ret = f2fs_clear_qf_name(sbi, USRQUOTA);
> -			if (ret)
> -				return ret;
> -			break;
> -		case Opt_offgrpjquota:
> -			ret = f2fs_clear_qf_name(sbi, GRPQUOTA);
> -			if (ret)
> -				return ret;
> -			break;
> -		case Opt_offprjjquota:
> -			ret = f2fs_clear_qf_name(sbi, PRJQUOTA);
> -			if (ret)
> -				return ret;
> -			break;
> -		case Opt_jqfmt_vfsold:
> -			F2FS_OPTION(sbi).s_jquota_fmt = QFMT_VFS_OLD;
> -			break;
> -		case Opt_jqfmt_vfsv0:
> -			F2FS_OPTION(sbi).s_jquota_fmt = QFMT_VFS_V0;
> -			break;
> -		case Opt_jqfmt_vfsv1:
> -			F2FS_OPTION(sbi).s_jquota_fmt = QFMT_VFS_V1;
> -			break;
> -		case Opt_noquota:
> +	case Opt_quota:
> +		if (result.negated) {
>  			clear_opt(sbi, QUOTA);
>  			clear_opt(sbi, USRQUOTA);
>  			clear_opt(sbi, GRPQUOTA);
>  			clear_opt(sbi, PRJQUOTA);
> -			break;
> +		} else
> +			set_opt(sbi, USRQUOTA);
> +		break;
> +	case Opt_usrquota:
> +		set_opt(sbi, USRQUOTA);
> +		break;
> +	case Opt_grpquota:
> +		set_opt(sbi, GRPQUOTA);
> +		break;
> +	case Opt_prjquota:
> +		set_opt(sbi, PRJQUOTA);
> +		break;
> +	case Opt_usrjquota:
> +		if (!*param->string)
> +			ret = f2fs_clear_qf_name(sbi, USRQUOTA);
> +		else
> +			ret = f2fs_set_qf_name(sbi, USRQUOTA, param);
> +		if (ret)
> +			return ret;
> +		break;
> +	case Opt_grpjquota:
> +		if (!*param->string)
> +			ret = f2fs_clear_qf_name(sbi, GRPQUOTA);
> +		else
> +			ret = f2fs_set_qf_name(sbi, GRPQUOTA, param);
> +		if (ret)
> +			return ret;
> +		break;
> +	case Opt_prjjquota:
> +		if (!*param->string)
> +			ret = f2fs_clear_qf_name(sbi, PRJQUOTA);
> +		else
> +			ret = f2fs_set_qf_name(sbi, PRJQUOTA, param);
> +		if (ret)
> +			return ret;
> +		break;
> +	case Opt_jqfmt:
> +		F2FS_OPTION(sbi).s_jquota_fmt = result.uint_32;
> +		break;
>  #else
> -		case Opt_quota:
> -		case Opt_usrquota:
> -		case Opt_grpquota:
> -		case Opt_prjquota:
> -		case Opt_usrjquota:
> -		case Opt_grpjquota:
> -		case Opt_prjjquota:
> -		case Opt_offusrjquota:
> -		case Opt_offgrpjquota:
> -		case Opt_offprjjquota:
> -		case Opt_jqfmt_vfsold:
> -		case Opt_jqfmt_vfsv0:
> -		case Opt_jqfmt_vfsv1:
> -		case Opt_noquota:
> -			f2fs_info(sbi, "quota operations not supported");
> -			break;
> +	case Opt_quota:
> +	case Opt_usrquota:
> +	case Opt_grpquota:
> +	case Opt_prjquota:
> +	case Opt_usrjquota:
> +	case Opt_grpjquota:
> +	case Opt_prjjquota:
> +		f2fs_info(sbi, "quota operations not supported");
> +		break;
>  #endif
> -		case Opt_alloc:
> -			name = match_strdup(&args[0]);
> -			if (!name)
> -				return -ENOMEM;
> -
> -			if (!strcmp(name, "default")) {
> -				F2FS_OPTION(sbi).alloc_mode = ALLOC_MODE_DEFAULT;
> -			} else if (!strcmp(name, "reuse")) {
> -				F2FS_OPTION(sbi).alloc_mode = ALLOC_MODE_REUSE;
> -			} else {
> -				kfree(name);
> -				return -EINVAL;
> -			}
> -			kfree(name);
> -			break;
> -		case Opt_fsync:
> -			name = match_strdup(&args[0]);
> -			if (!name)
> -				return -ENOMEM;
> -			if (!strcmp(name, "posix")) {
> -				F2FS_OPTION(sbi).fsync_mode = FSYNC_MODE_POSIX;
> -			} else if (!strcmp(name, "strict")) {
> -				F2FS_OPTION(sbi).fsync_mode = FSYNC_MODE_STRICT;
> -			} else if (!strcmp(name, "nobarrier")) {
> -				F2FS_OPTION(sbi).fsync_mode =
> -							FSYNC_MODE_NOBARRIER;
> -			} else {
> -				kfree(name);
> -				return -EINVAL;
> -			}
> -			kfree(name);
> -			break;
> -		case Opt_test_dummy_encryption:
> -			ret = f2fs_set_test_dummy_encryption(sbi, p, &args[0],
> -							     is_remount);
> -			if (ret)
> -				return ret;
> -			break;
> -		case Opt_inlinecrypt:
> +	case Opt_alloc:
> +		F2FS_OPTION(sbi).alloc_mode = result.uint_32;
> +		break;
> +	case Opt_fsync:
> +		F2FS_OPTION(sbi).fsync_mode = result.uint_32;
> +		break;
> +	case Opt_test_dummy_encryption:
> +		ret = f2fs_set_test_dummy_encryption(sbi, param, is_remount);
> +		if (ret)
> +			return ret;
> +		break;
> +	case Opt_inlinecrypt:
>  #ifdef CONFIG_FS_ENCRYPTION_INLINE_CRYPT
> -			set_opt(sbi, INLINECRYPT);
> +		set_opt(sbi, INLINECRYPT);
>  #else
> -			f2fs_info(sbi, "inline encryption not supported");
> +		f2fs_info(sbi, "inline encryption not supported");
>  #endif
> -			break;
> +		break;
> +	case Opt_checkpoint:
> +		/* revert to match_table for checkpoint= options */
> +		token = match_token(param->string, f2fs_checkpoint_tokens, args);
> +		switch (token) {
>  		case Opt_checkpoint_disable_cap_perc:
>  			if (args->from && match_int(args, &arg))
>  				return -EINVAL;
> @@ -1182,270 +978,225 @@ static int parse_options(struct f2fs_sb_info *sbi, char *options, bool is_remoun
>  		case Opt_checkpoint_enable:
>  			clear_opt(sbi, DISABLE_CHECKPOINT);
>  			break;
> -		case Opt_checkpoint_merge:
> -			set_opt(sbi, MERGE_CHECKPOINT);
> -			break;
> -		case Opt_nocheckpoint_merge:
> +		default:
> +			return -EINVAL;
> +		}
> +		break;
> +	case Opt_checkpoint_merge:
> +		if (result.negated)
>  			clear_opt(sbi, MERGE_CHECKPOINT);
> -			break;
> +		else
> +			set_opt(sbi, MERGE_CHECKPOINT);
> +		break;
>  #ifdef CONFIG_F2FS_FS_COMPRESSION
> -		case Opt_compress_algorithm:
> -			if (!f2fs_sb_has_compression(sbi)) {
> -				f2fs_info(sbi, "Image doesn't support compression");
> -				break;
> -			}
> -			name = match_strdup(&args[0]);
> -			if (!name)
> -				return -ENOMEM;
> -			if (!strcmp(name, "lzo")) {
> +	case Opt_compress_algorithm:
> +		if (!f2fs_sb_has_compression(sbi)) {
> +			f2fs_info(sbi, "Image doesn't support compression");
> +			break;
> +		}
> +		name = param->string;
> +		if (!strcmp(name, "lzo")) {
>  #ifdef CONFIG_F2FS_FS_LZO
> -				F2FS_OPTION(sbi).compress_level = 0;
> -				F2FS_OPTION(sbi).compress_algorithm =
> -								COMPRESS_LZO;
> +			F2FS_OPTION(sbi).compress_level = 0;
> +			F2FS_OPTION(sbi).compress_algorithm = COMPRESS_LZO;
>  #else
> -				f2fs_info(sbi, "kernel doesn't support lzo compression");
> +			f2fs_info(sbi, "kernel doesn't support lzo compression");
>  #endif
> -			} else if (!strncmp(name, "lz4", 3)) {
> +		} else if (!strncmp(name, "lz4", 3)) {
>  #ifdef CONFIG_F2FS_FS_LZ4
> -				ret = f2fs_set_lz4hc_level(sbi, name);
> -				if (ret) {
> -					kfree(name);
> -					return -EINVAL;
> -				}
> -				F2FS_OPTION(sbi).compress_algorithm =
> -								COMPRESS_LZ4;
> +			ret = f2fs_set_lz4hc_level(sbi, name);
> +			if (ret)
> +				return -EINVAL;
> +			F2FS_OPTION(sbi).compress_algorithm = COMPRESS_LZ4;
>  #else
> -				f2fs_info(sbi, "kernel doesn't support lz4 compression");
> +			f2fs_info(sbi, "kernel doesn't support lz4 compression");
>  #endif
> -			} else if (!strncmp(name, "zstd", 4)) {
> +		} else if (!strncmp(name, "zstd", 4)) {
>  #ifdef CONFIG_F2FS_FS_ZSTD
> -				ret = f2fs_set_zstd_level(sbi, name);
> -				if (ret) {
> -					kfree(name);
> -					return -EINVAL;
> -				}
> -				F2FS_OPTION(sbi).compress_algorithm =
> -								COMPRESS_ZSTD;
> +			ret = f2fs_set_zstd_level(sbi, name);
> +			if (ret)
> +				return -EINVAL;
> +			F2FS_OPTION(sbi).compress_algorithm = COMPRESS_ZSTD;
>  #else
> -				f2fs_info(sbi, "kernel doesn't support zstd compression");
> +			f2fs_info(sbi, "kernel doesn't support zstd compression");
>  #endif
> -			} else if (!strcmp(name, "lzo-rle")) {
> +		} else if (!strcmp(name, "lzo-rle")) {
>  #ifdef CONFIG_F2FS_FS_LZORLE
> -				F2FS_OPTION(sbi).compress_level = 0;
> -				F2FS_OPTION(sbi).compress_algorithm =
> -								COMPRESS_LZORLE;
> +			F2FS_OPTION(sbi).compress_level = 0;
> +			F2FS_OPTION(sbi).compress_algorithm = COMPRESS_LZORLE;
>  #else
> -				f2fs_info(sbi, "kernel doesn't support lzorle compression");
> +			f2fs_info(sbi, "kernel doesn't support lzorle compression");
>  #endif
> -			} else {
> -				kfree(name);
> -				return -EINVAL;
> -			}
> -			kfree(name);
> +		} else
> +			return -EINVAL;
> +		break;
> +	case Opt_compress_log_size:
> +		if (!f2fs_sb_has_compression(sbi)) {
> +			f2fs_info(sbi, "Image doesn't support compression");
>  			break;
> -		case Opt_compress_log_size:
> -			if (!f2fs_sb_has_compression(sbi)) {
> -				f2fs_info(sbi, "Image doesn't support compression");
> -				break;
> -			}
> -			if (args->from && match_int(args, &arg))
> -				return -EINVAL;
> -			if (arg < MIN_COMPRESS_LOG_SIZE ||
> -				arg > MAX_COMPRESS_LOG_SIZE) {
> -				f2fs_err(sbi,
> -					"Compress cluster log size is out of range");
> -				return -EINVAL;
> -			}
> -			F2FS_OPTION(sbi).compress_log_size = arg;
> +		}
> +		if (result.uint_32 < MIN_COMPRESS_LOG_SIZE ||
> +		    result.uint_32 > MAX_COMPRESS_LOG_SIZE) {
> +			f2fs_err(sbi,
> +				"Compress cluster log size is out of range");
> +			return -EINVAL;
> +		}
> +		F2FS_OPTION(sbi).compress_log_size = result.uint_32;
> +		break;
> +	case Opt_compress_extension:
> +		if (!f2fs_sb_has_compression(sbi)) {
> +			f2fs_info(sbi, "Image doesn't support compression");
>  			break;
> -		case Opt_compress_extension:
> -			if (!f2fs_sb_has_compression(sbi)) {
> -				f2fs_info(sbi, "Image doesn't support compression");
> -				break;
> -			}
> -			name = match_strdup(&args[0]);
> -			if (!name)
> -				return -ENOMEM;
> -
> -			ext = F2FS_OPTION(sbi).extensions;
> -			ext_cnt = F2FS_OPTION(sbi).compress_ext_cnt;
> -
> -			if (strlen(name) >= F2FS_EXTENSION_LEN ||
> -				ext_cnt >= COMPRESS_EXT_NUM) {
> -				f2fs_err(sbi,
> -					"invalid extension length/number");
> -				kfree(name);
> -				return -EINVAL;
> -			}
> +		}
> +		name = param->string;
> +		ext = F2FS_OPTION(sbi).extensions;
> +		ext_cnt = F2FS_OPTION(sbi).compress_ext_cnt;
>  
> -			if (is_compress_extension_exist(sbi, name, true)) {
> -				kfree(name);
> -				break;
> -			}
> +		if (strlen(name) >= F2FS_EXTENSION_LEN ||
> +		    ext_cnt >= COMPRESS_EXT_NUM) {
> +			f2fs_err(sbi, "invalid extension length/number");
> +			return -EINVAL;
> +		}
>  
> -			ret = strscpy(ext[ext_cnt], name);
> -			if (ret < 0) {
> -				kfree(name);
> -				return ret;
> -			}
> -			F2FS_OPTION(sbi).compress_ext_cnt++;
> -			kfree(name);
> +		if (is_compress_extension_exist(sbi, name, true))
>  			break;
> -		case Opt_nocompress_extension:
> -			if (!f2fs_sb_has_compression(sbi)) {
> -				f2fs_info(sbi, "Image doesn't support compression");
> -				break;
> -			}
> -			name = match_strdup(&args[0]);
> -			if (!name)
> -				return -ENOMEM;
>  
> -			noext = F2FS_OPTION(sbi).noextensions;
> -			noext_cnt = F2FS_OPTION(sbi).nocompress_ext_cnt;
> -
> -			if (strlen(name) >= F2FS_EXTENSION_LEN ||
> -				noext_cnt >= COMPRESS_EXT_NUM) {
> -				f2fs_err(sbi,
> -					"invalid extension length/number");
> -				kfree(name);
> -				return -EINVAL;
> -			}
> +		ret = strscpy(ext[ext_cnt], name, F2FS_EXTENSION_LEN);
> +		if (ret < 0)
> +			return ret;
> +		F2FS_OPTION(sbi).compress_ext_cnt++;
> +		break;
> +	case Opt_nocompress_extension:
> +		if (!f2fs_sb_has_compression(sbi)) {
> +			f2fs_info(sbi, "Image doesn't support compression");
> +			break;
> +		}
> +		name = param->string;
> +		noext = F2FS_OPTION(sbi).noextensions;
> +		noext_cnt = F2FS_OPTION(sbi).nocompress_ext_cnt;
>  
> -			if (is_compress_extension_exist(sbi, name, false)) {
> -				kfree(name);
> -				break;
> -			}
> +		if (strlen(name) >= F2FS_EXTENSION_LEN ||
> +			noext_cnt >= COMPRESS_EXT_NUM) {
> +			f2fs_err(sbi, "invalid extension length/number");
> +			return -EINVAL;
> +		}
>  
> -			ret = strscpy(noext[noext_cnt], name);
> -			if (ret < 0) {
> -				kfree(name);
> -				return ret;
> -			}
> -			F2FS_OPTION(sbi).nocompress_ext_cnt++;
> -			kfree(name);
> +		if (is_compress_extension_exist(sbi, name, false))
>  			break;
> -		case Opt_compress_chksum:
> -			if (!f2fs_sb_has_compression(sbi)) {
> -				f2fs_info(sbi, "Image doesn't support compression");
> -				break;
> -			}
> -			F2FS_OPTION(sbi).compress_chksum = true;
> +
> +		ret = strscpy(noext[noext_cnt], name, F2FS_EXTENSION_LEN);
> +		if (ret < 0)
> +			return ret;
> +		F2FS_OPTION(sbi).nocompress_ext_cnt++;
> +		break;
> +	case Opt_compress_chksum:
> +		if (!f2fs_sb_has_compression(sbi)) {
> +			f2fs_info(sbi, "Image doesn't support compression");
>  			break;
> -		case Opt_compress_mode:
> -			if (!f2fs_sb_has_compression(sbi)) {
> -				f2fs_info(sbi, "Image doesn't support compression");
> -				break;
> -			}
> -			name = match_strdup(&args[0]);
> -			if (!name)
> -				return -ENOMEM;
> -			if (!strcmp(name, "fs")) {
> -				F2FS_OPTION(sbi).compress_mode = COMPR_MODE_FS;
> -			} else if (!strcmp(name, "user")) {
> -				F2FS_OPTION(sbi).compress_mode = COMPR_MODE_USER;
> -			} else {
> -				kfree(name);
> -				return -EINVAL;
> -			}
> -			kfree(name);
> +		}
> +		F2FS_OPTION(sbi).compress_chksum = true;
> +		break;
> +	case Opt_compress_mode:
> +		if (!f2fs_sb_has_compression(sbi)) {
> +			f2fs_info(sbi, "Image doesn't support compression");
>  			break;
> -		case Opt_compress_cache:
> -			if (!f2fs_sb_has_compression(sbi)) {
> -				f2fs_info(sbi, "Image doesn't support compression");
> -				break;
> -			}
> -			set_opt(sbi, COMPRESS_CACHE);
> +		}
> +		F2FS_OPTION(sbi).compress_mode = result.uint_32;
> +		break;
> +	case Opt_compress_cache:
> +		if (!f2fs_sb_has_compression(sbi)) {
> +			f2fs_info(sbi, "Image doesn't support compression");
>  			break;
> +		}
> +		set_opt(sbi, COMPRESS_CACHE);
> +		break;
>  #else
> -		case Opt_compress_algorithm:
> -		case Opt_compress_log_size:
> -		case Opt_compress_extension:
> -		case Opt_nocompress_extension:
> -		case Opt_compress_chksum:
> -		case Opt_compress_mode:
> -		case Opt_compress_cache:
> -			f2fs_info(sbi, "compression options not supported");
> -			break;
> +	case Opt_compress_algorithm:
> +	case Opt_compress_log_size:
> +	case Opt_compress_extension:
> +	case Opt_nocompress_extension:
> +	case Opt_compress_chksum:
> +	case Opt_compress_mode:
> +	case Opt_compress_cache:
> +		f2fs_info(sbi, "compression options not supported");
> +		break;
>  #endif
> -		case Opt_atgc:
> -			set_opt(sbi, ATGC);
> -			break;
> -		case Opt_gc_merge:
> -			set_opt(sbi, GC_MERGE);
> -			break;
> -		case Opt_nogc_merge:
> +	case Opt_atgc:
> +		set_opt(sbi, ATGC);
> +		break;
> +	case Opt_gc_merge:
> +		if (result.negated)
>  			clear_opt(sbi, GC_MERGE);
> -			break;
> -		case Opt_discard_unit:
> -			name = match_strdup(&args[0]);
> -			if (!name)
> -				return -ENOMEM;
> -			if (!strcmp(name, "block")) {
> -				F2FS_OPTION(sbi).discard_unit =
> -						DISCARD_UNIT_BLOCK;
> -			} else if (!strcmp(name, "segment")) {
> -				F2FS_OPTION(sbi).discard_unit =
> -						DISCARD_UNIT_SEGMENT;
> -			} else if (!strcmp(name, "section")) {
> -				F2FS_OPTION(sbi).discard_unit =
> -						DISCARD_UNIT_SECTION;
> -			} else {
> -				kfree(name);
> -				return -EINVAL;
> -			}
> -			kfree(name);
> -			break;
> -		case Opt_memory_mode:
> -			name = match_strdup(&args[0]);
> -			if (!name)
> -				return -ENOMEM;
> -			if (!strcmp(name, "normal")) {
> -				F2FS_OPTION(sbi).memory_mode =
> -						MEMORY_MODE_NORMAL;
> -			} else if (!strcmp(name, "low")) {
> -				F2FS_OPTION(sbi).memory_mode =
> -						MEMORY_MODE_LOW;
> -			} else {
> -				kfree(name);
> -				return -EINVAL;
> -			}
> -			kfree(name);
> -			break;
> -		case Opt_age_extent_cache:
> -			set_opt(sbi, AGE_EXTENT_CACHE);
> -			break;
> -		case Opt_errors:
> -			name = match_strdup(&args[0]);
> -			if (!name)
> -				return -ENOMEM;
> -			if (!strcmp(name, "remount-ro")) {
> -				F2FS_OPTION(sbi).errors =
> -						MOUNT_ERRORS_READONLY;
> -			} else if (!strcmp(name, "continue")) {
> -				F2FS_OPTION(sbi).errors =
> -						MOUNT_ERRORS_CONTINUE;
> -			} else if (!strcmp(name, "panic")) {
> -				F2FS_OPTION(sbi).errors =
> -						MOUNT_ERRORS_PANIC;
> -			} else {
> -				kfree(name);
> -				return -EINVAL;
> +		else
> +			set_opt(sbi, GC_MERGE);
> +		break;
> +	case Opt_discard_unit:
> +		F2FS_OPTION(sbi).discard_unit = result.uint_32;
> +		break;
> +	case Opt_memory_mode:
> +		F2FS_OPTION(sbi).memory_mode = result.uint_32;
> +		break;
> +	case Opt_age_extent_cache:
> +		set_opt(sbi, AGE_EXTENT_CACHE);
> +		break;
> +	case Opt_errors:
> +		F2FS_OPTION(sbi).errors = result.uint_32;
> +		break;
> +	case Opt_nat_bits:
> +		set_opt(sbi, NAT_BITS);
> +		break;
> +	}
> +	return 0;
> +}
> +
> +static int parse_options(struct f2fs_sb_info *sbi, char *options, bool is_remount)
> +{
> +	struct fs_parameter param;
> +	struct fs_context fc;
> +	char *key;
> +	int ret;
> +
> +	if (!options)
> +		return 0;
> +
> +	memset(&fc, 0, sizeof(fc));
> +	fc.s_fs_info = sbi;
> +	if (is_remount)
> +		fc.purpose = FS_CONTEXT_FOR_RECONFIGURE;
> +
> +	while ((key = strsep(&options, ",")) != NULL) {
> +		if (*key) {
> +			size_t v_len = 0;
> +			char *value = strchr(key, '=');
> +
> +			param.type = fs_value_is_flag;
> +			param.string = NULL;
> +
> +			if (value) {
> +				if (value == key)
> +					continue;
> +
> +				*value++ = 0;
> +				v_len = strlen(value);
> +				param.string = kmemdup_nul(value, v_len, GFP_KERNEL);
> +				if (!param.string)
> +					return -ENOMEM;
> +				param.type = fs_value_is_string;
>  			}
> -			kfree(name);
> -			break;
> -		case Opt_nat_bits:
> -			set_opt(sbi, NAT_BITS);
> -			break;
> -		default:
> -			f2fs_err(sbi, "Unrecognized mount option \"%s\" or missing value",
> -				 p);
> -			return -EINVAL;
> +
> +			param.key = key;
> +			param.size = v_len;
> +
> +			ret = handle_mount_opt(&fc, &param);
> +			kfree(param.string);
> +			if (ret < 0)
> +				return ret;
>  		}
>  	}
>  	return 0;
>  }
>  
> -static int f2fs_default_check(struct f2fs_sb_info *sbi)
> +static int f2fs_validate_options(struct f2fs_sb_info *sbi)
>  {
>  #ifdef CONFIG_QUOTA
>  	if (f2fs_check_quota_options(sbi))
> @@ -2516,7 +2267,7 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
>  	}
>  #endif
>  
> -	err = f2fs_default_check(sbi);
> +	err = f2fs_validate_options(sbi);
>  	if (err)
>  		goto restore_opts;
>  
> @@ -4675,7 +4426,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
>  	if (err)
>  		goto free_options;
>  
> -	err = f2fs_default_check(sbi);
> +	err = f2fs_validate_options(sbi);
>  	if (err)
>  		goto free_options;
>  


  reply	other threads:[~2025-05-07 11:26 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-04-20 15:24 [PATCH 0/7 V2] f2fs: new mount API conversion Eric Sandeen
2025-04-20 15:25 ` [PATCH 1/7] f2fs: Add fs parameter specifications for mount options Eric Sandeen
2025-05-07  9:54   ` Chao Yu
2025-04-20 15:25 ` [PATCH 2/7] f2fs: move the option parser into handle_mount_opt Eric Sandeen
2025-05-07 11:26   ` Chao Yu [this message]
2025-05-07 12:31     ` Eric Sandeen
2025-05-07 15:02       ` Jaegeuk Kim
2025-05-08  3:29         ` Chao Yu
2025-05-08  3:28       ` Chao Yu
2025-04-20 15:25 ` [PATCH 3/7] f2fs: Allow sbi to be NULL in f2fs_printk Eric Sandeen
2025-05-07 11:29   ` Chao Yu
2025-04-20 15:25 ` [PATCH 4/7] f2fs: Add f2fs_fs_context to record the mount options Eric Sandeen
2025-04-20 15:25 ` [PATCH 5/7] f2fs: separate the options parsing and options checking Eric Sandeen
2025-04-21 16:34   ` kernel test robot
2025-04-21 17:37   ` kernel test robot
2025-04-21 17:37   ` kernel test robot
2025-04-20 15:25 ` [PATCH 6/7] f2fs: introduce fs_context_operation structure Eric Sandeen
2025-04-20 15:25 ` [PATCH 7/7] f2fs: switch to the new mount api Eric Sandeen
2025-04-22  2:39 ` [PATCH 0/7 V2] f2fs: new mount API conversion Eric Sandeen
2025-07-11 16:30 ` [f2fs-dev] " patchwork-bot+f2fs

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=2e354373-9f00-4499-8812-bcb7f00a6dbc@kernel.org \
    --to=chao@kernel.org \
    --cc=jaegeuk@kernel.org \
    --cc=lihongbo22@huawei.com \
    --cc=linux-f2fs-devel@lists.sourceforge.net \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=sandeen@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).