diff mbox series

[RFC,2/2] ocfs2: convert to the new mount API

Message ID 20241028144443.609151-3-sandeen@redhat.com (mailing list archive)
State New
Headers show
Series ocfs2, dlmfs: convert to the new mount API | expand

Commit Message

Eric Sandeen Oct. 28, 2024, 2:41 p.m. UTC
Convert ocfs2 to the new mount API.

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
---
 fs/ocfs2/ocfs2_trace.h |  20 +-
 fs/ocfs2/super.c       | 589 +++++++++++++++++++----------------------
 2 files changed, 277 insertions(+), 332 deletions(-)

Comments

Goldwyn Rodrigues Dec. 3, 2024, 4:46 p.m. UTC | #1
On  9:41 28/10, Eric Sandeen wrote:
> Convert ocfs2 to the new mount API.
> 
> Signed-off-by: Eric Sandeen <sandeen@redhat.com>

Reviewed-by: Goldwyn Rodrigues <rgoldwyn@suse.com>

> ---
>  fs/ocfs2/ocfs2_trace.h |  20 +-
>  fs/ocfs2/super.c       | 589 +++++++++++++++++++----------------------
>  2 files changed, 277 insertions(+), 332 deletions(-)
> 
> diff --git a/fs/ocfs2/ocfs2_trace.h b/fs/ocfs2/ocfs2_trace.h
> index 0511c69c9fde..54ed1495de9a 100644
> --- a/fs/ocfs2/ocfs2_trace.h
> +++ b/fs/ocfs2/ocfs2_trace.h
> @@ -1658,34 +1658,34 @@ TRACE_EVENT(ocfs2_remount,
>  );
>  
>  TRACE_EVENT(ocfs2_fill_super,
> -	TP_PROTO(void *sb, void *data, int silent),
> -	TP_ARGS(sb, data, silent),
> +	TP_PROTO(void *sb, void *fc, int silent),
> +	TP_ARGS(sb, fc, silent),
>  	TP_STRUCT__entry(
>  		__field(void *, sb)
> -		__field(void *, data)
> +		__field(void *, fc)
>  		__field(int, silent)
>  	),
>  	TP_fast_assign(
>  		__entry->sb = sb;
> -		__entry->data = data;
> +		__entry->fc = fc;
>  		__entry->silent = silent;
>  	),
>  	TP_printk("%p %p %d", __entry->sb,
> -		  __entry->data, __entry->silent)
> +		  __entry->fc, __entry->silent)
>  );
>  
>  TRACE_EVENT(ocfs2_parse_options,
> -	TP_PROTO(int is_remount, char *options),
> -	TP_ARGS(is_remount, options),
> +	TP_PROTO(int is_remount, const char *option),
> +	TP_ARGS(is_remount, option),
>  	TP_STRUCT__entry(
>  		__field(int, is_remount)
> -		__string(options, options)
> +		__string(option, option)
>  	),
>  	TP_fast_assign(
>  		__entry->is_remount = is_remount;
> -		__assign_str(options);
> +		__assign_str(option);
>  	),
> -	TP_printk("%d %s", __entry->is_remount, __get_str(options))
> +	TP_printk("%d %s", __entry->is_remount, __get_str(option))
>  );
>  
>  DEFINE_OCFS2_POINTER_EVENT(ocfs2_put_super);
> diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c
> index 3d404624bb96..110ffc4bb840 100644
> --- a/fs/ocfs2/super.c
> +++ b/fs/ocfs2/super.c
> @@ -19,10 +19,10 @@
>  #include <linux/blkdev.h>
>  #include <linux/socket.h>
>  #include <linux/inet.h>
> -#include <linux/parser.h>
> +#include <linux/fs_parser.h>
> +#include <linux/fs_context.h>
>  #include <linux/crc32.h>
>  #include <linux/debugfs.h>
> -#include <linux/mount.h>
>  #include <linux/seq_file.h>
>  #include <linux/quotaops.h>
>  #include <linux/signal.h>
> @@ -80,17 +80,15 @@ struct mount_options
>  	unsigned int	resv_level;
>  	int		dir_resv_level;
>  	char		cluster_stack[OCFS2_STACK_LABEL_LEN + 1];
> +	bool		user_stack;
>  };
>  
> -static int ocfs2_parse_options(struct super_block *sb, char *options,
> -			       struct mount_options *mopt,
> -			       int is_remount);
> +static int ocfs2_parse_param(struct fs_context *fc, struct fs_parameter *param);
>  static int ocfs2_check_set_options(struct super_block *sb,
>  				   struct mount_options *options);
>  static int ocfs2_show_options(struct seq_file *s, struct dentry *root);
>  static void ocfs2_put_super(struct super_block *sb);
>  static int ocfs2_mount_volume(struct super_block *sb);
> -static int ocfs2_remount(struct super_block *sb, int *flags, char *data);
>  static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err);
>  static int ocfs2_initialize_mem_caches(void);
>  static void ocfs2_free_mem_caches(void);
> @@ -135,7 +133,6 @@ static const struct super_operations ocfs2_sops = {
>  	.evict_inode	= ocfs2_evict_inode,
>  	.sync_fs	= ocfs2_sync_fs,
>  	.put_super	= ocfs2_put_super,
> -	.remount_fs	= ocfs2_remount,
>  	.show_options   = ocfs2_show_options,
>  	.quota_read	= ocfs2_quota_read,
>  	.quota_write	= ocfs2_quota_write,
> @@ -144,15 +141,10 @@ static const struct super_operations ocfs2_sops = {
>  
>  enum {
>  	Opt_barrier,
> -	Opt_err_panic,
> -	Opt_err_ro,
> +	Opt_errors,
>  	Opt_intr,
> -	Opt_nointr,
> -	Opt_hb_none,
> -	Opt_hb_local,
> -	Opt_hb_global,
> -	Opt_data_ordered,
> -	Opt_data_writeback,
> +	Opt_heartbeat,
> +	Opt_data,
>  	Opt_atime_quantum,
>  	Opt_slot,
>  	Opt_commit,
> @@ -160,52 +152,64 @@ enum {
>  	Opt_localflocks,
>  	Opt_stack,
>  	Opt_user_xattr,
> -	Opt_nouser_xattr,
>  	Opt_inode64,
>  	Opt_acl,
> -	Opt_noacl,
>  	Opt_usrquota,
>  	Opt_grpquota,
> -	Opt_coherency_buffered,
> -	Opt_coherency_full,
> +	Opt_coherency,
>  	Opt_resv_level,
>  	Opt_dir_resv_level,
>  	Opt_journal_async_commit,
> -	Opt_err_cont,
> -	Opt_err,
>  };
>  
> -static const match_table_t tokens = {
> -	{Opt_barrier, "barrier=%u"},
> -	{Opt_err_panic, "errors=panic"},
> -	{Opt_err_ro, "errors=remount-ro"},
> -	{Opt_intr, "intr"},
> -	{Opt_nointr, "nointr"},
> -	{Opt_hb_none, OCFS2_HB_NONE},
> -	{Opt_hb_local, OCFS2_HB_LOCAL},
> -	{Opt_hb_global, OCFS2_HB_GLOBAL},
> -	{Opt_data_ordered, "data=ordered"},
> -	{Opt_data_writeback, "data=writeback"},
> -	{Opt_atime_quantum, "atime_quantum=%u"},
> -	{Opt_slot, "preferred_slot=%u"},
> -	{Opt_commit, "commit=%u"},
> -	{Opt_localalloc, "localalloc=%d"},
> -	{Opt_localflocks, "localflocks"},
> -	{Opt_stack, "cluster_stack=%s"},
> -	{Opt_user_xattr, "user_xattr"},
> -	{Opt_nouser_xattr, "nouser_xattr"},
> -	{Opt_inode64, "inode64"},
> -	{Opt_acl, "acl"},
> -	{Opt_noacl, "noacl"},
> -	{Opt_usrquota, "usrquota"},
> -	{Opt_grpquota, "grpquota"},
> -	{Opt_coherency_buffered, "coherency=buffered"},
> -	{Opt_coherency_full, "coherency=full"},
> -	{Opt_resv_level, "resv_level=%u"},
> -	{Opt_dir_resv_level, "dir_resv_level=%u"},
> -	{Opt_journal_async_commit, "journal_async_commit"},
> -	{Opt_err_cont, "errors=continue"},
> -	{Opt_err, NULL}
> +static const struct constant_table ocfs2_param_errors[] = {
> +	{"panic",	OCFS2_MOUNT_ERRORS_PANIC},
> +	{"remount-ro",	OCFS2_MOUNT_ERRORS_ROFS},
> +	{"continue",	OCFS2_MOUNT_ERRORS_CONT},
> +	{}
> +};
> +
> +static const struct constant_table ocfs2_param_heartbeat[] = {
> +	{"local",	OCFS2_MOUNT_HB_LOCAL},
> +	{"none",	OCFS2_MOUNT_HB_NONE},
> +	{"global",	OCFS2_MOUNT_HB_GLOBAL},
> +	{}
> +};
> +
> +static const struct constant_table ocfs2_param_data[] = {
> +	{"writeback",	OCFS2_MOUNT_DATA_WRITEBACK},
> +	{"ordered",	0},
> +	{}
> +};
> +
> +static const struct constant_table ocfs2_param_coherency[] = {
> +	{"buffered",	OCFS2_MOUNT_COHERENCY_BUFFERED},
> +	{"full",	0},
> +	{}
> +};
> +
> +static const struct fs_parameter_spec ocfs2_param_spec[] = {
> +	fsparam_u32	("barrier",	Opt_barrier),
> +	fsparam_enum	("errors",	Opt_errors,	ocfs2_param_errors),
> +	fsparam_flag_no	("intr",	Opt_intr),
> +	fsparam_enum	("heartbeat",	Opt_heartbeat,	ocfs2_param_heartbeat),
> +	fsparam_enum	("data",	Opt_data,	ocfs2_param_data),
> +	fsparam_u32	("atime_quantum", Opt_atime_quantum),
> +	fsparam_u32	("preferred_slot", Opt_slot),
> +	fsparam_u32	("commit",	Opt_commit),
> +	fsparam_s32	("localalloc",	Opt_localalloc),
> +	fsparam_flag	("localflocks",	Opt_localflocks),
> +	fsparam_string	("cluster_stack", Opt_stack),
> +	fsparam_flag_no	("user_xattr",	Opt_user_xattr),
> +	fsparam_flag	("inode64",	Opt_inode64),
> +	fsparam_flag_no	("acl",		Opt_acl),
> +	fsparam_flag	("usrquota",	Opt_usrquota),
> +	fsparam_flag	("grpquota",	Opt_grpquota),
> +	fsparam_enum	("coherency",	Opt_coherency,	ocfs2_param_coherency),
> +	fsparam_u32	("resv_level",	Opt_resv_level),
> +	fsparam_u32	("dir_resv_level",	Opt_dir_resv_level),
> +	fsparam_flag	("journal_async_commit", Opt_journal_async_commit),
> +	{}
>  };
>  
>  #ifdef CONFIG_DEBUG_FS
> @@ -600,32 +604,32 @@ static unsigned long long ocfs2_max_file_offset(unsigned int bbits,
>  	return (((unsigned long long)bytes) << bitshift) - trim;
>  }
>  
> -static int ocfs2_remount(struct super_block *sb, int *flags, char *data)
> +static int ocfs2_reconfigure(struct fs_context *fc)
>  {
>  	int incompat_features;
>  	int ret = 0;
> -	struct mount_options parsed_options;
> +	struct mount_options *parsed_options = fc->fs_private;
> +	struct super_block *sb = fc->root->d_sb;
>  	struct ocfs2_super *osb = OCFS2_SB(sb);
>  	u32 tmp;
>  
>  	sync_filesystem(sb);
>  
> -	if (!ocfs2_parse_options(sb, data, &parsed_options, 1) ||
> -	    !ocfs2_check_set_options(sb, &parsed_options)) {
> +	if (!ocfs2_check_set_options(sb, parsed_options)) {
>  		ret = -EINVAL;
>  		goto out;
>  	}
>  
>  	tmp = OCFS2_MOUNT_HB_LOCAL | OCFS2_MOUNT_HB_GLOBAL |
>  		OCFS2_MOUNT_HB_NONE;
> -	if ((osb->s_mount_opt & tmp) != (parsed_options.mount_opt & tmp)) {
> +	if ((osb->s_mount_opt & tmp) != (parsed_options->mount_opt & tmp)) {
>  		ret = -EINVAL;
>  		mlog(ML_ERROR, "Cannot change heartbeat mode on remount\n");
>  		goto out;
>  	}
>  
>  	if ((osb->s_mount_opt & OCFS2_MOUNT_DATA_WRITEBACK) !=
> -	    (parsed_options.mount_opt & OCFS2_MOUNT_DATA_WRITEBACK)) {
> +	    (parsed_options->mount_opt & OCFS2_MOUNT_DATA_WRITEBACK)) {
>  		ret = -EINVAL;
>  		mlog(ML_ERROR, "Cannot change data mode on remount\n");
>  		goto out;
> @@ -634,16 +638,16 @@ static int ocfs2_remount(struct super_block *sb, int *flags, char *data)
>  	/* Probably don't want this on remount; it might
>  	 * mess with other nodes */
>  	if (!(osb->s_mount_opt & OCFS2_MOUNT_INODE64) &&
> -	    (parsed_options.mount_opt & OCFS2_MOUNT_INODE64)) {
> +	    (parsed_options->mount_opt & OCFS2_MOUNT_INODE64)) {
>  		ret = -EINVAL;
>  		mlog(ML_ERROR, "Cannot enable inode64 on remount\n");
>  		goto out;
>  	}
>  
>  	/* We're going to/from readonly mode. */
> -	if ((bool)(*flags & SB_RDONLY) != sb_rdonly(sb)) {
> +	if ((bool)(fc->sb_flags & SB_RDONLY) != sb_rdonly(sb)) {
>  		/* Disable quota accounting before remounting RO */
> -		if (*flags & SB_RDONLY) {
> +		if (fc->sb_flags & SB_RDONLY) {
>  			ret = ocfs2_susp_quotas(osb, 0);
>  			if (ret < 0)
>  				goto out;
> @@ -657,7 +661,7 @@ static int ocfs2_remount(struct super_block *sb, int *flags, char *data)
>  			goto unlock_osb;
>  		}
>  
> -		if (*flags & SB_RDONLY) {
> +		if (fc->sb_flags & SB_RDONLY) {
>  			sb->s_flags |= SB_RDONLY;
>  			osb->osb_flags |= OCFS2_OSB_SOFT_RO;
>  		} else {
> @@ -678,11 +682,11 @@ static int ocfs2_remount(struct super_block *sb, int *flags, char *data)
>  			sb->s_flags &= ~SB_RDONLY;
>  			osb->osb_flags &= ~OCFS2_OSB_SOFT_RO;
>  		}
> -		trace_ocfs2_remount(sb->s_flags, osb->osb_flags, *flags);
> +		trace_ocfs2_remount(sb->s_flags, osb->osb_flags, fc->sb_flags);
>  unlock_osb:
>  		spin_unlock(&osb->osb_lock);
>  		/* Enable quota accounting after remounting RW */
> -		if (!ret && !(*flags & SB_RDONLY)) {
> +		if (!ret && !(fc->sb_flags & SB_RDONLY)) {
>  			if (sb_any_quota_suspended(sb))
>  				ret = ocfs2_susp_quotas(osb, 1);
>  			else
> @@ -701,11 +705,11 @@ static int ocfs2_remount(struct super_block *sb, int *flags, char *data)
>  	if (!ret) {
>  		/* Only save off the new mount options in case of a successful
>  		 * remount. */
> -		osb->s_mount_opt = parsed_options.mount_opt;
> -		osb->s_atime_quantum = parsed_options.atime_quantum;
> -		osb->preferred_slot = parsed_options.slot;
> -		if (parsed_options.commit_interval)
> -			osb->osb_commit_interval = parsed_options.commit_interval;
> +		osb->s_mount_opt = parsed_options->mount_opt;
> +		osb->s_atime_quantum = parsed_options->atime_quantum;
> +		osb->preferred_slot = parsed_options->slot;
> +		if (parsed_options->commit_interval)
> +			osb->osb_commit_interval = parsed_options->commit_interval;
>  
>  		if (!ocfs2_is_hard_readonly(osb))
>  			ocfs2_set_journal_params(osb);
> @@ -966,23 +970,18 @@ static void ocfs2_disable_quotas(struct ocfs2_super *osb)
>  	}
>  }
>  
> -static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
> +static int ocfs2_fill_super(struct super_block *sb, struct fs_context *fc)
>  {
>  	struct dentry *root;
>  	int status, sector_size;
> -	struct mount_options parsed_options;
> +	struct mount_options *parsed_options = fc->fs_private;
>  	struct inode *inode = NULL;
>  	struct ocfs2_super *osb = NULL;
>  	struct buffer_head *bh = NULL;
>  	char nodestr[12];
>  	struct ocfs2_blockcheck_stats stats;
>  
> -	trace_ocfs2_fill_super(sb, data, silent);
> -
> -	if (!ocfs2_parse_options(sb, data, &parsed_options, 0)) {
> -		status = -EINVAL;
> -		goto out;
> -	}
> +	trace_ocfs2_fill_super(sb, fc, fc->sb_flags & SB_SILENT);
>  
>  	/* probe for superblock */
>  	status = ocfs2_sb_probe(sb, &bh, &sector_size, &stats);
> @@ -999,24 +998,24 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
>  
>  	osb = OCFS2_SB(sb);
>  
> -	if (!ocfs2_check_set_options(sb, &parsed_options)) {
> +	if (!ocfs2_check_set_options(sb, parsed_options)) {
>  		status = -EINVAL;
>  		goto out_super;
>  	}
> -	osb->s_mount_opt = parsed_options.mount_opt;
> -	osb->s_atime_quantum = parsed_options.atime_quantum;
> -	osb->preferred_slot = parsed_options.slot;
> -	osb->osb_commit_interval = parsed_options.commit_interval;
> +	osb->s_mount_opt = parsed_options->mount_opt;
> +	osb->s_atime_quantum = parsed_options->atime_quantum;
> +	osb->preferred_slot = parsed_options->slot;
> +	osb->osb_commit_interval = parsed_options->commit_interval;
>  
> -	ocfs2_la_set_sizes(osb, parsed_options.localalloc_opt);
> -	osb->osb_resv_level = parsed_options.resv_level;
> -	osb->osb_dir_resv_level = parsed_options.resv_level;
> -	if (parsed_options.dir_resv_level == -1)
> -		osb->osb_dir_resv_level = parsed_options.resv_level;
> +	ocfs2_la_set_sizes(osb, parsed_options->localalloc_opt);
> +	osb->osb_resv_level = parsed_options->resv_level;
> +	osb->osb_dir_resv_level = parsed_options->resv_level;
> +	if (parsed_options->dir_resv_level == -1)
> +		osb->osb_dir_resv_level = parsed_options->resv_level;
>  	else
> -		osb->osb_dir_resv_level = parsed_options.dir_resv_level;
> +		osb->osb_dir_resv_level = parsed_options->dir_resv_level;
>  
> -	status = ocfs2_verify_userspace_stack(osb, &parsed_options);
> +	status = ocfs2_verify_userspace_stack(osb, parsed_options);
>  	if (status)
>  		goto out_super;
>  
> @@ -1180,27 +1179,72 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
>  	return status;
>  }
>  
> -static struct dentry *ocfs2_mount(struct file_system_type *fs_type,
> -			int flags,
> -			const char *dev_name,
> -			void *data)
> +static int ocfs2_get_tree(struct fs_context *fc)
> +{
> +	return get_tree_bdev(fc, ocfs2_fill_super);
> +}
> +
> +static void ocfs2_free_fc(struct fs_context *fc)
>  {
> -	return mount_bdev(fs_type, flags, dev_name, data, ocfs2_fill_super);
> +	kfree(fc->fs_private);
> +}
> +
> +static const struct fs_context_operations ocfs2_context_ops = {
> +	.parse_param	= ocfs2_parse_param,
> +	.get_tree	= ocfs2_get_tree,
> +	.reconfigure	= ocfs2_reconfigure,
> +	.free		= ocfs2_free_fc,
> +};
> +
> +static int ocfs2_init_fs_context(struct fs_context *fc)
> +{
> +	struct mount_options *mopt;
> +
> +	mopt = kzalloc(sizeof(struct mount_options), GFP_KERNEL);
> +	if (!mopt)
> +		return -EINVAL;
> +
> +	mopt->commit_interval = 0;
> +	mopt->mount_opt = OCFS2_MOUNT_NOINTR;
> +	mopt->atime_quantum = OCFS2_DEFAULT_ATIME_QUANTUM;
> +	mopt->slot = OCFS2_INVALID_SLOT;
> +	mopt->localalloc_opt = -1;
> +	mopt->cluster_stack[0] = '\0';
> +	mopt->resv_level = OCFS2_DEFAULT_RESV_LEVEL;
> +	mopt->dir_resv_level = -1;
> +
> +	fc->fs_private = mopt;
> +	fc->ops = &ocfs2_context_ops;
> +
> +	return 0;
>  }
>  
>  static struct file_system_type ocfs2_fs_type = {
>  	.owner          = THIS_MODULE,
>  	.name           = "ocfs2",
> -	.mount          = ocfs2_mount,
>  	.kill_sb        = kill_block_super,
>  	.fs_flags       = FS_REQUIRES_DEV|FS_RENAME_DOES_D_MOVE,
> -	.next           = NULL
> +	.next           = NULL,
> +	.init_fs_context = ocfs2_init_fs_context,
> +	.parameters	= ocfs2_param_spec,
>  };
>  MODULE_ALIAS_FS("ocfs2");
>  
>  static int ocfs2_check_set_options(struct super_block *sb,
>  				   struct mount_options *options)
>  {
> +	if (options->user_stack == 0) {
> +		u32 tmp;
> +
> +		/* Ensure only one heartbeat mode */
> +		tmp = options->mount_opt & (OCFS2_MOUNT_HB_LOCAL |
> +					    OCFS2_MOUNT_HB_GLOBAL |
> +					    OCFS2_MOUNT_HB_NONE);
> +		if (hweight32(tmp) != 1) {
> +			mlog(ML_ERROR, "Invalid heartbeat mount options\n");
> +			return 0;
> +		}
> +	}
>  	if (options->mount_opt & OCFS2_MOUNT_USRQUOTA &&
>  	    !OCFS2_HAS_RO_COMPAT_FEATURE(sb,
>  					 OCFS2_FEATURE_RO_COMPAT_USRQUOTA)) {
> @@ -1232,241 +1276,142 @@ static int ocfs2_check_set_options(struct super_block *sb,
>  	return 1;
>  }
>  
> -static int ocfs2_parse_options(struct super_block *sb,
> -			       char *options,
> -			       struct mount_options *mopt,
> -			       int is_remount)
> +static int ocfs2_parse_param(struct fs_context *fc, struct fs_parameter *param)
>  {
> -	int status, user_stack = 0;
> -	char *p;
> -	u32 tmp;
> -	int token, option;
> -	substring_t args[MAX_OPT_ARGS];
> -
> -	trace_ocfs2_parse_options(is_remount, options ? options : "(none)");
> -
> -	mopt->commit_interval = 0;
> -	mopt->mount_opt = OCFS2_MOUNT_NOINTR;
> -	mopt->atime_quantum = OCFS2_DEFAULT_ATIME_QUANTUM;
> -	mopt->slot = OCFS2_INVALID_SLOT;
> -	mopt->localalloc_opt = -1;
> -	mopt->cluster_stack[0] = '\0';
> -	mopt->resv_level = OCFS2_DEFAULT_RESV_LEVEL;
> -	mopt->dir_resv_level = -1;
> -
> -	if (!options) {
> -		status = 1;
> -		goto bail;
> -	}
> -
> -	while ((p = strsep(&options, ",")) != NULL) {
> -		if (!*p)
> -			continue;
> -
> -		token = match_token(p, tokens, args);
> -		switch (token) {
> -		case Opt_hb_local:
> -			mopt->mount_opt |= OCFS2_MOUNT_HB_LOCAL;
> -			break;
> -		case Opt_hb_none:
> -			mopt->mount_opt |= OCFS2_MOUNT_HB_NONE;
> -			break;
> -		case Opt_hb_global:
> -			mopt->mount_opt |= OCFS2_MOUNT_HB_GLOBAL;
> -			break;
> -		case Opt_barrier:
> -			if (match_int(&args[0], &option)) {
> -				status = 0;
> -				goto bail;
> -			}
> -			if (option)
> -				mopt->mount_opt |= OCFS2_MOUNT_BARRIER;
> -			else
> -				mopt->mount_opt &= ~OCFS2_MOUNT_BARRIER;
> -			break;
> -		case Opt_intr:
> -			mopt->mount_opt &= ~OCFS2_MOUNT_NOINTR;
> -			break;
> -		case Opt_nointr:
> +	struct fs_parse_result result;
> +	int opt;
> +	struct mount_options *mopt = fc->fs_private;
> +	bool is_remount = (fc->purpose & FS_CONTEXT_FOR_RECONFIGURE);
> +
> +	trace_ocfs2_parse_options(is_remount, param->key);
> +
> +	opt = fs_parse(fc, ocfs2_param_spec, param, &result);
> +	if (opt < 0)
> +		return opt;
> +
> +	switch (opt) {
> +	case Opt_heartbeat:
> +		mopt->mount_opt |= result.uint_32;
> +		break;
> +	case Opt_barrier:
> +		if (result.uint_32)
> +			mopt->mount_opt |= OCFS2_MOUNT_BARRIER;
> +		else
> +			mopt->mount_opt &= ~OCFS2_MOUNT_BARRIER;
> +		break;
> +	case Opt_intr:
> +		if (result.negated)
>  			mopt->mount_opt |= OCFS2_MOUNT_NOINTR;
> -			break;
> -		case Opt_err_panic:
> -			mopt->mount_opt &= ~OCFS2_MOUNT_ERRORS_CONT;
> -			mopt->mount_opt &= ~OCFS2_MOUNT_ERRORS_ROFS;
> -			mopt->mount_opt |= OCFS2_MOUNT_ERRORS_PANIC;
> -			break;
> -		case Opt_err_ro:
> -			mopt->mount_opt &= ~OCFS2_MOUNT_ERRORS_CONT;
> -			mopt->mount_opt &= ~OCFS2_MOUNT_ERRORS_PANIC;
> -			mopt->mount_opt |= OCFS2_MOUNT_ERRORS_ROFS;
> -			break;
> -		case Opt_err_cont:
> -			mopt->mount_opt &= ~OCFS2_MOUNT_ERRORS_ROFS;
> -			mopt->mount_opt &= ~OCFS2_MOUNT_ERRORS_PANIC;
> -			mopt->mount_opt |= OCFS2_MOUNT_ERRORS_CONT;
> -			break;
> -		case Opt_data_ordered:
> -			mopt->mount_opt &= ~OCFS2_MOUNT_DATA_WRITEBACK;
> -			break;
> -		case Opt_data_writeback:
> -			mopt->mount_opt |= OCFS2_MOUNT_DATA_WRITEBACK;
> -			break;
> -		case Opt_user_xattr:
> -			mopt->mount_opt &= ~OCFS2_MOUNT_NOUSERXATTR;
> -			break;
> -		case Opt_nouser_xattr:
> +		else
> +			mopt->mount_opt &= ~OCFS2_MOUNT_NOINTR;
> +		break;
> +	case Opt_errors:
> +		mopt->mount_opt &= ~(OCFS2_MOUNT_ERRORS_CONT |
> +				     OCFS2_MOUNT_ERRORS_ROFS |
> +				     OCFS2_MOUNT_ERRORS_PANIC);
> +		mopt->mount_opt |= result.uint_32;
> +		break;
> +	case Opt_data:
> +		mopt->mount_opt &= ~OCFS2_MOUNT_DATA_WRITEBACK;
> +		mopt->mount_opt |= result.uint_32;
> +		break;
> +	case Opt_user_xattr:
> +		if (result.negated)
>  			mopt->mount_opt |= OCFS2_MOUNT_NOUSERXATTR;
> -			break;
> -		case Opt_atime_quantum:
> -			if (match_int(&args[0], &option)) {
> -				status = 0;
> -				goto bail;
> -			}
> -			if (option >= 0)
> -				mopt->atime_quantum = option;
> -			break;
> -		case Opt_slot:
> -			if (match_int(&args[0], &option)) {
> -				status = 0;
> -				goto bail;
> -			}
> -			if (option)
> -				mopt->slot = (u16)option;
> -			break;
> -		case Opt_commit:
> -			if (match_int(&args[0], &option)) {
> -				status = 0;
> -				goto bail;
> -			}
> -			if (option < 0)
> -				return 0;
> -			if (option == 0)
> -				option = JBD2_DEFAULT_MAX_COMMIT_AGE;
> -			mopt->commit_interval = HZ * option;
> -			break;
> -		case Opt_localalloc:
> -			if (match_int(&args[0], &option)) {
> -				status = 0;
> -				goto bail;
> -			}
> -			if (option >= 0)
> -				mopt->localalloc_opt = option;
> -			break;
> -		case Opt_localflocks:
> -			/*
> -			 * Changing this during remount could race
> -			 * flock() requests, or "unbalance" existing
> -			 * ones (e.g., a lock is taken in one mode but
> -			 * dropped in the other). If users care enough
> -			 * to flip locking modes during remount, we
> -			 * could add a "local" flag to individual
> -			 * flock structures for proper tracking of
> -			 * state.
> -			 */
> -			if (!is_remount)
> -				mopt->mount_opt |= OCFS2_MOUNT_LOCALFLOCKS;
> -			break;
> -		case Opt_stack:
> -			/* Check both that the option we were passed
> -			 * is of the right length and that it is a proper
> -			 * string of the right length.
> -			 */
> -			if (((args[0].to - args[0].from) !=
> -			     OCFS2_STACK_LABEL_LEN) ||
> -			    (strnlen(args[0].from,
> -				     OCFS2_STACK_LABEL_LEN) !=
> -			     OCFS2_STACK_LABEL_LEN)) {
> -				mlog(ML_ERROR,
> -				     "Invalid cluster_stack option\n");
> -				status = 0;
> -				goto bail;
> -			}
> -			memcpy(mopt->cluster_stack, args[0].from,
> -			       OCFS2_STACK_LABEL_LEN);
> -			mopt->cluster_stack[OCFS2_STACK_LABEL_LEN] = '\0';
> -			/*
> -			 * Open code the memcmp here as we don't have
> -			 * an osb to pass to
> -			 * ocfs2_userspace_stack().
> -			 */
> -			if (memcmp(mopt->cluster_stack,
> -				   OCFS2_CLASSIC_CLUSTER_STACK,
> -				   OCFS2_STACK_LABEL_LEN))
> -				user_stack = 1;
> -			break;
> -		case Opt_inode64:
> -			mopt->mount_opt |= OCFS2_MOUNT_INODE64;
> -			break;
> -		case Opt_usrquota:
> -			mopt->mount_opt |= OCFS2_MOUNT_USRQUOTA;
> -			break;
> -		case Opt_grpquota:
> -			mopt->mount_opt |= OCFS2_MOUNT_GRPQUOTA;
> -			break;
> -		case Opt_coherency_buffered:
> -			mopt->mount_opt |= OCFS2_MOUNT_COHERENCY_BUFFERED;
> -			break;
> -		case Opt_coherency_full:
> -			mopt->mount_opt &= ~OCFS2_MOUNT_COHERENCY_BUFFERED;
> -			break;
> -		case Opt_acl:
> -			mopt->mount_opt |= OCFS2_MOUNT_POSIX_ACL;
> -			mopt->mount_opt &= ~OCFS2_MOUNT_NO_POSIX_ACL;
> -			break;
> -		case Opt_noacl:
> +		else
> +			mopt->mount_opt &= ~OCFS2_MOUNT_NOUSERXATTR;
> +		break;
> +	case Opt_atime_quantum:
> +		mopt->atime_quantum = result.uint_32;
> +		break;
> +	case Opt_slot:
> +		if (result.uint_32)
> +			mopt->slot = (u16)result.uint_32;
> +		break;
> +	case Opt_commit:
> +		if (result.uint_32 == 0)
> +			mopt->commit_interval = HZ * JBD2_DEFAULT_MAX_COMMIT_AGE;
> +		else
> +			mopt->commit_interval = HZ * result.uint_32;
> +		break;
> +	case Opt_localalloc:
> +		if (result.int_32 >= 0)
> +			mopt->localalloc_opt = result.int_32;
> +		break;
> +	case Opt_localflocks:
> +		/*
> +		 * Changing this during remount could race flock() requests, or
> +		 * "unbalance" existing ones (e.g., a lock is taken in one mode
> +		 * but dropped in the other). If users care enough to flip
> +		 * locking modes during remount, we could add a "local" flag to
> +		 * individual flock structures for proper tracking of state.
> +		 */
> +		if (!is_remount)
> +			mopt->mount_opt |= OCFS2_MOUNT_LOCALFLOCKS;
> +		break;
> +	case Opt_stack:
> +		/* Check both that the option we were passed is of the right
> +		 * length and that it is a proper string of the right length.
> +		 */
> +		if (strlen(param->string) != OCFS2_STACK_LABEL_LEN) {
> +			mlog(ML_ERROR, "Invalid cluster_stack option\n");
> +			return -EINVAL;
> +		}
> +		memcpy(mopt->cluster_stack, param->string, OCFS2_STACK_LABEL_LEN);
> +		mopt->cluster_stack[OCFS2_STACK_LABEL_LEN] = '\0';
> +		/*
> +		 * Open code the memcmp here as we don't have an osb to pass
> +		 * to ocfs2_userspace_stack().
> +		 */
> +		if (memcmp(mopt->cluster_stack,
> +			   OCFS2_CLASSIC_CLUSTER_STACK,
> +			   OCFS2_STACK_LABEL_LEN))
> +			mopt->user_stack = 1;
> +		break;
> +	case Opt_inode64:
> +		mopt->mount_opt |= OCFS2_MOUNT_INODE64;
> +		break;
> +	case Opt_usrquota:
> +		mopt->mount_opt |= OCFS2_MOUNT_USRQUOTA;
> +		break;
> +	case Opt_grpquota:
> +		mopt->mount_opt |= OCFS2_MOUNT_GRPQUOTA;
> +		break;
> +	case Opt_coherency:
> +		mopt->mount_opt &= ~OCFS2_MOUNT_COHERENCY_BUFFERED;
> +		mopt->mount_opt |= result.uint_32;
> +		break;
> +	case Opt_acl:
> +		if (result.negated) {
>  			mopt->mount_opt |= OCFS2_MOUNT_NO_POSIX_ACL;
>  			mopt->mount_opt &= ~OCFS2_MOUNT_POSIX_ACL;
> +		} else {
> +			mopt->mount_opt |= OCFS2_MOUNT_POSIX_ACL;
> +			mopt->mount_opt &= ~OCFS2_MOUNT_NO_POSIX_ACL;
> +		}
> +		break;
> +	case Opt_resv_level:
> +		if (is_remount)
>  			break;
> -		case Opt_resv_level:
> -			if (is_remount)
> -				break;
> -			if (match_int(&args[0], &option)) {
> -				status = 0;
> -				goto bail;
> -			}
> -			if (option >= OCFS2_MIN_RESV_LEVEL &&
> -			    option < OCFS2_MAX_RESV_LEVEL)
> -				mopt->resv_level = option;
> -			break;
> -		case Opt_dir_resv_level:
> -			if (is_remount)
> -				break;
> -			if (match_int(&args[0], &option)) {
> -				status = 0;
> -				goto bail;
> -			}
> -			if (option >= OCFS2_MIN_RESV_LEVEL &&
> -			    option < OCFS2_MAX_RESV_LEVEL)
> -				mopt->dir_resv_level = option;
> -			break;
> -		case Opt_journal_async_commit:
> -			mopt->mount_opt |= OCFS2_MOUNT_JOURNAL_ASYNC_COMMIT;
> +		if (result.uint_32 >= OCFS2_MIN_RESV_LEVEL &&
> +		    result.uint_32 < OCFS2_MAX_RESV_LEVEL)
> +			mopt->resv_level = result.uint_32;
> +		break;
> +	case Opt_dir_resv_level:
> +		if (is_remount)
>  			break;
> -		default:
> -			mlog(ML_ERROR,
> -			     "Unrecognized mount option \"%s\" "
> -			     "or missing value\n", p);
> -			status = 0;
> -			goto bail;
> -		}
> -	}
> -
> -	if (user_stack == 0) {
> -		/* Ensure only one heartbeat mode */
> -		tmp = mopt->mount_opt & (OCFS2_MOUNT_HB_LOCAL |
> -					 OCFS2_MOUNT_HB_GLOBAL |
> -					 OCFS2_MOUNT_HB_NONE);
> -		if (hweight32(tmp) != 1) {
> -			mlog(ML_ERROR, "Invalid heartbeat mount options\n");
> -			status = 0;
> -			goto bail;
> -		}
> +		if (result.uint_32 >= OCFS2_MIN_RESV_LEVEL &&
> +		    result.uint_32 < OCFS2_MAX_RESV_LEVEL)
> +			mopt->dir_resv_level = result.uint_32;
> +		break;
> +	case Opt_journal_async_commit:
> +		mopt->mount_opt |= OCFS2_MOUNT_JOURNAL_ASYNC_COMMIT;
> +		break;
> +	default:
> +		return -EINVAL;
>  	}
>  
> -	status = 1;
> -
> -bail:
> -	return status;
> +	return 0;
>  }
>  
>  static int ocfs2_show_options(struct seq_file *s, struct dentry *root)
> -- 
> 2.46.0
> 
>
Joseph Qi Dec. 4, 2024, 12:01 p.m. UTC | #2
On 10/28/24 10:41 PM, Eric Sandeen wrote:
> Convert ocfs2 to the new mount API.
> 
> Signed-off-by: Eric Sandeen <sandeen@redhat.com>

Acked-by: Joseph Qi <joseph.qi@linux.alibaba.com>

> ---
>  fs/ocfs2/ocfs2_trace.h |  20 +-
>  fs/ocfs2/super.c       | 589 +++++++++++++++++++----------------------
>  2 files changed, 277 insertions(+), 332 deletions(-)
> 
> diff --git a/fs/ocfs2/ocfs2_trace.h b/fs/ocfs2/ocfs2_trace.h
> index 0511c69c9fde..54ed1495de9a 100644
> --- a/fs/ocfs2/ocfs2_trace.h
> +++ b/fs/ocfs2/ocfs2_trace.h
> @@ -1658,34 +1658,34 @@ TRACE_EVENT(ocfs2_remount,
>  );
>  
>  TRACE_EVENT(ocfs2_fill_super,
> -	TP_PROTO(void *sb, void *data, int silent),
> -	TP_ARGS(sb, data, silent),
> +	TP_PROTO(void *sb, void *fc, int silent),
> +	TP_ARGS(sb, fc, silent),
>  	TP_STRUCT__entry(
>  		__field(void *, sb)
> -		__field(void *, data)
> +		__field(void *, fc)
>  		__field(int, silent)
>  	),
>  	TP_fast_assign(
>  		__entry->sb = sb;
> -		__entry->data = data;
> +		__entry->fc = fc;
>  		__entry->silent = silent;
>  	),
>  	TP_printk("%p %p %d", __entry->sb,
> -		  __entry->data, __entry->silent)
> +		  __entry->fc, __entry->silent)
>  );
>  
>  TRACE_EVENT(ocfs2_parse_options,
> -	TP_PROTO(int is_remount, char *options),
> -	TP_ARGS(is_remount, options),
> +	TP_PROTO(int is_remount, const char *option),
> +	TP_ARGS(is_remount, option),
>  	TP_STRUCT__entry(
>  		__field(int, is_remount)
> -		__string(options, options)
> +		__string(option, option)
>  	),
>  	TP_fast_assign(
>  		__entry->is_remount = is_remount;
> -		__assign_str(options);
> +		__assign_str(option);
>  	),
> -	TP_printk("%d %s", __entry->is_remount, __get_str(options))
> +	TP_printk("%d %s", __entry->is_remount, __get_str(option))
>  );
>  
>  DEFINE_OCFS2_POINTER_EVENT(ocfs2_put_super);
> diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c
> index 3d404624bb96..110ffc4bb840 100644
> --- a/fs/ocfs2/super.c
> +++ b/fs/ocfs2/super.c
> @@ -19,10 +19,10 @@
>  #include <linux/blkdev.h>
>  #include <linux/socket.h>
>  #include <linux/inet.h>
> -#include <linux/parser.h>
> +#include <linux/fs_parser.h>
> +#include <linux/fs_context.h>
>  #include <linux/crc32.h>
>  #include <linux/debugfs.h>
> -#include <linux/mount.h>
>  #include <linux/seq_file.h>
>  #include <linux/quotaops.h>
>  #include <linux/signal.h>
> @@ -80,17 +80,15 @@ struct mount_options
>  	unsigned int	resv_level;
>  	int		dir_resv_level;
>  	char		cluster_stack[OCFS2_STACK_LABEL_LEN + 1];
> +	bool		user_stack;
>  };
>  
> -static int ocfs2_parse_options(struct super_block *sb, char *options,
> -			       struct mount_options *mopt,
> -			       int is_remount);
> +static int ocfs2_parse_param(struct fs_context *fc, struct fs_parameter *param);
>  static int ocfs2_check_set_options(struct super_block *sb,
>  				   struct mount_options *options);
>  static int ocfs2_show_options(struct seq_file *s, struct dentry *root);
>  static void ocfs2_put_super(struct super_block *sb);
>  static int ocfs2_mount_volume(struct super_block *sb);
> -static int ocfs2_remount(struct super_block *sb, int *flags, char *data);
>  static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err);
>  static int ocfs2_initialize_mem_caches(void);
>  static void ocfs2_free_mem_caches(void);
> @@ -135,7 +133,6 @@ static const struct super_operations ocfs2_sops = {
>  	.evict_inode	= ocfs2_evict_inode,
>  	.sync_fs	= ocfs2_sync_fs,
>  	.put_super	= ocfs2_put_super,
> -	.remount_fs	= ocfs2_remount,
>  	.show_options   = ocfs2_show_options,
>  	.quota_read	= ocfs2_quota_read,
>  	.quota_write	= ocfs2_quota_write,
> @@ -144,15 +141,10 @@ static const struct super_operations ocfs2_sops = {
>  
>  enum {
>  	Opt_barrier,
> -	Opt_err_panic,
> -	Opt_err_ro,
> +	Opt_errors,
>  	Opt_intr,
> -	Opt_nointr,
> -	Opt_hb_none,
> -	Opt_hb_local,
> -	Opt_hb_global,
> -	Opt_data_ordered,
> -	Opt_data_writeback,
> +	Opt_heartbeat,
> +	Opt_data,
>  	Opt_atime_quantum,
>  	Opt_slot,
>  	Opt_commit,
> @@ -160,52 +152,64 @@ enum {
>  	Opt_localflocks,
>  	Opt_stack,
>  	Opt_user_xattr,
> -	Opt_nouser_xattr,
>  	Opt_inode64,
>  	Opt_acl,
> -	Opt_noacl,
>  	Opt_usrquota,
>  	Opt_grpquota,
> -	Opt_coherency_buffered,
> -	Opt_coherency_full,
> +	Opt_coherency,
>  	Opt_resv_level,
>  	Opt_dir_resv_level,
>  	Opt_journal_async_commit,
> -	Opt_err_cont,
> -	Opt_err,
>  };
>  
> -static const match_table_t tokens = {
> -	{Opt_barrier, "barrier=%u"},
> -	{Opt_err_panic, "errors=panic"},
> -	{Opt_err_ro, "errors=remount-ro"},
> -	{Opt_intr, "intr"},
> -	{Opt_nointr, "nointr"},
> -	{Opt_hb_none, OCFS2_HB_NONE},
> -	{Opt_hb_local, OCFS2_HB_LOCAL},
> -	{Opt_hb_global, OCFS2_HB_GLOBAL},
> -	{Opt_data_ordered, "data=ordered"},
> -	{Opt_data_writeback, "data=writeback"},
> -	{Opt_atime_quantum, "atime_quantum=%u"},
> -	{Opt_slot, "preferred_slot=%u"},
> -	{Opt_commit, "commit=%u"},
> -	{Opt_localalloc, "localalloc=%d"},
> -	{Opt_localflocks, "localflocks"},
> -	{Opt_stack, "cluster_stack=%s"},
> -	{Opt_user_xattr, "user_xattr"},
> -	{Opt_nouser_xattr, "nouser_xattr"},
> -	{Opt_inode64, "inode64"},
> -	{Opt_acl, "acl"},
> -	{Opt_noacl, "noacl"},
> -	{Opt_usrquota, "usrquota"},
> -	{Opt_grpquota, "grpquota"},
> -	{Opt_coherency_buffered, "coherency=buffered"},
> -	{Opt_coherency_full, "coherency=full"},
> -	{Opt_resv_level, "resv_level=%u"},
> -	{Opt_dir_resv_level, "dir_resv_level=%u"},
> -	{Opt_journal_async_commit, "journal_async_commit"},
> -	{Opt_err_cont, "errors=continue"},
> -	{Opt_err, NULL}
> +static const struct constant_table ocfs2_param_errors[] = {
> +	{"panic",	OCFS2_MOUNT_ERRORS_PANIC},
> +	{"remount-ro",	OCFS2_MOUNT_ERRORS_ROFS},
> +	{"continue",	OCFS2_MOUNT_ERRORS_CONT},
> +	{}
> +};
> +
> +static const struct constant_table ocfs2_param_heartbeat[] = {
> +	{"local",	OCFS2_MOUNT_HB_LOCAL},
> +	{"none",	OCFS2_MOUNT_HB_NONE},
> +	{"global",	OCFS2_MOUNT_HB_GLOBAL},
> +	{}
> +};
> +
> +static const struct constant_table ocfs2_param_data[] = {
> +	{"writeback",	OCFS2_MOUNT_DATA_WRITEBACK},
> +	{"ordered",	0},
> +	{}
> +};
> +
> +static const struct constant_table ocfs2_param_coherency[] = {
> +	{"buffered",	OCFS2_MOUNT_COHERENCY_BUFFERED},
> +	{"full",	0},
> +	{}
> +};
> +
> +static const struct fs_parameter_spec ocfs2_param_spec[] = {
> +	fsparam_u32	("barrier",	Opt_barrier),
> +	fsparam_enum	("errors",	Opt_errors,	ocfs2_param_errors),
> +	fsparam_flag_no	("intr",	Opt_intr),
> +	fsparam_enum	("heartbeat",	Opt_heartbeat,	ocfs2_param_heartbeat),
> +	fsparam_enum	("data",	Opt_data,	ocfs2_param_data),
> +	fsparam_u32	("atime_quantum", Opt_atime_quantum),
> +	fsparam_u32	("preferred_slot", Opt_slot),
> +	fsparam_u32	("commit",	Opt_commit),
> +	fsparam_s32	("localalloc",	Opt_localalloc),
> +	fsparam_flag	("localflocks",	Opt_localflocks),
> +	fsparam_string	("cluster_stack", Opt_stack),
> +	fsparam_flag_no	("user_xattr",	Opt_user_xattr),
> +	fsparam_flag	("inode64",	Opt_inode64),
> +	fsparam_flag_no	("acl",		Opt_acl),
> +	fsparam_flag	("usrquota",	Opt_usrquota),
> +	fsparam_flag	("grpquota",	Opt_grpquota),
> +	fsparam_enum	("coherency",	Opt_coherency,	ocfs2_param_coherency),
> +	fsparam_u32	("resv_level",	Opt_resv_level),
> +	fsparam_u32	("dir_resv_level",	Opt_dir_resv_level),
> +	fsparam_flag	("journal_async_commit", Opt_journal_async_commit),
> +	{}
>  };
>  
>  #ifdef CONFIG_DEBUG_FS
> @@ -600,32 +604,32 @@ static unsigned long long ocfs2_max_file_offset(unsigned int bbits,
>  	return (((unsigned long long)bytes) << bitshift) - trim;
>  }
>  
> -static int ocfs2_remount(struct super_block *sb, int *flags, char *data)
> +static int ocfs2_reconfigure(struct fs_context *fc)
>  {
>  	int incompat_features;
>  	int ret = 0;
> -	struct mount_options parsed_options;
> +	struct mount_options *parsed_options = fc->fs_private;
> +	struct super_block *sb = fc->root->d_sb;
>  	struct ocfs2_super *osb = OCFS2_SB(sb);
>  	u32 tmp;
>  
>  	sync_filesystem(sb);
>  
> -	if (!ocfs2_parse_options(sb, data, &parsed_options, 1) ||
> -	    !ocfs2_check_set_options(sb, &parsed_options)) {
> +	if (!ocfs2_check_set_options(sb, parsed_options)) {
>  		ret = -EINVAL;
>  		goto out;
>  	}
>  
>  	tmp = OCFS2_MOUNT_HB_LOCAL | OCFS2_MOUNT_HB_GLOBAL |
>  		OCFS2_MOUNT_HB_NONE;
> -	if ((osb->s_mount_opt & tmp) != (parsed_options.mount_opt & tmp)) {
> +	if ((osb->s_mount_opt & tmp) != (parsed_options->mount_opt & tmp)) {
>  		ret = -EINVAL;
>  		mlog(ML_ERROR, "Cannot change heartbeat mode on remount\n");
>  		goto out;
>  	}
>  
>  	if ((osb->s_mount_opt & OCFS2_MOUNT_DATA_WRITEBACK) !=
> -	    (parsed_options.mount_opt & OCFS2_MOUNT_DATA_WRITEBACK)) {
> +	    (parsed_options->mount_opt & OCFS2_MOUNT_DATA_WRITEBACK)) {
>  		ret = -EINVAL;
>  		mlog(ML_ERROR, "Cannot change data mode on remount\n");
>  		goto out;
> @@ -634,16 +638,16 @@ static int ocfs2_remount(struct super_block *sb, int *flags, char *data)
>  	/* Probably don't want this on remount; it might
>  	 * mess with other nodes */
>  	if (!(osb->s_mount_opt & OCFS2_MOUNT_INODE64) &&
> -	    (parsed_options.mount_opt & OCFS2_MOUNT_INODE64)) {
> +	    (parsed_options->mount_opt & OCFS2_MOUNT_INODE64)) {
>  		ret = -EINVAL;
>  		mlog(ML_ERROR, "Cannot enable inode64 on remount\n");
>  		goto out;
>  	}
>  
>  	/* We're going to/from readonly mode. */
> -	if ((bool)(*flags & SB_RDONLY) != sb_rdonly(sb)) {
> +	if ((bool)(fc->sb_flags & SB_RDONLY) != sb_rdonly(sb)) {
>  		/* Disable quota accounting before remounting RO */
> -		if (*flags & SB_RDONLY) {
> +		if (fc->sb_flags & SB_RDONLY) {
>  			ret = ocfs2_susp_quotas(osb, 0);
>  			if (ret < 0)
>  				goto out;
> @@ -657,7 +661,7 @@ static int ocfs2_remount(struct super_block *sb, int *flags, char *data)
>  			goto unlock_osb;
>  		}
>  
> -		if (*flags & SB_RDONLY) {
> +		if (fc->sb_flags & SB_RDONLY) {
>  			sb->s_flags |= SB_RDONLY;
>  			osb->osb_flags |= OCFS2_OSB_SOFT_RO;
>  		} else {
> @@ -678,11 +682,11 @@ static int ocfs2_remount(struct super_block *sb, int *flags, char *data)
>  			sb->s_flags &= ~SB_RDONLY;
>  			osb->osb_flags &= ~OCFS2_OSB_SOFT_RO;
>  		}
> -		trace_ocfs2_remount(sb->s_flags, osb->osb_flags, *flags);
> +		trace_ocfs2_remount(sb->s_flags, osb->osb_flags, fc->sb_flags);
>  unlock_osb:
>  		spin_unlock(&osb->osb_lock);
>  		/* Enable quota accounting after remounting RW */
> -		if (!ret && !(*flags & SB_RDONLY)) {
> +		if (!ret && !(fc->sb_flags & SB_RDONLY)) {
>  			if (sb_any_quota_suspended(sb))
>  				ret = ocfs2_susp_quotas(osb, 1);
>  			else
> @@ -701,11 +705,11 @@ static int ocfs2_remount(struct super_block *sb, int *flags, char *data)
>  	if (!ret) {
>  		/* Only save off the new mount options in case of a successful
>  		 * remount. */
> -		osb->s_mount_opt = parsed_options.mount_opt;
> -		osb->s_atime_quantum = parsed_options.atime_quantum;
> -		osb->preferred_slot = parsed_options.slot;
> -		if (parsed_options.commit_interval)
> -			osb->osb_commit_interval = parsed_options.commit_interval;
> +		osb->s_mount_opt = parsed_options->mount_opt;
> +		osb->s_atime_quantum = parsed_options->atime_quantum;
> +		osb->preferred_slot = parsed_options->slot;
> +		if (parsed_options->commit_interval)
> +			osb->osb_commit_interval = parsed_options->commit_interval;
>  
>  		if (!ocfs2_is_hard_readonly(osb))
>  			ocfs2_set_journal_params(osb);
> @@ -966,23 +970,18 @@ static void ocfs2_disable_quotas(struct ocfs2_super *osb)
>  	}
>  }
>  
> -static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
> +static int ocfs2_fill_super(struct super_block *sb, struct fs_context *fc)
>  {
>  	struct dentry *root;
>  	int status, sector_size;
> -	struct mount_options parsed_options;
> +	struct mount_options *parsed_options = fc->fs_private;
>  	struct inode *inode = NULL;
>  	struct ocfs2_super *osb = NULL;
>  	struct buffer_head *bh = NULL;
>  	char nodestr[12];
>  	struct ocfs2_blockcheck_stats stats;
>  
> -	trace_ocfs2_fill_super(sb, data, silent);
> -
> -	if (!ocfs2_parse_options(sb, data, &parsed_options, 0)) {
> -		status = -EINVAL;
> -		goto out;
> -	}
> +	trace_ocfs2_fill_super(sb, fc, fc->sb_flags & SB_SILENT);
>  
>  	/* probe for superblock */
>  	status = ocfs2_sb_probe(sb, &bh, &sector_size, &stats);
> @@ -999,24 +998,24 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
>  
>  	osb = OCFS2_SB(sb);
>  
> -	if (!ocfs2_check_set_options(sb, &parsed_options)) {
> +	if (!ocfs2_check_set_options(sb, parsed_options)) {
>  		status = -EINVAL;
>  		goto out_super;
>  	}
> -	osb->s_mount_opt = parsed_options.mount_opt;
> -	osb->s_atime_quantum = parsed_options.atime_quantum;
> -	osb->preferred_slot = parsed_options.slot;
> -	osb->osb_commit_interval = parsed_options.commit_interval;
> +	osb->s_mount_opt = parsed_options->mount_opt;
> +	osb->s_atime_quantum = parsed_options->atime_quantum;
> +	osb->preferred_slot = parsed_options->slot;
> +	osb->osb_commit_interval = parsed_options->commit_interval;
>  
> -	ocfs2_la_set_sizes(osb, parsed_options.localalloc_opt);
> -	osb->osb_resv_level = parsed_options.resv_level;
> -	osb->osb_dir_resv_level = parsed_options.resv_level;
> -	if (parsed_options.dir_resv_level == -1)
> -		osb->osb_dir_resv_level = parsed_options.resv_level;
> +	ocfs2_la_set_sizes(osb, parsed_options->localalloc_opt);
> +	osb->osb_resv_level = parsed_options->resv_level;
> +	osb->osb_dir_resv_level = parsed_options->resv_level;
> +	if (parsed_options->dir_resv_level == -1)
> +		osb->osb_dir_resv_level = parsed_options->resv_level;
>  	else
> -		osb->osb_dir_resv_level = parsed_options.dir_resv_level;
> +		osb->osb_dir_resv_level = parsed_options->dir_resv_level;
>  
> -	status = ocfs2_verify_userspace_stack(osb, &parsed_options);
> +	status = ocfs2_verify_userspace_stack(osb, parsed_options);
>  	if (status)
>  		goto out_super;
>  
> @@ -1180,27 +1179,72 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
>  	return status;
>  }
>  
> -static struct dentry *ocfs2_mount(struct file_system_type *fs_type,
> -			int flags,
> -			const char *dev_name,
> -			void *data)
> +static int ocfs2_get_tree(struct fs_context *fc)
> +{
> +	return get_tree_bdev(fc, ocfs2_fill_super);
> +}
> +
> +static void ocfs2_free_fc(struct fs_context *fc)
>  {
> -	return mount_bdev(fs_type, flags, dev_name, data, ocfs2_fill_super);
> +	kfree(fc->fs_private);
> +}
> +
> +static const struct fs_context_operations ocfs2_context_ops = {
> +	.parse_param	= ocfs2_parse_param,
> +	.get_tree	= ocfs2_get_tree,
> +	.reconfigure	= ocfs2_reconfigure,
> +	.free		= ocfs2_free_fc,
> +};
> +
> +static int ocfs2_init_fs_context(struct fs_context *fc)
> +{
> +	struct mount_options *mopt;
> +
> +	mopt = kzalloc(sizeof(struct mount_options), GFP_KERNEL);
> +	if (!mopt)
> +		return -EINVAL;
> +
> +	mopt->commit_interval = 0;
> +	mopt->mount_opt = OCFS2_MOUNT_NOINTR;
> +	mopt->atime_quantum = OCFS2_DEFAULT_ATIME_QUANTUM;
> +	mopt->slot = OCFS2_INVALID_SLOT;
> +	mopt->localalloc_opt = -1;
> +	mopt->cluster_stack[0] = '\0';
> +	mopt->resv_level = OCFS2_DEFAULT_RESV_LEVEL;
> +	mopt->dir_resv_level = -1;
> +
> +	fc->fs_private = mopt;
> +	fc->ops = &ocfs2_context_ops;
> +
> +	return 0;
>  }
>  
>  static struct file_system_type ocfs2_fs_type = {
>  	.owner          = THIS_MODULE,
>  	.name           = "ocfs2",
> -	.mount          = ocfs2_mount,
>  	.kill_sb        = kill_block_super,
>  	.fs_flags       = FS_REQUIRES_DEV|FS_RENAME_DOES_D_MOVE,
> -	.next           = NULL
> +	.next           = NULL,
> +	.init_fs_context = ocfs2_init_fs_context,
> +	.parameters	= ocfs2_param_spec,
>  };
>  MODULE_ALIAS_FS("ocfs2");
>  
>  static int ocfs2_check_set_options(struct super_block *sb,
>  				   struct mount_options *options)
>  {
> +	if (options->user_stack == 0) {
> +		u32 tmp;
> +
> +		/* Ensure only one heartbeat mode */
> +		tmp = options->mount_opt & (OCFS2_MOUNT_HB_LOCAL |
> +					    OCFS2_MOUNT_HB_GLOBAL |
> +					    OCFS2_MOUNT_HB_NONE);
> +		if (hweight32(tmp) != 1) {
> +			mlog(ML_ERROR, "Invalid heartbeat mount options\n");
> +			return 0;
> +		}
> +	}
>  	if (options->mount_opt & OCFS2_MOUNT_USRQUOTA &&
>  	    !OCFS2_HAS_RO_COMPAT_FEATURE(sb,
>  					 OCFS2_FEATURE_RO_COMPAT_USRQUOTA)) {
> @@ -1232,241 +1276,142 @@ static int ocfs2_check_set_options(struct super_block *sb,
>  	return 1;
>  }
>  
> -static int ocfs2_parse_options(struct super_block *sb,
> -			       char *options,
> -			       struct mount_options *mopt,
> -			       int is_remount)
> +static int ocfs2_parse_param(struct fs_context *fc, struct fs_parameter *param)
>  {
> -	int status, user_stack = 0;
> -	char *p;
> -	u32 tmp;
> -	int token, option;
> -	substring_t args[MAX_OPT_ARGS];
> -
> -	trace_ocfs2_parse_options(is_remount, options ? options : "(none)");
> -
> -	mopt->commit_interval = 0;
> -	mopt->mount_opt = OCFS2_MOUNT_NOINTR;
> -	mopt->atime_quantum = OCFS2_DEFAULT_ATIME_QUANTUM;
> -	mopt->slot = OCFS2_INVALID_SLOT;
> -	mopt->localalloc_opt = -1;
> -	mopt->cluster_stack[0] = '\0';
> -	mopt->resv_level = OCFS2_DEFAULT_RESV_LEVEL;
> -	mopt->dir_resv_level = -1;
> -
> -	if (!options) {
> -		status = 1;
> -		goto bail;
> -	}
> -
> -	while ((p = strsep(&options, ",")) != NULL) {
> -		if (!*p)
> -			continue;
> -
> -		token = match_token(p, tokens, args);
> -		switch (token) {
> -		case Opt_hb_local:
> -			mopt->mount_opt |= OCFS2_MOUNT_HB_LOCAL;
> -			break;
> -		case Opt_hb_none:
> -			mopt->mount_opt |= OCFS2_MOUNT_HB_NONE;
> -			break;
> -		case Opt_hb_global:
> -			mopt->mount_opt |= OCFS2_MOUNT_HB_GLOBAL;
> -			break;
> -		case Opt_barrier:
> -			if (match_int(&args[0], &option)) {
> -				status = 0;
> -				goto bail;
> -			}
> -			if (option)
> -				mopt->mount_opt |= OCFS2_MOUNT_BARRIER;
> -			else
> -				mopt->mount_opt &= ~OCFS2_MOUNT_BARRIER;
> -			break;
> -		case Opt_intr:
> -			mopt->mount_opt &= ~OCFS2_MOUNT_NOINTR;
> -			break;
> -		case Opt_nointr:
> +	struct fs_parse_result result;
> +	int opt;
> +	struct mount_options *mopt = fc->fs_private;
> +	bool is_remount = (fc->purpose & FS_CONTEXT_FOR_RECONFIGURE);
> +
> +	trace_ocfs2_parse_options(is_remount, param->key);
> +
> +	opt = fs_parse(fc, ocfs2_param_spec, param, &result);
> +	if (opt < 0)
> +		return opt;
> +
> +	switch (opt) {
> +	case Opt_heartbeat:
> +		mopt->mount_opt |= result.uint_32;
> +		break;
> +	case Opt_barrier:
> +		if (result.uint_32)
> +			mopt->mount_opt |= OCFS2_MOUNT_BARRIER;
> +		else
> +			mopt->mount_opt &= ~OCFS2_MOUNT_BARRIER;
> +		break;
> +	case Opt_intr:
> +		if (result.negated)
>  			mopt->mount_opt |= OCFS2_MOUNT_NOINTR;
> -			break;
> -		case Opt_err_panic:
> -			mopt->mount_opt &= ~OCFS2_MOUNT_ERRORS_CONT;
> -			mopt->mount_opt &= ~OCFS2_MOUNT_ERRORS_ROFS;
> -			mopt->mount_opt |= OCFS2_MOUNT_ERRORS_PANIC;
> -			break;
> -		case Opt_err_ro:
> -			mopt->mount_opt &= ~OCFS2_MOUNT_ERRORS_CONT;
> -			mopt->mount_opt &= ~OCFS2_MOUNT_ERRORS_PANIC;
> -			mopt->mount_opt |= OCFS2_MOUNT_ERRORS_ROFS;
> -			break;
> -		case Opt_err_cont:
> -			mopt->mount_opt &= ~OCFS2_MOUNT_ERRORS_ROFS;
> -			mopt->mount_opt &= ~OCFS2_MOUNT_ERRORS_PANIC;
> -			mopt->mount_opt |= OCFS2_MOUNT_ERRORS_CONT;
> -			break;
> -		case Opt_data_ordered:
> -			mopt->mount_opt &= ~OCFS2_MOUNT_DATA_WRITEBACK;
> -			break;
> -		case Opt_data_writeback:
> -			mopt->mount_opt |= OCFS2_MOUNT_DATA_WRITEBACK;
> -			break;
> -		case Opt_user_xattr:
> -			mopt->mount_opt &= ~OCFS2_MOUNT_NOUSERXATTR;
> -			break;
> -		case Opt_nouser_xattr:
> +		else
> +			mopt->mount_opt &= ~OCFS2_MOUNT_NOINTR;
> +		break;
> +	case Opt_errors:
> +		mopt->mount_opt &= ~(OCFS2_MOUNT_ERRORS_CONT |
> +				     OCFS2_MOUNT_ERRORS_ROFS |
> +				     OCFS2_MOUNT_ERRORS_PANIC);
> +		mopt->mount_opt |= result.uint_32;
> +		break;
> +	case Opt_data:
> +		mopt->mount_opt &= ~OCFS2_MOUNT_DATA_WRITEBACK;
> +		mopt->mount_opt |= result.uint_32;
> +		break;
> +	case Opt_user_xattr:
> +		if (result.negated)
>  			mopt->mount_opt |= OCFS2_MOUNT_NOUSERXATTR;
> -			break;
> -		case Opt_atime_quantum:
> -			if (match_int(&args[0], &option)) {
> -				status = 0;
> -				goto bail;
> -			}
> -			if (option >= 0)
> -				mopt->atime_quantum = option;
> -			break;
> -		case Opt_slot:
> -			if (match_int(&args[0], &option)) {
> -				status = 0;
> -				goto bail;
> -			}
> -			if (option)
> -				mopt->slot = (u16)option;
> -			break;
> -		case Opt_commit:
> -			if (match_int(&args[0], &option)) {
> -				status = 0;
> -				goto bail;
> -			}
> -			if (option < 0)
> -				return 0;
> -			if (option == 0)
> -				option = JBD2_DEFAULT_MAX_COMMIT_AGE;
> -			mopt->commit_interval = HZ * option;
> -			break;
> -		case Opt_localalloc:
> -			if (match_int(&args[0], &option)) {
> -				status = 0;
> -				goto bail;
> -			}
> -			if (option >= 0)
> -				mopt->localalloc_opt = option;
> -			break;
> -		case Opt_localflocks:
> -			/*
> -			 * Changing this during remount could race
> -			 * flock() requests, or "unbalance" existing
> -			 * ones (e.g., a lock is taken in one mode but
> -			 * dropped in the other). If users care enough
> -			 * to flip locking modes during remount, we
> -			 * could add a "local" flag to individual
> -			 * flock structures for proper tracking of
> -			 * state.
> -			 */
> -			if (!is_remount)
> -				mopt->mount_opt |= OCFS2_MOUNT_LOCALFLOCKS;
> -			break;
> -		case Opt_stack:
> -			/* Check both that the option we were passed
> -			 * is of the right length and that it is a proper
> -			 * string of the right length.
> -			 */
> -			if (((args[0].to - args[0].from) !=
> -			     OCFS2_STACK_LABEL_LEN) ||
> -			    (strnlen(args[0].from,
> -				     OCFS2_STACK_LABEL_LEN) !=
> -			     OCFS2_STACK_LABEL_LEN)) {
> -				mlog(ML_ERROR,
> -				     "Invalid cluster_stack option\n");
> -				status = 0;
> -				goto bail;
> -			}
> -			memcpy(mopt->cluster_stack, args[0].from,
> -			       OCFS2_STACK_LABEL_LEN);
> -			mopt->cluster_stack[OCFS2_STACK_LABEL_LEN] = '\0';
> -			/*
> -			 * Open code the memcmp here as we don't have
> -			 * an osb to pass to
> -			 * ocfs2_userspace_stack().
> -			 */
> -			if (memcmp(mopt->cluster_stack,
> -				   OCFS2_CLASSIC_CLUSTER_STACK,
> -				   OCFS2_STACK_LABEL_LEN))
> -				user_stack = 1;
> -			break;
> -		case Opt_inode64:
> -			mopt->mount_opt |= OCFS2_MOUNT_INODE64;
> -			break;
> -		case Opt_usrquota:
> -			mopt->mount_opt |= OCFS2_MOUNT_USRQUOTA;
> -			break;
> -		case Opt_grpquota:
> -			mopt->mount_opt |= OCFS2_MOUNT_GRPQUOTA;
> -			break;
> -		case Opt_coherency_buffered:
> -			mopt->mount_opt |= OCFS2_MOUNT_COHERENCY_BUFFERED;
> -			break;
> -		case Opt_coherency_full:
> -			mopt->mount_opt &= ~OCFS2_MOUNT_COHERENCY_BUFFERED;
> -			break;
> -		case Opt_acl:
> -			mopt->mount_opt |= OCFS2_MOUNT_POSIX_ACL;
> -			mopt->mount_opt &= ~OCFS2_MOUNT_NO_POSIX_ACL;
> -			break;
> -		case Opt_noacl:
> +		else
> +			mopt->mount_opt &= ~OCFS2_MOUNT_NOUSERXATTR;
> +		break;
> +	case Opt_atime_quantum:
> +		mopt->atime_quantum = result.uint_32;
> +		break;
> +	case Opt_slot:
> +		if (result.uint_32)
> +			mopt->slot = (u16)result.uint_32;
> +		break;
> +	case Opt_commit:
> +		if (result.uint_32 == 0)
> +			mopt->commit_interval = HZ * JBD2_DEFAULT_MAX_COMMIT_AGE;
> +		else
> +			mopt->commit_interval = HZ * result.uint_32;
> +		break;
> +	case Opt_localalloc:
> +		if (result.int_32 >= 0)
> +			mopt->localalloc_opt = result.int_32;
> +		break;
> +	case Opt_localflocks:
> +		/*
> +		 * Changing this during remount could race flock() requests, or
> +		 * "unbalance" existing ones (e.g., a lock is taken in one mode
> +		 * but dropped in the other). If users care enough to flip
> +		 * locking modes during remount, we could add a "local" flag to
> +		 * individual flock structures for proper tracking of state.
> +		 */
> +		if (!is_remount)
> +			mopt->mount_opt |= OCFS2_MOUNT_LOCALFLOCKS;
> +		break;
> +	case Opt_stack:
> +		/* Check both that the option we were passed is of the right
> +		 * length and that it is a proper string of the right length.
> +		 */
> +		if (strlen(param->string) != OCFS2_STACK_LABEL_LEN) {
> +			mlog(ML_ERROR, "Invalid cluster_stack option\n");
> +			return -EINVAL;
> +		}
> +		memcpy(mopt->cluster_stack, param->string, OCFS2_STACK_LABEL_LEN);
> +		mopt->cluster_stack[OCFS2_STACK_LABEL_LEN] = '\0';
> +		/*
> +		 * Open code the memcmp here as we don't have an osb to pass
> +		 * to ocfs2_userspace_stack().
> +		 */
> +		if (memcmp(mopt->cluster_stack,
> +			   OCFS2_CLASSIC_CLUSTER_STACK,
> +			   OCFS2_STACK_LABEL_LEN))
> +			mopt->user_stack = 1;
> +		break;
> +	case Opt_inode64:
> +		mopt->mount_opt |= OCFS2_MOUNT_INODE64;
> +		break;
> +	case Opt_usrquota:
> +		mopt->mount_opt |= OCFS2_MOUNT_USRQUOTA;
> +		break;
> +	case Opt_grpquota:
> +		mopt->mount_opt |= OCFS2_MOUNT_GRPQUOTA;
> +		break;
> +	case Opt_coherency:
> +		mopt->mount_opt &= ~OCFS2_MOUNT_COHERENCY_BUFFERED;
> +		mopt->mount_opt |= result.uint_32;
> +		break;
> +	case Opt_acl:
> +		if (result.negated) {
>  			mopt->mount_opt |= OCFS2_MOUNT_NO_POSIX_ACL;
>  			mopt->mount_opt &= ~OCFS2_MOUNT_POSIX_ACL;
> +		} else {
> +			mopt->mount_opt |= OCFS2_MOUNT_POSIX_ACL;
> +			mopt->mount_opt &= ~OCFS2_MOUNT_NO_POSIX_ACL;
> +		}
> +		break;
> +	case Opt_resv_level:
> +		if (is_remount)
>  			break;
> -		case Opt_resv_level:
> -			if (is_remount)
> -				break;
> -			if (match_int(&args[0], &option)) {
> -				status = 0;
> -				goto bail;
> -			}
> -			if (option >= OCFS2_MIN_RESV_LEVEL &&
> -			    option < OCFS2_MAX_RESV_LEVEL)
> -				mopt->resv_level = option;
> -			break;
> -		case Opt_dir_resv_level:
> -			if (is_remount)
> -				break;
> -			if (match_int(&args[0], &option)) {
> -				status = 0;
> -				goto bail;
> -			}
> -			if (option >= OCFS2_MIN_RESV_LEVEL &&
> -			    option < OCFS2_MAX_RESV_LEVEL)
> -				mopt->dir_resv_level = option;
> -			break;
> -		case Opt_journal_async_commit:
> -			mopt->mount_opt |= OCFS2_MOUNT_JOURNAL_ASYNC_COMMIT;
> +		if (result.uint_32 >= OCFS2_MIN_RESV_LEVEL &&
> +		    result.uint_32 < OCFS2_MAX_RESV_LEVEL)
> +			mopt->resv_level = result.uint_32;
> +		break;
> +	case Opt_dir_resv_level:
> +		if (is_remount)
>  			break;
> -		default:
> -			mlog(ML_ERROR,
> -			     "Unrecognized mount option \"%s\" "
> -			     "or missing value\n", p);
> -			status = 0;
> -			goto bail;
> -		}
> -	}
> -
> -	if (user_stack == 0) {
> -		/* Ensure only one heartbeat mode */
> -		tmp = mopt->mount_opt & (OCFS2_MOUNT_HB_LOCAL |
> -					 OCFS2_MOUNT_HB_GLOBAL |
> -					 OCFS2_MOUNT_HB_NONE);
> -		if (hweight32(tmp) != 1) {
> -			mlog(ML_ERROR, "Invalid heartbeat mount options\n");
> -			status = 0;
> -			goto bail;
> -		}
> +		if (result.uint_32 >= OCFS2_MIN_RESV_LEVEL &&
> +		    result.uint_32 < OCFS2_MAX_RESV_LEVEL)
> +			mopt->dir_resv_level = result.uint_32;
> +		break;
> +	case Opt_journal_async_commit:
> +		mopt->mount_opt |= OCFS2_MOUNT_JOURNAL_ASYNC_COMMIT;
> +		break;
> +	default:
> +		return -EINVAL;
>  	}
>  
> -	status = 1;
> -
> -bail:
> -	return status;
> +	return 0;
>  }
>  
>  static int ocfs2_show_options(struct seq_file *s, struct dentry *root)
diff mbox series

Patch

diff --git a/fs/ocfs2/ocfs2_trace.h b/fs/ocfs2/ocfs2_trace.h
index 0511c69c9fde..54ed1495de9a 100644
--- a/fs/ocfs2/ocfs2_trace.h
+++ b/fs/ocfs2/ocfs2_trace.h
@@ -1658,34 +1658,34 @@  TRACE_EVENT(ocfs2_remount,
 );
 
 TRACE_EVENT(ocfs2_fill_super,
-	TP_PROTO(void *sb, void *data, int silent),
-	TP_ARGS(sb, data, silent),
+	TP_PROTO(void *sb, void *fc, int silent),
+	TP_ARGS(sb, fc, silent),
 	TP_STRUCT__entry(
 		__field(void *, sb)
-		__field(void *, data)
+		__field(void *, fc)
 		__field(int, silent)
 	),
 	TP_fast_assign(
 		__entry->sb = sb;
-		__entry->data = data;
+		__entry->fc = fc;
 		__entry->silent = silent;
 	),
 	TP_printk("%p %p %d", __entry->sb,
-		  __entry->data, __entry->silent)
+		  __entry->fc, __entry->silent)
 );
 
 TRACE_EVENT(ocfs2_parse_options,
-	TP_PROTO(int is_remount, char *options),
-	TP_ARGS(is_remount, options),
+	TP_PROTO(int is_remount, const char *option),
+	TP_ARGS(is_remount, option),
 	TP_STRUCT__entry(
 		__field(int, is_remount)
-		__string(options, options)
+		__string(option, option)
 	),
 	TP_fast_assign(
 		__entry->is_remount = is_remount;
-		__assign_str(options);
+		__assign_str(option);
 	),
-	TP_printk("%d %s", __entry->is_remount, __get_str(options))
+	TP_printk("%d %s", __entry->is_remount, __get_str(option))
 );
 
 DEFINE_OCFS2_POINTER_EVENT(ocfs2_put_super);
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c
index 3d404624bb96..110ffc4bb840 100644
--- a/fs/ocfs2/super.c
+++ b/fs/ocfs2/super.c
@@ -19,10 +19,10 @@ 
 #include <linux/blkdev.h>
 #include <linux/socket.h>
 #include <linux/inet.h>
-#include <linux/parser.h>
+#include <linux/fs_parser.h>
+#include <linux/fs_context.h>
 #include <linux/crc32.h>
 #include <linux/debugfs.h>
-#include <linux/mount.h>
 #include <linux/seq_file.h>
 #include <linux/quotaops.h>
 #include <linux/signal.h>
@@ -80,17 +80,15 @@  struct mount_options
 	unsigned int	resv_level;
 	int		dir_resv_level;
 	char		cluster_stack[OCFS2_STACK_LABEL_LEN + 1];
+	bool		user_stack;
 };
 
-static int ocfs2_parse_options(struct super_block *sb, char *options,
-			       struct mount_options *mopt,
-			       int is_remount);
+static int ocfs2_parse_param(struct fs_context *fc, struct fs_parameter *param);
 static int ocfs2_check_set_options(struct super_block *sb,
 				   struct mount_options *options);
 static int ocfs2_show_options(struct seq_file *s, struct dentry *root);
 static void ocfs2_put_super(struct super_block *sb);
 static int ocfs2_mount_volume(struct super_block *sb);
-static int ocfs2_remount(struct super_block *sb, int *flags, char *data);
 static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err);
 static int ocfs2_initialize_mem_caches(void);
 static void ocfs2_free_mem_caches(void);
@@ -135,7 +133,6 @@  static const struct super_operations ocfs2_sops = {
 	.evict_inode	= ocfs2_evict_inode,
 	.sync_fs	= ocfs2_sync_fs,
 	.put_super	= ocfs2_put_super,
-	.remount_fs	= ocfs2_remount,
 	.show_options   = ocfs2_show_options,
 	.quota_read	= ocfs2_quota_read,
 	.quota_write	= ocfs2_quota_write,
@@ -144,15 +141,10 @@  static const struct super_operations ocfs2_sops = {
 
 enum {
 	Opt_barrier,
-	Opt_err_panic,
-	Opt_err_ro,
+	Opt_errors,
 	Opt_intr,
-	Opt_nointr,
-	Opt_hb_none,
-	Opt_hb_local,
-	Opt_hb_global,
-	Opt_data_ordered,
-	Opt_data_writeback,
+	Opt_heartbeat,
+	Opt_data,
 	Opt_atime_quantum,
 	Opt_slot,
 	Opt_commit,
@@ -160,52 +152,64 @@  enum {
 	Opt_localflocks,
 	Opt_stack,
 	Opt_user_xattr,
-	Opt_nouser_xattr,
 	Opt_inode64,
 	Opt_acl,
-	Opt_noacl,
 	Opt_usrquota,
 	Opt_grpquota,
-	Opt_coherency_buffered,
-	Opt_coherency_full,
+	Opt_coherency,
 	Opt_resv_level,
 	Opt_dir_resv_level,
 	Opt_journal_async_commit,
-	Opt_err_cont,
-	Opt_err,
 };
 
-static const match_table_t tokens = {
-	{Opt_barrier, "barrier=%u"},
-	{Opt_err_panic, "errors=panic"},
-	{Opt_err_ro, "errors=remount-ro"},
-	{Opt_intr, "intr"},
-	{Opt_nointr, "nointr"},
-	{Opt_hb_none, OCFS2_HB_NONE},
-	{Opt_hb_local, OCFS2_HB_LOCAL},
-	{Opt_hb_global, OCFS2_HB_GLOBAL},
-	{Opt_data_ordered, "data=ordered"},
-	{Opt_data_writeback, "data=writeback"},
-	{Opt_atime_quantum, "atime_quantum=%u"},
-	{Opt_slot, "preferred_slot=%u"},
-	{Opt_commit, "commit=%u"},
-	{Opt_localalloc, "localalloc=%d"},
-	{Opt_localflocks, "localflocks"},
-	{Opt_stack, "cluster_stack=%s"},
-	{Opt_user_xattr, "user_xattr"},
-	{Opt_nouser_xattr, "nouser_xattr"},
-	{Opt_inode64, "inode64"},
-	{Opt_acl, "acl"},
-	{Opt_noacl, "noacl"},
-	{Opt_usrquota, "usrquota"},
-	{Opt_grpquota, "grpquota"},
-	{Opt_coherency_buffered, "coherency=buffered"},
-	{Opt_coherency_full, "coherency=full"},
-	{Opt_resv_level, "resv_level=%u"},
-	{Opt_dir_resv_level, "dir_resv_level=%u"},
-	{Opt_journal_async_commit, "journal_async_commit"},
-	{Opt_err_cont, "errors=continue"},
-	{Opt_err, NULL}
+static const struct constant_table ocfs2_param_errors[] = {
+	{"panic",	OCFS2_MOUNT_ERRORS_PANIC},
+	{"remount-ro",	OCFS2_MOUNT_ERRORS_ROFS},
+	{"continue",	OCFS2_MOUNT_ERRORS_CONT},
+	{}
+};
+
+static const struct constant_table ocfs2_param_heartbeat[] = {
+	{"local",	OCFS2_MOUNT_HB_LOCAL},
+	{"none",	OCFS2_MOUNT_HB_NONE},
+	{"global",	OCFS2_MOUNT_HB_GLOBAL},
+	{}
+};
+
+static const struct constant_table ocfs2_param_data[] = {
+	{"writeback",	OCFS2_MOUNT_DATA_WRITEBACK},
+	{"ordered",	0},
+	{}
+};
+
+static const struct constant_table ocfs2_param_coherency[] = {
+	{"buffered",	OCFS2_MOUNT_COHERENCY_BUFFERED},
+	{"full",	0},
+	{}
+};
+
+static const struct fs_parameter_spec ocfs2_param_spec[] = {
+	fsparam_u32	("barrier",	Opt_barrier),
+	fsparam_enum	("errors",	Opt_errors,	ocfs2_param_errors),
+	fsparam_flag_no	("intr",	Opt_intr),
+	fsparam_enum	("heartbeat",	Opt_heartbeat,	ocfs2_param_heartbeat),
+	fsparam_enum	("data",	Opt_data,	ocfs2_param_data),
+	fsparam_u32	("atime_quantum", Opt_atime_quantum),
+	fsparam_u32	("preferred_slot", Opt_slot),
+	fsparam_u32	("commit",	Opt_commit),
+	fsparam_s32	("localalloc",	Opt_localalloc),
+	fsparam_flag	("localflocks",	Opt_localflocks),
+	fsparam_string	("cluster_stack", Opt_stack),
+	fsparam_flag_no	("user_xattr",	Opt_user_xattr),
+	fsparam_flag	("inode64",	Opt_inode64),
+	fsparam_flag_no	("acl",		Opt_acl),
+	fsparam_flag	("usrquota",	Opt_usrquota),
+	fsparam_flag	("grpquota",	Opt_grpquota),
+	fsparam_enum	("coherency",	Opt_coherency,	ocfs2_param_coherency),
+	fsparam_u32	("resv_level",	Opt_resv_level),
+	fsparam_u32	("dir_resv_level",	Opt_dir_resv_level),
+	fsparam_flag	("journal_async_commit", Opt_journal_async_commit),
+	{}
 };
 
 #ifdef CONFIG_DEBUG_FS
@@ -600,32 +604,32 @@  static unsigned long long ocfs2_max_file_offset(unsigned int bbits,
 	return (((unsigned long long)bytes) << bitshift) - trim;
 }
 
-static int ocfs2_remount(struct super_block *sb, int *flags, char *data)
+static int ocfs2_reconfigure(struct fs_context *fc)
 {
 	int incompat_features;
 	int ret = 0;
-	struct mount_options parsed_options;
+	struct mount_options *parsed_options = fc->fs_private;
+	struct super_block *sb = fc->root->d_sb;
 	struct ocfs2_super *osb = OCFS2_SB(sb);
 	u32 tmp;
 
 	sync_filesystem(sb);
 
-	if (!ocfs2_parse_options(sb, data, &parsed_options, 1) ||
-	    !ocfs2_check_set_options(sb, &parsed_options)) {
+	if (!ocfs2_check_set_options(sb, parsed_options)) {
 		ret = -EINVAL;
 		goto out;
 	}
 
 	tmp = OCFS2_MOUNT_HB_LOCAL | OCFS2_MOUNT_HB_GLOBAL |
 		OCFS2_MOUNT_HB_NONE;
-	if ((osb->s_mount_opt & tmp) != (parsed_options.mount_opt & tmp)) {
+	if ((osb->s_mount_opt & tmp) != (parsed_options->mount_opt & tmp)) {
 		ret = -EINVAL;
 		mlog(ML_ERROR, "Cannot change heartbeat mode on remount\n");
 		goto out;
 	}
 
 	if ((osb->s_mount_opt & OCFS2_MOUNT_DATA_WRITEBACK) !=
-	    (parsed_options.mount_opt & OCFS2_MOUNT_DATA_WRITEBACK)) {
+	    (parsed_options->mount_opt & OCFS2_MOUNT_DATA_WRITEBACK)) {
 		ret = -EINVAL;
 		mlog(ML_ERROR, "Cannot change data mode on remount\n");
 		goto out;
@@ -634,16 +638,16 @@  static int ocfs2_remount(struct super_block *sb, int *flags, char *data)
 	/* Probably don't want this on remount; it might
 	 * mess with other nodes */
 	if (!(osb->s_mount_opt & OCFS2_MOUNT_INODE64) &&
-	    (parsed_options.mount_opt & OCFS2_MOUNT_INODE64)) {
+	    (parsed_options->mount_opt & OCFS2_MOUNT_INODE64)) {
 		ret = -EINVAL;
 		mlog(ML_ERROR, "Cannot enable inode64 on remount\n");
 		goto out;
 	}
 
 	/* We're going to/from readonly mode. */
-	if ((bool)(*flags & SB_RDONLY) != sb_rdonly(sb)) {
+	if ((bool)(fc->sb_flags & SB_RDONLY) != sb_rdonly(sb)) {
 		/* Disable quota accounting before remounting RO */
-		if (*flags & SB_RDONLY) {
+		if (fc->sb_flags & SB_RDONLY) {
 			ret = ocfs2_susp_quotas(osb, 0);
 			if (ret < 0)
 				goto out;
@@ -657,7 +661,7 @@  static int ocfs2_remount(struct super_block *sb, int *flags, char *data)
 			goto unlock_osb;
 		}
 
-		if (*flags & SB_RDONLY) {
+		if (fc->sb_flags & SB_RDONLY) {
 			sb->s_flags |= SB_RDONLY;
 			osb->osb_flags |= OCFS2_OSB_SOFT_RO;
 		} else {
@@ -678,11 +682,11 @@  static int ocfs2_remount(struct super_block *sb, int *flags, char *data)
 			sb->s_flags &= ~SB_RDONLY;
 			osb->osb_flags &= ~OCFS2_OSB_SOFT_RO;
 		}
-		trace_ocfs2_remount(sb->s_flags, osb->osb_flags, *flags);
+		trace_ocfs2_remount(sb->s_flags, osb->osb_flags, fc->sb_flags);
 unlock_osb:
 		spin_unlock(&osb->osb_lock);
 		/* Enable quota accounting after remounting RW */
-		if (!ret && !(*flags & SB_RDONLY)) {
+		if (!ret && !(fc->sb_flags & SB_RDONLY)) {
 			if (sb_any_quota_suspended(sb))
 				ret = ocfs2_susp_quotas(osb, 1);
 			else
@@ -701,11 +705,11 @@  static int ocfs2_remount(struct super_block *sb, int *flags, char *data)
 	if (!ret) {
 		/* Only save off the new mount options in case of a successful
 		 * remount. */
-		osb->s_mount_opt = parsed_options.mount_opt;
-		osb->s_atime_quantum = parsed_options.atime_quantum;
-		osb->preferred_slot = parsed_options.slot;
-		if (parsed_options.commit_interval)
-			osb->osb_commit_interval = parsed_options.commit_interval;
+		osb->s_mount_opt = parsed_options->mount_opt;
+		osb->s_atime_quantum = parsed_options->atime_quantum;
+		osb->preferred_slot = parsed_options->slot;
+		if (parsed_options->commit_interval)
+			osb->osb_commit_interval = parsed_options->commit_interval;
 
 		if (!ocfs2_is_hard_readonly(osb))
 			ocfs2_set_journal_params(osb);
@@ -966,23 +970,18 @@  static void ocfs2_disable_quotas(struct ocfs2_super *osb)
 	}
 }
 
-static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
+static int ocfs2_fill_super(struct super_block *sb, struct fs_context *fc)
 {
 	struct dentry *root;
 	int status, sector_size;
-	struct mount_options parsed_options;
+	struct mount_options *parsed_options = fc->fs_private;
 	struct inode *inode = NULL;
 	struct ocfs2_super *osb = NULL;
 	struct buffer_head *bh = NULL;
 	char nodestr[12];
 	struct ocfs2_blockcheck_stats stats;
 
-	trace_ocfs2_fill_super(sb, data, silent);
-
-	if (!ocfs2_parse_options(sb, data, &parsed_options, 0)) {
-		status = -EINVAL;
-		goto out;
-	}
+	trace_ocfs2_fill_super(sb, fc, fc->sb_flags & SB_SILENT);
 
 	/* probe for superblock */
 	status = ocfs2_sb_probe(sb, &bh, &sector_size, &stats);
@@ -999,24 +998,24 @@  static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
 
 	osb = OCFS2_SB(sb);
 
-	if (!ocfs2_check_set_options(sb, &parsed_options)) {
+	if (!ocfs2_check_set_options(sb, parsed_options)) {
 		status = -EINVAL;
 		goto out_super;
 	}
-	osb->s_mount_opt = parsed_options.mount_opt;
-	osb->s_atime_quantum = parsed_options.atime_quantum;
-	osb->preferred_slot = parsed_options.slot;
-	osb->osb_commit_interval = parsed_options.commit_interval;
+	osb->s_mount_opt = parsed_options->mount_opt;
+	osb->s_atime_quantum = parsed_options->atime_quantum;
+	osb->preferred_slot = parsed_options->slot;
+	osb->osb_commit_interval = parsed_options->commit_interval;
 
-	ocfs2_la_set_sizes(osb, parsed_options.localalloc_opt);
-	osb->osb_resv_level = parsed_options.resv_level;
-	osb->osb_dir_resv_level = parsed_options.resv_level;
-	if (parsed_options.dir_resv_level == -1)
-		osb->osb_dir_resv_level = parsed_options.resv_level;
+	ocfs2_la_set_sizes(osb, parsed_options->localalloc_opt);
+	osb->osb_resv_level = parsed_options->resv_level;
+	osb->osb_dir_resv_level = parsed_options->resv_level;
+	if (parsed_options->dir_resv_level == -1)
+		osb->osb_dir_resv_level = parsed_options->resv_level;
 	else
-		osb->osb_dir_resv_level = parsed_options.dir_resv_level;
+		osb->osb_dir_resv_level = parsed_options->dir_resv_level;
 
-	status = ocfs2_verify_userspace_stack(osb, &parsed_options);
+	status = ocfs2_verify_userspace_stack(osb, parsed_options);
 	if (status)
 		goto out_super;
 
@@ -1180,27 +1179,72 @@  static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
 	return status;
 }
 
-static struct dentry *ocfs2_mount(struct file_system_type *fs_type,
-			int flags,
-			const char *dev_name,
-			void *data)
+static int ocfs2_get_tree(struct fs_context *fc)
+{
+	return get_tree_bdev(fc, ocfs2_fill_super);
+}
+
+static void ocfs2_free_fc(struct fs_context *fc)
 {
-	return mount_bdev(fs_type, flags, dev_name, data, ocfs2_fill_super);
+	kfree(fc->fs_private);
+}
+
+static const struct fs_context_operations ocfs2_context_ops = {
+	.parse_param	= ocfs2_parse_param,
+	.get_tree	= ocfs2_get_tree,
+	.reconfigure	= ocfs2_reconfigure,
+	.free		= ocfs2_free_fc,
+};
+
+static int ocfs2_init_fs_context(struct fs_context *fc)
+{
+	struct mount_options *mopt;
+
+	mopt = kzalloc(sizeof(struct mount_options), GFP_KERNEL);
+	if (!mopt)
+		return -EINVAL;
+
+	mopt->commit_interval = 0;
+	mopt->mount_opt = OCFS2_MOUNT_NOINTR;
+	mopt->atime_quantum = OCFS2_DEFAULT_ATIME_QUANTUM;
+	mopt->slot = OCFS2_INVALID_SLOT;
+	mopt->localalloc_opt = -1;
+	mopt->cluster_stack[0] = '\0';
+	mopt->resv_level = OCFS2_DEFAULT_RESV_LEVEL;
+	mopt->dir_resv_level = -1;
+
+	fc->fs_private = mopt;
+	fc->ops = &ocfs2_context_ops;
+
+	return 0;
 }
 
 static struct file_system_type ocfs2_fs_type = {
 	.owner          = THIS_MODULE,
 	.name           = "ocfs2",
-	.mount          = ocfs2_mount,
 	.kill_sb        = kill_block_super,
 	.fs_flags       = FS_REQUIRES_DEV|FS_RENAME_DOES_D_MOVE,
-	.next           = NULL
+	.next           = NULL,
+	.init_fs_context = ocfs2_init_fs_context,
+	.parameters	= ocfs2_param_spec,
 };
 MODULE_ALIAS_FS("ocfs2");
 
 static int ocfs2_check_set_options(struct super_block *sb,
 				   struct mount_options *options)
 {
+	if (options->user_stack == 0) {
+		u32 tmp;
+
+		/* Ensure only one heartbeat mode */
+		tmp = options->mount_opt & (OCFS2_MOUNT_HB_LOCAL |
+					    OCFS2_MOUNT_HB_GLOBAL |
+					    OCFS2_MOUNT_HB_NONE);
+		if (hweight32(tmp) != 1) {
+			mlog(ML_ERROR, "Invalid heartbeat mount options\n");
+			return 0;
+		}
+	}
 	if (options->mount_opt & OCFS2_MOUNT_USRQUOTA &&
 	    !OCFS2_HAS_RO_COMPAT_FEATURE(sb,
 					 OCFS2_FEATURE_RO_COMPAT_USRQUOTA)) {
@@ -1232,241 +1276,142 @@  static int ocfs2_check_set_options(struct super_block *sb,
 	return 1;
 }
 
-static int ocfs2_parse_options(struct super_block *sb,
-			       char *options,
-			       struct mount_options *mopt,
-			       int is_remount)
+static int ocfs2_parse_param(struct fs_context *fc, struct fs_parameter *param)
 {
-	int status, user_stack = 0;
-	char *p;
-	u32 tmp;
-	int token, option;
-	substring_t args[MAX_OPT_ARGS];
-
-	trace_ocfs2_parse_options(is_remount, options ? options : "(none)");
-
-	mopt->commit_interval = 0;
-	mopt->mount_opt = OCFS2_MOUNT_NOINTR;
-	mopt->atime_quantum = OCFS2_DEFAULT_ATIME_QUANTUM;
-	mopt->slot = OCFS2_INVALID_SLOT;
-	mopt->localalloc_opt = -1;
-	mopt->cluster_stack[0] = '\0';
-	mopt->resv_level = OCFS2_DEFAULT_RESV_LEVEL;
-	mopt->dir_resv_level = -1;
-
-	if (!options) {
-		status = 1;
-		goto bail;
-	}
-
-	while ((p = strsep(&options, ",")) != NULL) {
-		if (!*p)
-			continue;
-
-		token = match_token(p, tokens, args);
-		switch (token) {
-		case Opt_hb_local:
-			mopt->mount_opt |= OCFS2_MOUNT_HB_LOCAL;
-			break;
-		case Opt_hb_none:
-			mopt->mount_opt |= OCFS2_MOUNT_HB_NONE;
-			break;
-		case Opt_hb_global:
-			mopt->mount_opt |= OCFS2_MOUNT_HB_GLOBAL;
-			break;
-		case Opt_barrier:
-			if (match_int(&args[0], &option)) {
-				status = 0;
-				goto bail;
-			}
-			if (option)
-				mopt->mount_opt |= OCFS2_MOUNT_BARRIER;
-			else
-				mopt->mount_opt &= ~OCFS2_MOUNT_BARRIER;
-			break;
-		case Opt_intr:
-			mopt->mount_opt &= ~OCFS2_MOUNT_NOINTR;
-			break;
-		case Opt_nointr:
+	struct fs_parse_result result;
+	int opt;
+	struct mount_options *mopt = fc->fs_private;
+	bool is_remount = (fc->purpose & FS_CONTEXT_FOR_RECONFIGURE);
+
+	trace_ocfs2_parse_options(is_remount, param->key);
+
+	opt = fs_parse(fc, ocfs2_param_spec, param, &result);
+	if (opt < 0)
+		return opt;
+
+	switch (opt) {
+	case Opt_heartbeat:
+		mopt->mount_opt |= result.uint_32;
+		break;
+	case Opt_barrier:
+		if (result.uint_32)
+			mopt->mount_opt |= OCFS2_MOUNT_BARRIER;
+		else
+			mopt->mount_opt &= ~OCFS2_MOUNT_BARRIER;
+		break;
+	case Opt_intr:
+		if (result.negated)
 			mopt->mount_opt |= OCFS2_MOUNT_NOINTR;
-			break;
-		case Opt_err_panic:
-			mopt->mount_opt &= ~OCFS2_MOUNT_ERRORS_CONT;
-			mopt->mount_opt &= ~OCFS2_MOUNT_ERRORS_ROFS;
-			mopt->mount_opt |= OCFS2_MOUNT_ERRORS_PANIC;
-			break;
-		case Opt_err_ro:
-			mopt->mount_opt &= ~OCFS2_MOUNT_ERRORS_CONT;
-			mopt->mount_opt &= ~OCFS2_MOUNT_ERRORS_PANIC;
-			mopt->mount_opt |= OCFS2_MOUNT_ERRORS_ROFS;
-			break;
-		case Opt_err_cont:
-			mopt->mount_opt &= ~OCFS2_MOUNT_ERRORS_ROFS;
-			mopt->mount_opt &= ~OCFS2_MOUNT_ERRORS_PANIC;
-			mopt->mount_opt |= OCFS2_MOUNT_ERRORS_CONT;
-			break;
-		case Opt_data_ordered:
-			mopt->mount_opt &= ~OCFS2_MOUNT_DATA_WRITEBACK;
-			break;
-		case Opt_data_writeback:
-			mopt->mount_opt |= OCFS2_MOUNT_DATA_WRITEBACK;
-			break;
-		case Opt_user_xattr:
-			mopt->mount_opt &= ~OCFS2_MOUNT_NOUSERXATTR;
-			break;
-		case Opt_nouser_xattr:
+		else
+			mopt->mount_opt &= ~OCFS2_MOUNT_NOINTR;
+		break;
+	case Opt_errors:
+		mopt->mount_opt &= ~(OCFS2_MOUNT_ERRORS_CONT |
+				     OCFS2_MOUNT_ERRORS_ROFS |
+				     OCFS2_MOUNT_ERRORS_PANIC);
+		mopt->mount_opt |= result.uint_32;
+		break;
+	case Opt_data:
+		mopt->mount_opt &= ~OCFS2_MOUNT_DATA_WRITEBACK;
+		mopt->mount_opt |= result.uint_32;
+		break;
+	case Opt_user_xattr:
+		if (result.negated)
 			mopt->mount_opt |= OCFS2_MOUNT_NOUSERXATTR;
-			break;
-		case Opt_atime_quantum:
-			if (match_int(&args[0], &option)) {
-				status = 0;
-				goto bail;
-			}
-			if (option >= 0)
-				mopt->atime_quantum = option;
-			break;
-		case Opt_slot:
-			if (match_int(&args[0], &option)) {
-				status = 0;
-				goto bail;
-			}
-			if (option)
-				mopt->slot = (u16)option;
-			break;
-		case Opt_commit:
-			if (match_int(&args[0], &option)) {
-				status = 0;
-				goto bail;
-			}
-			if (option < 0)
-				return 0;
-			if (option == 0)
-				option = JBD2_DEFAULT_MAX_COMMIT_AGE;
-			mopt->commit_interval = HZ * option;
-			break;
-		case Opt_localalloc:
-			if (match_int(&args[0], &option)) {
-				status = 0;
-				goto bail;
-			}
-			if (option >= 0)
-				mopt->localalloc_opt = option;
-			break;
-		case Opt_localflocks:
-			/*
-			 * Changing this during remount could race
-			 * flock() requests, or "unbalance" existing
-			 * ones (e.g., a lock is taken in one mode but
-			 * dropped in the other). If users care enough
-			 * to flip locking modes during remount, we
-			 * could add a "local" flag to individual
-			 * flock structures for proper tracking of
-			 * state.
-			 */
-			if (!is_remount)
-				mopt->mount_opt |= OCFS2_MOUNT_LOCALFLOCKS;
-			break;
-		case Opt_stack:
-			/* Check both that the option we were passed
-			 * is of the right length and that it is a proper
-			 * string of the right length.
-			 */
-			if (((args[0].to - args[0].from) !=
-			     OCFS2_STACK_LABEL_LEN) ||
-			    (strnlen(args[0].from,
-				     OCFS2_STACK_LABEL_LEN) !=
-			     OCFS2_STACK_LABEL_LEN)) {
-				mlog(ML_ERROR,
-				     "Invalid cluster_stack option\n");
-				status = 0;
-				goto bail;
-			}
-			memcpy(mopt->cluster_stack, args[0].from,
-			       OCFS2_STACK_LABEL_LEN);
-			mopt->cluster_stack[OCFS2_STACK_LABEL_LEN] = '\0';
-			/*
-			 * Open code the memcmp here as we don't have
-			 * an osb to pass to
-			 * ocfs2_userspace_stack().
-			 */
-			if (memcmp(mopt->cluster_stack,
-				   OCFS2_CLASSIC_CLUSTER_STACK,
-				   OCFS2_STACK_LABEL_LEN))
-				user_stack = 1;
-			break;
-		case Opt_inode64:
-			mopt->mount_opt |= OCFS2_MOUNT_INODE64;
-			break;
-		case Opt_usrquota:
-			mopt->mount_opt |= OCFS2_MOUNT_USRQUOTA;
-			break;
-		case Opt_grpquota:
-			mopt->mount_opt |= OCFS2_MOUNT_GRPQUOTA;
-			break;
-		case Opt_coherency_buffered:
-			mopt->mount_opt |= OCFS2_MOUNT_COHERENCY_BUFFERED;
-			break;
-		case Opt_coherency_full:
-			mopt->mount_opt &= ~OCFS2_MOUNT_COHERENCY_BUFFERED;
-			break;
-		case Opt_acl:
-			mopt->mount_opt |= OCFS2_MOUNT_POSIX_ACL;
-			mopt->mount_opt &= ~OCFS2_MOUNT_NO_POSIX_ACL;
-			break;
-		case Opt_noacl:
+		else
+			mopt->mount_opt &= ~OCFS2_MOUNT_NOUSERXATTR;
+		break;
+	case Opt_atime_quantum:
+		mopt->atime_quantum = result.uint_32;
+		break;
+	case Opt_slot:
+		if (result.uint_32)
+			mopt->slot = (u16)result.uint_32;
+		break;
+	case Opt_commit:
+		if (result.uint_32 == 0)
+			mopt->commit_interval = HZ * JBD2_DEFAULT_MAX_COMMIT_AGE;
+		else
+			mopt->commit_interval = HZ * result.uint_32;
+		break;
+	case Opt_localalloc:
+		if (result.int_32 >= 0)
+			mopt->localalloc_opt = result.int_32;
+		break;
+	case Opt_localflocks:
+		/*
+		 * Changing this during remount could race flock() requests, or
+		 * "unbalance" existing ones (e.g., a lock is taken in one mode
+		 * but dropped in the other). If users care enough to flip
+		 * locking modes during remount, we could add a "local" flag to
+		 * individual flock structures for proper tracking of state.
+		 */
+		if (!is_remount)
+			mopt->mount_opt |= OCFS2_MOUNT_LOCALFLOCKS;
+		break;
+	case Opt_stack:
+		/* Check both that the option we were passed is of the right
+		 * length and that it is a proper string of the right length.
+		 */
+		if (strlen(param->string) != OCFS2_STACK_LABEL_LEN) {
+			mlog(ML_ERROR, "Invalid cluster_stack option\n");
+			return -EINVAL;
+		}
+		memcpy(mopt->cluster_stack, param->string, OCFS2_STACK_LABEL_LEN);
+		mopt->cluster_stack[OCFS2_STACK_LABEL_LEN] = '\0';
+		/*
+		 * Open code the memcmp here as we don't have an osb to pass
+		 * to ocfs2_userspace_stack().
+		 */
+		if (memcmp(mopt->cluster_stack,
+			   OCFS2_CLASSIC_CLUSTER_STACK,
+			   OCFS2_STACK_LABEL_LEN))
+			mopt->user_stack = 1;
+		break;
+	case Opt_inode64:
+		mopt->mount_opt |= OCFS2_MOUNT_INODE64;
+		break;
+	case Opt_usrquota:
+		mopt->mount_opt |= OCFS2_MOUNT_USRQUOTA;
+		break;
+	case Opt_grpquota:
+		mopt->mount_opt |= OCFS2_MOUNT_GRPQUOTA;
+		break;
+	case Opt_coherency:
+		mopt->mount_opt &= ~OCFS2_MOUNT_COHERENCY_BUFFERED;
+		mopt->mount_opt |= result.uint_32;
+		break;
+	case Opt_acl:
+		if (result.negated) {
 			mopt->mount_opt |= OCFS2_MOUNT_NO_POSIX_ACL;
 			mopt->mount_opt &= ~OCFS2_MOUNT_POSIX_ACL;
+		} else {
+			mopt->mount_opt |= OCFS2_MOUNT_POSIX_ACL;
+			mopt->mount_opt &= ~OCFS2_MOUNT_NO_POSIX_ACL;
+		}
+		break;
+	case Opt_resv_level:
+		if (is_remount)
 			break;
-		case Opt_resv_level:
-			if (is_remount)
-				break;
-			if (match_int(&args[0], &option)) {
-				status = 0;
-				goto bail;
-			}
-			if (option >= OCFS2_MIN_RESV_LEVEL &&
-			    option < OCFS2_MAX_RESV_LEVEL)
-				mopt->resv_level = option;
-			break;
-		case Opt_dir_resv_level:
-			if (is_remount)
-				break;
-			if (match_int(&args[0], &option)) {
-				status = 0;
-				goto bail;
-			}
-			if (option >= OCFS2_MIN_RESV_LEVEL &&
-			    option < OCFS2_MAX_RESV_LEVEL)
-				mopt->dir_resv_level = option;
-			break;
-		case Opt_journal_async_commit:
-			mopt->mount_opt |= OCFS2_MOUNT_JOURNAL_ASYNC_COMMIT;
+		if (result.uint_32 >= OCFS2_MIN_RESV_LEVEL &&
+		    result.uint_32 < OCFS2_MAX_RESV_LEVEL)
+			mopt->resv_level = result.uint_32;
+		break;
+	case Opt_dir_resv_level:
+		if (is_remount)
 			break;
-		default:
-			mlog(ML_ERROR,
-			     "Unrecognized mount option \"%s\" "
-			     "or missing value\n", p);
-			status = 0;
-			goto bail;
-		}
-	}
-
-	if (user_stack == 0) {
-		/* Ensure only one heartbeat mode */
-		tmp = mopt->mount_opt & (OCFS2_MOUNT_HB_LOCAL |
-					 OCFS2_MOUNT_HB_GLOBAL |
-					 OCFS2_MOUNT_HB_NONE);
-		if (hweight32(tmp) != 1) {
-			mlog(ML_ERROR, "Invalid heartbeat mount options\n");
-			status = 0;
-			goto bail;
-		}
+		if (result.uint_32 >= OCFS2_MIN_RESV_LEVEL &&
+		    result.uint_32 < OCFS2_MAX_RESV_LEVEL)
+			mopt->dir_resv_level = result.uint_32;
+		break;
+	case Opt_journal_async_commit:
+		mopt->mount_opt |= OCFS2_MOUNT_JOURNAL_ASYNC_COMMIT;
+		break;
+	default:
+		return -EINVAL;
 	}
 
-	status = 1;
-
-bail:
-	return status;
+	return 0;
 }
 
 static int ocfs2_show_options(struct seq_file *s, struct dentry *root)