public inbox for linux-ext4@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2] ext2: convert to the new mount API
@ 2025-02-23 19:57 Eric Sandeen
  2025-02-23 19:57 ` [PATCH 1/2] " Eric Sandeen
  2025-02-23 19:57 ` [PATCH 2/2] ext2: create ext2_msg_fc for use during parsing Eric Sandeen
  0 siblings, 2 replies; 7+ messages in thread
From: Eric Sandeen @ 2025-02-23 19:57 UTC (permalink / raw)
  To: jack; +Cc: linux-ext4

First patch allows ext2_msg to take a NULL sb since we don't have
that during option parsing - ext4 does the same.

Second patch lets it take an fc instead; it strikes me as a little
messy and I won't be offended if it's not wanted. :)

Thanks,
-Eric


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 1/2] ext2: convert to the new mount API
  2025-02-23 19:57 [PATCH 0/2] ext2: convert to the new mount API Eric Sandeen
@ 2025-02-23 19:57 ` Eric Sandeen
  2025-02-24 16:02   ` Jan Kara
  2025-02-23 19:57 ` [PATCH 2/2] ext2: create ext2_msg_fc for use during parsing Eric Sandeen
  1 sibling, 1 reply; 7+ messages in thread
From: Eric Sandeen @ 2025-02-23 19:57 UTC (permalink / raw)
  To: jack; +Cc: linux-ext4, Eric Sandeen

Convert ext2 to the new mount API.

Note that this makes the sb= option more accepting than it was before;
previosly, sb= was only accepted if it was the first specified option.
Now it can exist anywhere, and if respecified, the last specified value
is used.

Parse-time messages here are sent to ext2_msg with a NULL sb, and
ext2_msg is adjusted to accept that, as ext4 does today as well.

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
---
 fs/ext2/ext2.h  |   1 +
 fs/ext2/super.c | 571 ++++++++++++++++++++++++++----------------------
 2 files changed, 310 insertions(+), 262 deletions(-)

diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h
index f38bdd46e4f7..4025f875252a 100644
--- a/fs/ext2/ext2.h
+++ b/fs/ext2/ext2.h
@@ -368,6 +368,7 @@ struct ext2_inode {
 #define EXT2_MOUNT_ERRORS_CONT		0x000010  /* Continue on errors */
 #define EXT2_MOUNT_ERRORS_RO		0x000020  /* Remount fs ro on errors */
 #define EXT2_MOUNT_ERRORS_PANIC		0x000040  /* Panic on errors */
+#define EXT2_MOUNT_ERRORS_MASK		0x000070
 #define EXT2_MOUNT_MINIX_DF		0x000080  /* Mimics the Minix statfs */
 #define EXT2_MOUNT_NOBH			0x000100  /* No buffer_heads */
 #define EXT2_MOUNT_NO_UID32		0x000200  /* Disable 32-bit UIDs */
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index 37f7ce56adce..cb6253656eb2 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -23,7 +23,8 @@
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/blkdev.h>
-#include <linux/parser.h>
+#include <linux/fs_context.h>
+#include <linux/fs_parser.h>
 #include <linux/random.h>
 #include <linux/buffer_head.h>
 #include <linux/exportfs.h>
@@ -40,7 +41,6 @@
 #include "acl.h"
 
 static void ext2_write_super(struct super_block *sb);
-static int ext2_remount (struct super_block * sb, int * flags, char * data);
 static int ext2_statfs (struct dentry * dentry, struct kstatfs * buf);
 static int ext2_sync_fs(struct super_block *sb, int wait);
 static int ext2_freeze(struct super_block *sb);
@@ -92,7 +92,10 @@ void ext2_msg(struct super_block *sb, const char *prefix,
 	vaf.fmt = fmt;
 	vaf.va = &args;
 
-	printk("%sEXT2-fs (%s): %pV\n", prefix, sb->s_id, &vaf);
+	if (sb)
+		printk("%sEXT2-fs (%s): %pV\n", prefix, sb->s_id, &vaf);
+	else
+		printk("%sEXT2-fs: %pV\n", prefix, &vaf);
 
 	va_end(args);
 }
@@ -346,7 +349,6 @@ static const struct super_operations ext2_sops = {
 	.freeze_fs	= ext2_freeze,
 	.unfreeze_fs	= ext2_unfreeze,
 	.statfs		= ext2_statfs,
-	.remount_fs	= ext2_remount,
 	.show_options	= ext2_show_options,
 #ifdef CONFIG_QUOTA
 	.quota_read	= ext2_quota_read,
@@ -402,230 +404,217 @@ static const struct export_operations ext2_export_ops = {
 	.get_parent = ext2_get_parent,
 };
 
-static unsigned long get_sb_block(void **data)
-{
-	unsigned long 	sb_block;
-	char 		*options = (char *) *data;
-
-	if (!options || strncmp(options, "sb=", 3) != 0)
-		return 1;	/* Default location */
-	options += 3;
-	sb_block = simple_strtoul(options, &options, 0);
-	if (*options && *options != ',') {
-		printk("EXT2-fs: Invalid sb specification: %s\n",
-		       (char *) *data);
-		return 1;
-	}
-	if (*options == ',')
-		options++;
-	*data = (void *) options;
-	return sb_block;
-}
-
 enum {
-	Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid,
-	Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic,
-	Opt_err_ro, Opt_nouid32, Opt_debug,
-	Opt_oldalloc, Opt_orlov, Opt_nobh, Opt_user_xattr, Opt_nouser_xattr,
-	Opt_acl, Opt_noacl, Opt_xip, Opt_dax, Opt_ignore, Opt_err, Opt_quota,
-	Opt_usrquota, Opt_grpquota, Opt_reservation, Opt_noreservation
+	Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid, Opt_resgid, Opt_resuid,
+	Opt_sb, Opt_errors, Opt_nouid32, Opt_debug, Opt_oldalloc, Opt_orlov,
+	Opt_nobh, Opt_user_xattr, Opt_acl, Opt_xip, Opt_dax, Opt_ignore,
+	Opt_quota, Opt_usrquota, Opt_grpquota, Opt_reservation,
+};
+
+static const struct constant_table ext2_param_errors[] = {
+	{"continue",	EXT2_MOUNT_ERRORS_CONT},
+	{"panic",	EXT2_MOUNT_ERRORS_PANIC},
+	{"remount-ro",	EXT2_MOUNT_ERRORS_RO},
+	{}
+};
+
+const struct fs_parameter_spec ext2_param_spec[] = {
+	fsparam_flag	("bsddf", Opt_bsd_df),
+	fsparam_flag	("minixdf", Opt_minix_df),
+	fsparam_flag	("grpid", Opt_grpid),
+	fsparam_flag	("bsdgroups", Opt_grpid),
+	fsparam_flag	("nogrpid", Opt_nogrpid),
+	fsparam_flag	("sysvgroups", Opt_nogrpid),
+	fsparam_gid	("resgid", Opt_resgid),
+	fsparam_uid	("resuid", Opt_resuid),
+	fsparam_u32	("sb", Opt_sb),
+	fsparam_enum	("errors", Opt_errors, ext2_param_errors),
+	fsparam_flag	("nouid32", Opt_nouid32),
+	fsparam_flag	("debug", Opt_debug),
+	fsparam_flag	("oldalloc", Opt_oldalloc),
+	fsparam_flag	("orlov", Opt_orlov),
+	fsparam_flag	("nobh", Opt_nobh),
+	fsparam_flag_no	("user_xattr", Opt_user_xattr),
+	fsparam_flag_no	("acl", Opt_acl),
+	fsparam_flag	("xip", Opt_xip),
+	fsparam_flag	("dax", Opt_dax),
+	fsparam_flag	("grpquota", Opt_grpquota),
+	fsparam_flag	("noquota", Opt_ignore),
+	fsparam_flag	("quota", Opt_quota),
+	fsparam_flag	("usrquota", Opt_usrquota),
+	fsparam_flag_no	("reservation", Opt_reservation),
+	{}
 };
 
-static const match_table_t tokens = {
-	{Opt_bsd_df, "bsddf"},
-	{Opt_minix_df, "minixdf"},
-	{Opt_grpid, "grpid"},
-	{Opt_grpid, "bsdgroups"},
-	{Opt_nogrpid, "nogrpid"},
-	{Opt_nogrpid, "sysvgroups"},
-	{Opt_resgid, "resgid=%u"},
-	{Opt_resuid, "resuid=%u"},
-	{Opt_sb, "sb=%u"},
-	{Opt_err_cont, "errors=continue"},
-	{Opt_err_panic, "errors=panic"},
-	{Opt_err_ro, "errors=remount-ro"},
-	{Opt_nouid32, "nouid32"},
-	{Opt_debug, "debug"},
-	{Opt_oldalloc, "oldalloc"},
-	{Opt_orlov, "orlov"},
-	{Opt_nobh, "nobh"},
-	{Opt_user_xattr, "user_xattr"},
-	{Opt_nouser_xattr, "nouser_xattr"},
-	{Opt_acl, "acl"},
-	{Opt_noacl, "noacl"},
-	{Opt_xip, "xip"},
-	{Opt_dax, "dax"},
-	{Opt_grpquota, "grpquota"},
-	{Opt_ignore, "noquota"},
-	{Opt_quota, "quota"},
-	{Opt_usrquota, "usrquota"},
-	{Opt_reservation, "reservation"},
-	{Opt_noreservation, "noreservation"},
-	{Opt_err, NULL}
+#define EXT2_SPEC_s_resuid                      (1 << 0)
+#define EXT2_SPEC_s_resgid                      (1 << 1)
+
+struct ext2_fs_context {
+	unsigned long	vals_s_flags;	/* Bits to set in s_flags */
+	unsigned long	mask_s_flags;	/* Bits changed in s_flags */
+	unsigned int	vals_s_mount_opt;
+	unsigned int	mask_s_mount_opt;
+	kuid_t		s_resuid;
+	kgid_t		s_resgid;
+	unsigned long	s_sb_block;
+	unsigned int	spec;
+
 };
 
-static int parse_options(char *options, struct super_block *sb,
-			 struct ext2_mount_options *opts)
+static inline void ctx_set_mount_opt(struct ext2_fs_context *ctx,
+				  unsigned long flag)
+{
+	ctx->mask_s_mount_opt |= flag;
+	ctx->vals_s_mount_opt |= flag;
+}
+
+static inline void ctx_clear_mount_opt(struct ext2_fs_context *ctx,
+				    unsigned long flag)
+{
+	ctx->mask_s_mount_opt |= flag;
+	ctx->vals_s_mount_opt &= ~flag;
+}
+
+static inline unsigned long
+ctx_test_mount_opt(struct ext2_fs_context *ctx, unsigned long flag)
+{
+	return (ctx->vals_s_mount_opt & flag);
+}
+
+static inline bool
+ctx_parsed_mount_opt(struct ext2_fs_context *ctx, unsigned long flag)
+{
+	return (ctx->mask_s_mount_opt & flag);
+}
+
+static void ext2_free_fc(struct fs_context *fc)
 {
-	char *p;
-	substring_t args[MAX_OPT_ARGS];
-	int option;
-	kuid_t uid;
-	kgid_t gid;
-
-	if (!options)
-		return 1;
-
-	while ((p = strsep (&options, ",")) != NULL) {
-		int token;
-		if (!*p)
-			continue;
-
-		token = match_token(p, tokens, args);
-		switch (token) {
-		case Opt_bsd_df:
-			clear_opt (opts->s_mount_opt, MINIX_DF);
-			break;
-		case Opt_minix_df:
-			set_opt (opts->s_mount_opt, MINIX_DF);
-			break;
-		case Opt_grpid:
-			set_opt (opts->s_mount_opt, GRPID);
-			break;
-		case Opt_nogrpid:
-			clear_opt (opts->s_mount_opt, GRPID);
-			break;
-		case Opt_resuid:
-			if (match_int(&args[0], &option))
-				return 0;
-			uid = make_kuid(current_user_ns(), option);
-			if (!uid_valid(uid)) {
-				ext2_msg(sb, KERN_ERR, "Invalid uid value %d", option);
-				return 0;
-
-			}
-			opts->s_resuid = uid;
-			break;
-		case Opt_resgid:
-			if (match_int(&args[0], &option))
-				return 0;
-			gid = make_kgid(current_user_ns(), option);
-			if (!gid_valid(gid)) {
-				ext2_msg(sb, KERN_ERR, "Invalid gid value %d", option);
-				return 0;
-			}
-			opts->s_resgid = gid;
-			break;
-		case Opt_sb:
-			/* handled by get_sb_block() instead of here */
-			/* *sb_block = match_int(&args[0]); */
-			break;
-		case Opt_err_panic:
-			clear_opt (opts->s_mount_opt, ERRORS_CONT);
-			clear_opt (opts->s_mount_opt, ERRORS_RO);
-			set_opt (opts->s_mount_opt, ERRORS_PANIC);
-			break;
-		case Opt_err_ro:
-			clear_opt (opts->s_mount_opt, ERRORS_CONT);
-			clear_opt (opts->s_mount_opt, ERRORS_PANIC);
-			set_opt (opts->s_mount_opt, ERRORS_RO);
-			break;
-		case Opt_err_cont:
-			clear_opt (opts->s_mount_opt, ERRORS_RO);
-			clear_opt (opts->s_mount_opt, ERRORS_PANIC);
-			set_opt (opts->s_mount_opt, ERRORS_CONT);
-			break;
-		case Opt_nouid32:
-			set_opt (opts->s_mount_opt, NO_UID32);
-			break;
-		case Opt_debug:
-			set_opt (opts->s_mount_opt, DEBUG);
-			break;
-		case Opt_oldalloc:
-			set_opt (opts->s_mount_opt, OLDALLOC);
-			break;
-		case Opt_orlov:
-			clear_opt (opts->s_mount_opt, OLDALLOC);
-			break;
-		case Opt_nobh:
-			ext2_msg(sb, KERN_INFO,
-				"nobh option not supported");
-			break;
+	kfree(fc->fs_private);
+}
+
+static int ext2_parse_param(struct fs_context *fc, struct fs_parameter *param)
+{
+	struct ext2_fs_context *ctx = fc->fs_private;
+	int opt;
+	struct fs_parse_result result;
+
+	opt = fs_parse(fc, ext2_param_spec, param, &result);
+	if (opt < 0)
+		return opt;
+
+	switch (opt) {
+	case Opt_bsd_df:
+		ctx_clear_mount_opt(ctx, EXT2_MOUNT_MINIX_DF);
+		break;
+	case Opt_minix_df:
+		ctx_set_mount_opt(ctx, EXT2_MOUNT_MINIX_DF);
+		break;
+	case Opt_grpid:
+		ctx_set_mount_opt(ctx, EXT2_MOUNT_GRPID);
+		break;
+	case Opt_nogrpid:
+		ctx_clear_mount_opt(ctx, EXT2_MOUNT_GRPID);
+		break;
+	case Opt_resuid:
+		ctx->s_resuid = result.uid;
+		ctx->spec |= EXT2_SPEC_s_resuid;
+		break;
+	case Opt_resgid:
+		ctx->s_resgid = result.gid;
+		ctx->spec |= EXT2_SPEC_s_resgid;
+		break;
+	case Opt_sb:
+		/* Note that this is silently ignored on remount */
+		ctx->s_sb_block = result.uint_32;
+		break;
+	case Opt_errors:
+		ctx_clear_mount_opt(ctx, EXT2_MOUNT_ERRORS_MASK);
+		ctx_set_mount_opt(ctx, result.uint_32);
+		break;
+	case Opt_nouid32:
+		ctx_set_mount_opt(ctx, EXT2_MOUNT_NO_UID32);
+		break;
+	case Opt_debug:
+		ctx_set_mount_opt(ctx, EXT2_MOUNT_DEBUG);
+		break;
+	case Opt_oldalloc:
+		ctx_set_mount_opt(ctx, EXT2_MOUNT_OLDALLOC);
+		break;
+	case Opt_orlov:
+		ctx_clear_mount_opt(ctx, EXT2_MOUNT_OLDALLOC);
+		break;
+	case Opt_nobh:
+		ext2_msg(NULL, KERN_INFO, "nobh option not supported\n");
+		break;
 #ifdef CONFIG_EXT2_FS_XATTR
-		case Opt_user_xattr:
-			set_opt (opts->s_mount_opt, XATTR_USER);
-			break;
-		case Opt_nouser_xattr:
-			clear_opt (opts->s_mount_opt, XATTR_USER);
-			break;
+	case Opt_user_xattr:
+		if (!result.negated)
+			ctx_set_mount_opt(ctx, EXT2_MOUNT_XATTR_USER);
+		else
+			ctx_clear_mount_opt(ctx, EXT2_MOUNT_XATTR_USER);
+		break;
 #else
-		case Opt_user_xattr:
-		case Opt_nouser_xattr:
-			ext2_msg(sb, KERN_INFO, "(no)user_xattr options"
-				"not supported");
-			break;
+	case Opt_user_xattr:
+		ext2_msg(NULL, KERN_INFO, "(no)user_xattr options not supported");
+		break;
 #endif
 #ifdef CONFIG_EXT2_FS_POSIX_ACL
-		case Opt_acl:
-			set_opt(opts->s_mount_opt, POSIX_ACL);
-			break;
-		case Opt_noacl:
-			clear_opt(opts->s_mount_opt, POSIX_ACL);
-			break;
+	case Opt_acl:
+		if (!result.negated)
+			ctx_set_mount_opt(ctx, EXT2_MOUNT_POSIX_ACL);
+		else
+			ctx_clear_mount_opt(ctx, EXT2_MOUNT_POSIX_ACL);
+		break;
 #else
-		case Opt_acl:
-		case Opt_noacl:
-			ext2_msg(sb, KERN_INFO,
-				"(no)acl options not supported");
-			break;
+	case Opt_acl:
+		ext2_msg(NULL, KERN_INFO, "(no)acl options not supported");
+		break;
 #endif
-		case Opt_xip:
-			ext2_msg(sb, KERN_INFO, "use dax instead of xip");
-			set_opt(opts->s_mount_opt, XIP);
-			fallthrough;
-		case Opt_dax:
+	case Opt_xip:
+		ext2_msg(NULL, KERN_INFO, "use dax instead of xip");
+		ctx_set_mount_opt(ctx, EXT2_MOUNT_XIP);
+		fallthrough;
+	case Opt_dax:
 #ifdef CONFIG_FS_DAX
-			ext2_msg(sb, KERN_WARNING,
-		"DAX enabled. Warning: EXPERIMENTAL, use at your own risk");
-			set_opt(opts->s_mount_opt, DAX);
+		ext2_msg(NULL, KERN_WARNING,
+		    "DAX enabled. Warning: EXPERIMENTAL, use at your own risk");
+		ctx_set_mount_opt(ctx, EXT2_MOUNT_DAX);
 #else
-			ext2_msg(sb, KERN_INFO, "dax option not supported");
+		ext2_msg(NULL, KERN_INFO, "dax option not supported");
 #endif
-			break;
+		break;
 
 #if defined(CONFIG_QUOTA)
-		case Opt_quota:
-		case Opt_usrquota:
-			set_opt(opts->s_mount_opt, USRQUOTA);
-			break;
-
-		case Opt_grpquota:
-			set_opt(opts->s_mount_opt, GRPQUOTA);
-			break;
+	case Opt_quota:
+	case Opt_usrquota:
+		ctx_set_mount_opt(ctx, EXT2_MOUNT_USRQUOTA);
+		break;
+
+	case Opt_grpquota:
+		ctx_set_mount_opt(ctx, EXT2_MOUNT_GRPQUOTA);
+		break;
 #else
-		case Opt_quota:
-		case Opt_usrquota:
-		case Opt_grpquota:
-			ext2_msg(sb, KERN_INFO,
-				"quota operations not supported");
-			break;
+	case Opt_quota:
+	case Opt_usrquota:
+	case Opt_grpquota:
+		ext2_msg(NULL, KERN_INFO, "quota operations not supported");
+		break;
 #endif
-
-		case Opt_reservation:
-			set_opt(opts->s_mount_opt, RESERVATION);
-			ext2_msg(sb, KERN_INFO, "reservations ON");
-			break;
-		case Opt_noreservation:
-			clear_opt(opts->s_mount_opt, RESERVATION);
-			ext2_msg(sb, KERN_INFO, "reservations OFF");
-			break;
-		case Opt_ignore:
-			break;
-		default:
-			return 0;
+	case Opt_reservation:
+		if (!result.negated) {
+			ctx_set_mount_opt(ctx, EXT2_MOUNT_RESERVATION);
+			ext2_msg(NULL, KERN_INFO, "reservations ON");
+		} else {
+			ctx_clear_mount_opt(ctx, EXT2_MOUNT_RESERVATION);
+			ext2_msg(NULL, KERN_INFO, "reservations OFF");
 		}
+		break;
+	case Opt_ignore:
+		break;
+	default:
+		return -EINVAL;
 	}
-	return 1;
+	return 0;
 }
 
 static int ext2_setup_super (struct super_block * sb,
@@ -801,24 +790,83 @@ static unsigned long descriptor_loc(struct super_block *sb,
 	return ext2_group_first_block_no(sb, bg) + ext2_bg_has_super(sb, bg);
 }
 
-static int ext2_fill_super(struct super_block *sb, void *data, int silent)
+/*
+ * Set all mount options either from defaults on disk, or from parsed
+ * options. Parsed/specified options override on-disk defaults.
+ */
+static void ext2_set_options(struct fs_context *fc, struct ext2_sb_info *sbi)
 {
+	struct ext2_fs_context *ctx = fc->fs_private;
+	struct ext2_super_block *es = sbi->s_es;
+	unsigned long def_mount_opts = le32_to_cpu(es->s_default_mount_opts);
+
+	/* Copy parsed mount options to sbi */
+	sbi->s_mount_opt = ctx->vals_s_mount_opt;
+
+	/* Use in-superblock defaults only if not specified during parsing */
+	if (!ctx_parsed_mount_opt(ctx, EXT2_MOUNT_DEBUG) &&
+	    def_mount_opts & EXT2_DEFM_DEBUG)
+		set_opt(sbi->s_mount_opt, DEBUG);
+
+	if (!ctx_parsed_mount_opt(ctx, EXT2_MOUNT_GRPID) &&
+	    def_mount_opts & EXT2_DEFM_BSDGROUPS)
+		set_opt(sbi->s_mount_opt, GRPID);
+
+	if (!ctx_parsed_mount_opt(ctx, EXT2_MOUNT_NO_UID32) &&
+	    def_mount_opts & EXT2_DEFM_UID16)
+		set_opt(sbi->s_mount_opt, NO_UID32);
+
+#ifdef CONFIG_EXT2_FS_XATTR
+	if (!ctx_parsed_mount_opt(ctx, EXT2_MOUNT_XATTR_USER) &&
+	    def_mount_opts & EXT2_DEFM_XATTR_USER)
+		set_opt(sbi->s_mount_opt, XATTR_USER);
+#endif
+#ifdef CONFIG_EXT2_FS_POSIX_ACL
+	if (!ctx_parsed_mount_opt(ctx, EXT2_MOUNT_POSIX_ACL) &&
+	    def_mount_opts & EXT2_DEFM_ACL)
+		set_opt(sbi->s_mount_opt, POSIX_ACL);
+#endif
+
+	if (!ctx_parsed_mount_opt(ctx, EXT2_MOUNT_ERRORS_MASK)) {
+		if (le16_to_cpu(sbi->s_es->s_errors) == EXT2_ERRORS_PANIC)
+			set_opt(sbi->s_mount_opt, ERRORS_PANIC);
+		else if (le16_to_cpu(sbi->s_es->s_errors) == EXT2_ERRORS_CONTINUE)
+			set_opt(sbi->s_mount_opt, ERRORS_CONT);
+		else
+			set_opt(sbi->s_mount_opt, ERRORS_RO);
+	}
+
+	if (ctx->spec & EXT2_SPEC_s_resuid)
+		sbi->s_resuid = ctx->s_resuid;
+	else
+		sbi->s_resuid = make_kuid(&init_user_ns,
+					   le16_to_cpu(es->s_def_resuid));
+
+	if (ctx->spec & EXT2_SPEC_s_resgid)
+		sbi->s_resgid = ctx->s_resgid;
+	else
+		sbi->s_resgid = make_kgid(&init_user_ns,
+					   le16_to_cpu(es->s_def_resgid));
+}
+
+static int ext2_fill_super(struct super_block *sb, struct fs_context *fc)
+{
+	struct ext2_fs_context *ctx = fc->fs_private;
+	int silent = fc->sb_flags & SB_SILENT;
 	struct buffer_head * bh;
 	struct ext2_sb_info * sbi;
 	struct ext2_super_block * es;
 	struct inode *root;
 	unsigned long block;
-	unsigned long sb_block = get_sb_block(&data);
+	unsigned long sb_block = ctx->s_sb_block;
 	unsigned long logic_sb_block;
 	unsigned long offset = 0;
-	unsigned long def_mount_opts;
 	long ret = -ENOMEM;
 	int blocksize = BLOCK_SIZE;
 	int db_count;
 	int i, j;
 	__le32 features;
 	int err;
-	struct ext2_mount_options opts;
 
 	sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
 	if (!sbi)
@@ -877,42 +925,7 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
 	if (sb->s_magic != EXT2_SUPER_MAGIC)
 		goto cantfind_ext2;
 
-	opts.s_mount_opt = 0;
-	/* Set defaults before we parse the mount options */
-	def_mount_opts = le32_to_cpu(es->s_default_mount_opts);
-	if (def_mount_opts & EXT2_DEFM_DEBUG)
-		set_opt(opts.s_mount_opt, DEBUG);
-	if (def_mount_opts & EXT2_DEFM_BSDGROUPS)
-		set_opt(opts.s_mount_opt, GRPID);
-	if (def_mount_opts & EXT2_DEFM_UID16)
-		set_opt(opts.s_mount_opt, NO_UID32);
-#ifdef CONFIG_EXT2_FS_XATTR
-	if (def_mount_opts & EXT2_DEFM_XATTR_USER)
-		set_opt(opts.s_mount_opt, XATTR_USER);
-#endif
-#ifdef CONFIG_EXT2_FS_POSIX_ACL
-	if (def_mount_opts & EXT2_DEFM_ACL)
-		set_opt(opts.s_mount_opt, POSIX_ACL);
-#endif
-	
-	if (le16_to_cpu(sbi->s_es->s_errors) == EXT2_ERRORS_PANIC)
-		set_opt(opts.s_mount_opt, ERRORS_PANIC);
-	else if (le16_to_cpu(sbi->s_es->s_errors) == EXT2_ERRORS_CONTINUE)
-		set_opt(opts.s_mount_opt, ERRORS_CONT);
-	else
-		set_opt(opts.s_mount_opt, ERRORS_RO);
-
-	opts.s_resuid = make_kuid(&init_user_ns, le16_to_cpu(es->s_def_resuid));
-	opts.s_resgid = make_kgid(&init_user_ns, le16_to_cpu(es->s_def_resgid));
-	
-	set_opt(opts.s_mount_opt, RESERVATION);
-
-	if (!parse_options((char *) data, sb, &opts))
-		goto failed_mount;
-
-	sbi->s_mount_opt = opts.s_mount_opt;
-	sbi->s_resuid = opts.s_resuid;
-	sbi->s_resgid = opts.s_resgid;
+	ext2_set_options(fc, sbi);
 
 	sb->s_flags = (sb->s_flags & ~SB_POSIXACL) |
 		(test_opt(sb, POSIX_ACL) ? SB_POSIXACL : 0);
@@ -1324,23 +1337,21 @@ static void ext2_write_super(struct super_block *sb)
 		ext2_sync_fs(sb, 1);
 }
 
-static int ext2_remount (struct super_block * sb, int * flags, char * data)
+static int ext2_reconfigure(struct fs_context *fc)
 {
+	struct ext2_fs_context *ctx = fc->fs_private;
+	struct super_block *sb = fc->root->d_sb;
 	struct ext2_sb_info * sbi = EXT2_SB(sb);
 	struct ext2_super_block * es;
 	struct ext2_mount_options new_opts;
+	int flags = fc->sb_flags;
 	int err;
 
 	sync_filesystem(sb);
 
-	spin_lock(&sbi->s_lock);
-	new_opts.s_mount_opt = sbi->s_mount_opt;
-	new_opts.s_resuid = sbi->s_resuid;
-	new_opts.s_resgid = sbi->s_resgid;
-	spin_unlock(&sbi->s_lock);
-
-	if (!parse_options(data, sb, &new_opts))
-		return -EINVAL;
+	new_opts.s_mount_opt = ctx->vals_s_mount_opt;
+	new_opts.s_resuid = ctx->s_resuid;
+	new_opts.s_resgid = ctx->s_resgid;
 
 	spin_lock(&sbi->s_lock);
 	es = sbi->s_es;
@@ -1349,9 +1360,9 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data)
 			 "dax flag with busy inodes while remounting");
 		new_opts.s_mount_opt ^= EXT2_MOUNT_DAX;
 	}
-	if ((bool)(*flags & SB_RDONLY) == sb_rdonly(sb))
+	if ((bool)(flags & SB_RDONLY) == sb_rdonly(sb))
 		goto out_set;
-	if (*flags & SB_RDONLY) {
+	if (flags & SB_RDONLY) {
 		if (le16_to_cpu(es->s_state) & EXT2_VALID_FS ||
 		    !(sbi->s_mount_state & EXT2_VALID_FS))
 			goto out_set;
@@ -1470,10 +1481,9 @@ static int ext2_statfs (struct dentry * dentry, struct kstatfs * buf)
 	return 0;
 }
 
-static struct dentry *ext2_mount(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *data)
+static int ext2_get_tree(struct fs_context *fc)
 {
-	return mount_bdev(fs_type, flags, dev_name, data, ext2_fill_super);
+	return get_tree_bdev(fc, ext2_fill_super);
 }
 
 #ifdef CONFIG_QUOTA
@@ -1624,12 +1634,49 @@ static int ext2_quota_off(struct super_block *sb, int type)
 
 #endif
 
+static const struct fs_context_operations ext2_context_ops = {
+	.parse_param	= ext2_parse_param,
+	.get_tree	= ext2_get_tree,
+	.reconfigure	= ext2_reconfigure,
+	.free		= ext2_free_fc,
+};
+
+static int ext2_init_fs_context(struct fs_context *fc)
+{
+	struct ext2_fs_context *ctx;
+
+	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	if (fc->purpose == FS_CONTEXT_FOR_RECONFIGURE) {
+		struct super_block *sb = fc->root->d_sb;
+		struct ext2_sb_info *sbi = EXT2_SB(sb);
+
+		spin_lock(&sbi->s_lock);
+		ctx->vals_s_mount_opt = sbi->s_mount_opt;
+		ctx->vals_s_flags = sb->s_flags;
+		ctx->s_resuid = sbi->s_resuid;
+		ctx->s_resgid = sbi->s_resgid;
+		spin_unlock(&sbi->s_lock);
+	} else {
+		ctx->s_sb_block = 1;
+		ctx_set_mount_opt(ctx, EXT2_MOUNT_RESERVATION);
+	}
+
+	fc->fs_private = ctx;
+	fc->ops = &ext2_context_ops;
+
+	return 0;
+}
+
 static struct file_system_type ext2_fs_type = {
 	.owner		= THIS_MODULE,
 	.name		= "ext2",
-	.mount		= ext2_mount,
 	.kill_sb	= kill_block_super,
 	.fs_flags	= FS_REQUIRES_DEV,
+	.init_fs_context = ext2_init_fs_context,
+	.parameters	= ext2_param_spec,
 };
 MODULE_ALIAS_FS("ext2");
 
-- 
2.48.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 2/2] ext2: create ext2_msg_fc for use during parsing
  2025-02-23 19:57 [PATCH 0/2] ext2: convert to the new mount API Eric Sandeen
  2025-02-23 19:57 ` [PATCH 1/2] " Eric Sandeen
@ 2025-02-23 19:57 ` Eric Sandeen
  2025-02-24 16:01   ` Jan Kara
  1 sibling, 1 reply; 7+ messages in thread
From: Eric Sandeen @ 2025-02-23 19:57 UTC (permalink / raw)
  To: jack; +Cc: linux-ext4, Eric Sandeen

Rather than send a NULL sb to ext2_msg, which omits the s_id from
messages, create a new ext2_msg_fc which is able to provide this
information from the filesystem context *fc when parsing.

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
---
 fs/ext2/super.c | 48 +++++++++++++++++++++++++++++++++++-------------
 1 file changed, 35 insertions(+), 13 deletions(-)

diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index cb6253656eb2..2a4c007972b9 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -81,6 +81,31 @@ void ext2_error(struct super_block *sb, const char *function,
 	}
 }
 
+static void ext2_msg_fc(struct fs_context *fc, const char *prefix,
+			const char *fmt, ...)
+{
+	struct va_format vaf;
+	va_list args;
+	const char *s_id;
+
+	if (fc->purpose == FS_CONTEXT_FOR_RECONFIGURE) {
+		s_id = fc->root->d_sb->s_id;
+	} else {
+		/* get last path component of source */
+		s_id = strrchr(fc->source, '/');
+		if (s_id)
+			s_id++;
+	}
+	va_start(args, fmt);
+
+	vaf.fmt = fmt;
+	vaf.va = &args;
+
+	printk("%sEXT2-fs (%s): %pV\n", prefix, s_id, &vaf);
+
+	va_end(args);
+}
+
 void ext2_msg(struct super_block *sb, const char *prefix,
 		const char *fmt, ...)
 {
@@ -92,10 +117,7 @@ void ext2_msg(struct super_block *sb, const char *prefix,
 	vaf.fmt = fmt;
 	vaf.va = &args;
 
-	if (sb)
-		printk("%sEXT2-fs (%s): %pV\n", prefix, sb->s_id, &vaf);
-	else
-		printk("%sEXT2-fs: %pV\n", prefix, &vaf);
+	printk("%sEXT2-fs (%s): %pV\n", prefix, sb->s_id, &vaf);
 
 	va_end(args);
 }
@@ -544,7 +566,7 @@ static int ext2_parse_param(struct fs_context *fc, struct fs_parameter *param)
 		ctx_clear_mount_opt(ctx, EXT2_MOUNT_OLDALLOC);
 		break;
 	case Opt_nobh:
-		ext2_msg(NULL, KERN_INFO, "nobh option not supported\n");
+		ext2_msg_fc(fc, KERN_INFO, "nobh option not supported\n");
 		break;
 #ifdef CONFIG_EXT2_FS_XATTR
 	case Opt_user_xattr:
@@ -555,7 +577,7 @@ static int ext2_parse_param(struct fs_context *fc, struct fs_parameter *param)
 		break;
 #else
 	case Opt_user_xattr:
-		ext2_msg(NULL, KERN_INFO, "(no)user_xattr options not supported");
+		ext2_msg_fc(fc, KERN_INFO, "(no)user_xattr options not supported");
 		break;
 #endif
 #ifdef CONFIG_EXT2_FS_POSIX_ACL
@@ -567,20 +589,20 @@ static int ext2_parse_param(struct fs_context *fc, struct fs_parameter *param)
 		break;
 #else
 	case Opt_acl:
-		ext2_msg(NULL, KERN_INFO, "(no)acl options not supported");
+		ext2_msg_fc(fc, KERN_INFO, "(no)acl options not supported");
 		break;
 #endif
 	case Opt_xip:
-		ext2_msg(NULL, KERN_INFO, "use dax instead of xip");
+		ext2_msg_fc(fc, KERN_INFO, "use dax instead of xip");
 		ctx_set_mount_opt(ctx, EXT2_MOUNT_XIP);
 		fallthrough;
 	case Opt_dax:
 #ifdef CONFIG_FS_DAX
-		ext2_msg(NULL, KERN_WARNING,
+		ext2_msg_fc(fc, KERN_WARNING,
 		    "DAX enabled. Warning: EXPERIMENTAL, use at your own risk");
 		ctx_set_mount_opt(ctx, EXT2_MOUNT_DAX);
 #else
-		ext2_msg(NULL, KERN_INFO, "dax option not supported");
+		ext2_msg_fc(fc, KERN_INFO, "dax option not supported");
 #endif
 		break;
 
@@ -597,16 +619,16 @@ static int ext2_parse_param(struct fs_context *fc, struct fs_parameter *param)
 	case Opt_quota:
 	case Opt_usrquota:
 	case Opt_grpquota:
-		ext2_msg(NULL, KERN_INFO, "quota operations not supported");
+		ext2_msg_fc(fc, KERN_INFO, "quota operations not supported");
 		break;
 #endif
 	case Opt_reservation:
 		if (!result.negated) {
 			ctx_set_mount_opt(ctx, EXT2_MOUNT_RESERVATION);
-			ext2_msg(NULL, KERN_INFO, "reservations ON");
+			ext2_msg_fc(fc, KERN_INFO, "reservations ON");
 		} else {
 			ctx_clear_mount_opt(ctx, EXT2_MOUNT_RESERVATION);
-			ext2_msg(NULL, KERN_INFO, "reservations OFF");
+			ext2_msg_fc(fc, KERN_INFO, "reservations OFF");
 		}
 		break;
 	case Opt_ignore:
-- 
2.48.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH 2/2] ext2: create ext2_msg_fc for use during parsing
  2025-02-23 19:57 ` [PATCH 2/2] ext2: create ext2_msg_fc for use during parsing Eric Sandeen
@ 2025-02-24 16:01   ` Jan Kara
  0 siblings, 0 replies; 7+ messages in thread
From: Jan Kara @ 2025-02-24 16:01 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: jack, linux-ext4

On Sun 23-02-25 13:57:41, Eric Sandeen wrote:
> Rather than send a NULL sb to ext2_msg, which omits the s_id from
> messages, create a new ext2_msg_fc which is able to provide this
> information from the filesystem context *fc when parsing.
> 
> Signed-off-by: Eric Sandeen <sandeen@redhat.com>
...
> +static void ext2_msg_fc(struct fs_context *fc, const char *prefix,
> +			const char *fmt, ...)
> +{
> +	struct va_format vaf;
> +	va_list args;
> +	const char *s_id;
> +
> +	if (fc->purpose == FS_CONTEXT_FOR_RECONFIGURE) {
> +		s_id = fc->root->d_sb->s_id;

So the remount handling is definitely valuable...

> +	} else {
> +		/* get last path component of source */
> +		s_id = strrchr(fc->source, '/');
> +		if (s_id)
> +			s_id++;
> +	}

And this isn't too bad but I think it will crash if fc->source has no / in
it? I'll fix that up on commit.

Thanks for the patch!

								Honza

> +	va_start(args, fmt);
> +
> +	vaf.fmt = fmt;
> +	vaf.va = &args;
> +
> +	printk("%sEXT2-fs (%s): %pV\n", prefix, s_id, &vaf);
> +
> +	va_end(args);
> +}
> +
>  void ext2_msg(struct super_block *sb, const char *prefix,
>  		const char *fmt, ...)
>  {
> @@ -92,10 +117,7 @@ void ext2_msg(struct super_block *sb, const char *prefix,
>  	vaf.fmt = fmt;
>  	vaf.va = &args;
>  
> -	if (sb)
> -		printk("%sEXT2-fs (%s): %pV\n", prefix, sb->s_id, &vaf);
> -	else
> -		printk("%sEXT2-fs: %pV\n", prefix, &vaf);
> +	printk("%sEXT2-fs (%s): %pV\n", prefix, sb->s_id, &vaf);
>  
>  	va_end(args);
>  }
> @@ -544,7 +566,7 @@ static int ext2_parse_param(struct fs_context *fc, struct fs_parameter *param)
>  		ctx_clear_mount_opt(ctx, EXT2_MOUNT_OLDALLOC);
>  		break;
>  	case Opt_nobh:
> -		ext2_msg(NULL, KERN_INFO, "nobh option not supported\n");
> +		ext2_msg_fc(fc, KERN_INFO, "nobh option not supported\n");
>  		break;
>  #ifdef CONFIG_EXT2_FS_XATTR
>  	case Opt_user_xattr:
> @@ -555,7 +577,7 @@ static int ext2_parse_param(struct fs_context *fc, struct fs_parameter *param)
>  		break;
>  #else
>  	case Opt_user_xattr:
> -		ext2_msg(NULL, KERN_INFO, "(no)user_xattr options not supported");
> +		ext2_msg_fc(fc, KERN_INFO, "(no)user_xattr options not supported");
>  		break;
>  #endif
>  #ifdef CONFIG_EXT2_FS_POSIX_ACL
> @@ -567,20 +589,20 @@ static int ext2_parse_param(struct fs_context *fc, struct fs_parameter *param)
>  		break;
>  #else
>  	case Opt_acl:
> -		ext2_msg(NULL, KERN_INFO, "(no)acl options not supported");
> +		ext2_msg_fc(fc, KERN_INFO, "(no)acl options not supported");
>  		break;
>  #endif
>  	case Opt_xip:
> -		ext2_msg(NULL, KERN_INFO, "use dax instead of xip");
> +		ext2_msg_fc(fc, KERN_INFO, "use dax instead of xip");
>  		ctx_set_mount_opt(ctx, EXT2_MOUNT_XIP);
>  		fallthrough;
>  	case Opt_dax:
>  #ifdef CONFIG_FS_DAX
> -		ext2_msg(NULL, KERN_WARNING,
> +		ext2_msg_fc(fc, KERN_WARNING,
>  		    "DAX enabled. Warning: EXPERIMENTAL, use at your own risk");
>  		ctx_set_mount_opt(ctx, EXT2_MOUNT_DAX);
>  #else
> -		ext2_msg(NULL, KERN_INFO, "dax option not supported");
> +		ext2_msg_fc(fc, KERN_INFO, "dax option not supported");
>  #endif
>  		break;
>  
> @@ -597,16 +619,16 @@ static int ext2_parse_param(struct fs_context *fc, struct fs_parameter *param)
>  	case Opt_quota:
>  	case Opt_usrquota:
>  	case Opt_grpquota:
> -		ext2_msg(NULL, KERN_INFO, "quota operations not supported");
> +		ext2_msg_fc(fc, KERN_INFO, "quota operations not supported");
>  		break;
>  #endif
>  	case Opt_reservation:
>  		if (!result.negated) {
>  			ctx_set_mount_opt(ctx, EXT2_MOUNT_RESERVATION);
> -			ext2_msg(NULL, KERN_INFO, "reservations ON");
> +			ext2_msg_fc(fc, KERN_INFO, "reservations ON");
>  		} else {
>  			ctx_clear_mount_opt(ctx, EXT2_MOUNT_RESERVATION);
> -			ext2_msg(NULL, KERN_INFO, "reservations OFF");
> +			ext2_msg_fc(fc, KERN_INFO, "reservations OFF");
>  		}
>  		break;
>  	case Opt_ignore:
> -- 
> 2.48.0
> 
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/2] ext2: convert to the new mount API
  2025-02-23 19:57 ` [PATCH 1/2] " Eric Sandeen
@ 2025-02-24 16:02   ` Jan Kara
  2025-02-26 16:42     ` Eric Sandeen
  0 siblings, 1 reply; 7+ messages in thread
From: Jan Kara @ 2025-02-24 16:02 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: jack, linux-ext4

On Sun 23-02-25 13:57:40, Eric Sandeen wrote:
> Convert ext2 to the new mount API.
> 
> Note that this makes the sb= option more accepting than it was before;
> previosly, sb= was only accepted if it was the first specified option.
> Now it can exist anywhere, and if respecified, the last specified value
> is used.
> 
> Parse-time messages here are sent to ext2_msg with a NULL sb, and
> ext2_msg is adjusted to accept that, as ext4 does today as well.
> 
> Signed-off-by: Eric Sandeen <sandeen@redhat.com>

Looks good to me. Thanks!

									Honza

> ---
>  fs/ext2/ext2.h  |   1 +
>  fs/ext2/super.c | 571 ++++++++++++++++++++++++++----------------------
>  2 files changed, 310 insertions(+), 262 deletions(-)
> 
> diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h
> index f38bdd46e4f7..4025f875252a 100644
> --- a/fs/ext2/ext2.h
> +++ b/fs/ext2/ext2.h
> @@ -368,6 +368,7 @@ struct ext2_inode {
>  #define EXT2_MOUNT_ERRORS_CONT		0x000010  /* Continue on errors */
>  #define EXT2_MOUNT_ERRORS_RO		0x000020  /* Remount fs ro on errors */
>  #define EXT2_MOUNT_ERRORS_PANIC		0x000040  /* Panic on errors */
> +#define EXT2_MOUNT_ERRORS_MASK		0x000070
>  #define EXT2_MOUNT_MINIX_DF		0x000080  /* Mimics the Minix statfs */
>  #define EXT2_MOUNT_NOBH			0x000100  /* No buffer_heads */
>  #define EXT2_MOUNT_NO_UID32		0x000200  /* Disable 32-bit UIDs */
> diff --git a/fs/ext2/super.c b/fs/ext2/super.c
> index 37f7ce56adce..cb6253656eb2 100644
> --- a/fs/ext2/super.c
> +++ b/fs/ext2/super.c
> @@ -23,7 +23,8 @@
>  #include <linux/slab.h>
>  #include <linux/init.h>
>  #include <linux/blkdev.h>
> -#include <linux/parser.h>
> +#include <linux/fs_context.h>
> +#include <linux/fs_parser.h>
>  #include <linux/random.h>
>  #include <linux/buffer_head.h>
>  #include <linux/exportfs.h>
> @@ -40,7 +41,6 @@
>  #include "acl.h"
>  
>  static void ext2_write_super(struct super_block *sb);
> -static int ext2_remount (struct super_block * sb, int * flags, char * data);
>  static int ext2_statfs (struct dentry * dentry, struct kstatfs * buf);
>  static int ext2_sync_fs(struct super_block *sb, int wait);
>  static int ext2_freeze(struct super_block *sb);
> @@ -92,7 +92,10 @@ void ext2_msg(struct super_block *sb, const char *prefix,
>  	vaf.fmt = fmt;
>  	vaf.va = &args;
>  
> -	printk("%sEXT2-fs (%s): %pV\n", prefix, sb->s_id, &vaf);
> +	if (sb)
> +		printk("%sEXT2-fs (%s): %pV\n", prefix, sb->s_id, &vaf);
> +	else
> +		printk("%sEXT2-fs: %pV\n", prefix, &vaf);
>  
>  	va_end(args);
>  }
> @@ -346,7 +349,6 @@ static const struct super_operations ext2_sops = {
>  	.freeze_fs	= ext2_freeze,
>  	.unfreeze_fs	= ext2_unfreeze,
>  	.statfs		= ext2_statfs,
> -	.remount_fs	= ext2_remount,
>  	.show_options	= ext2_show_options,
>  #ifdef CONFIG_QUOTA
>  	.quota_read	= ext2_quota_read,
> @@ -402,230 +404,217 @@ static const struct export_operations ext2_export_ops = {
>  	.get_parent = ext2_get_parent,
>  };
>  
> -static unsigned long get_sb_block(void **data)
> -{
> -	unsigned long 	sb_block;
> -	char 		*options = (char *) *data;
> -
> -	if (!options || strncmp(options, "sb=", 3) != 0)
> -		return 1;	/* Default location */
> -	options += 3;
> -	sb_block = simple_strtoul(options, &options, 0);
> -	if (*options && *options != ',') {
> -		printk("EXT2-fs: Invalid sb specification: %s\n",
> -		       (char *) *data);
> -		return 1;
> -	}
> -	if (*options == ',')
> -		options++;
> -	*data = (void *) options;
> -	return sb_block;
> -}
> -
>  enum {
> -	Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid,
> -	Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic,
> -	Opt_err_ro, Opt_nouid32, Opt_debug,
> -	Opt_oldalloc, Opt_orlov, Opt_nobh, Opt_user_xattr, Opt_nouser_xattr,
> -	Opt_acl, Opt_noacl, Opt_xip, Opt_dax, Opt_ignore, Opt_err, Opt_quota,
> -	Opt_usrquota, Opt_grpquota, Opt_reservation, Opt_noreservation
> +	Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid, Opt_resgid, Opt_resuid,
> +	Opt_sb, Opt_errors, Opt_nouid32, Opt_debug, Opt_oldalloc, Opt_orlov,
> +	Opt_nobh, Opt_user_xattr, Opt_acl, Opt_xip, Opt_dax, Opt_ignore,
> +	Opt_quota, Opt_usrquota, Opt_grpquota, Opt_reservation,
> +};
> +
> +static const struct constant_table ext2_param_errors[] = {
> +	{"continue",	EXT2_MOUNT_ERRORS_CONT},
> +	{"panic",	EXT2_MOUNT_ERRORS_PANIC},
> +	{"remount-ro",	EXT2_MOUNT_ERRORS_RO},
> +	{}
> +};
> +
> +const struct fs_parameter_spec ext2_param_spec[] = {
> +	fsparam_flag	("bsddf", Opt_bsd_df),
> +	fsparam_flag	("minixdf", Opt_minix_df),
> +	fsparam_flag	("grpid", Opt_grpid),
> +	fsparam_flag	("bsdgroups", Opt_grpid),
> +	fsparam_flag	("nogrpid", Opt_nogrpid),
> +	fsparam_flag	("sysvgroups", Opt_nogrpid),
> +	fsparam_gid	("resgid", Opt_resgid),
> +	fsparam_uid	("resuid", Opt_resuid),
> +	fsparam_u32	("sb", Opt_sb),
> +	fsparam_enum	("errors", Opt_errors, ext2_param_errors),
> +	fsparam_flag	("nouid32", Opt_nouid32),
> +	fsparam_flag	("debug", Opt_debug),
> +	fsparam_flag	("oldalloc", Opt_oldalloc),
> +	fsparam_flag	("orlov", Opt_orlov),
> +	fsparam_flag	("nobh", Opt_nobh),
> +	fsparam_flag_no	("user_xattr", Opt_user_xattr),
> +	fsparam_flag_no	("acl", Opt_acl),
> +	fsparam_flag	("xip", Opt_xip),
> +	fsparam_flag	("dax", Opt_dax),
> +	fsparam_flag	("grpquota", Opt_grpquota),
> +	fsparam_flag	("noquota", Opt_ignore),
> +	fsparam_flag	("quota", Opt_quota),
> +	fsparam_flag	("usrquota", Opt_usrquota),
> +	fsparam_flag_no	("reservation", Opt_reservation),
> +	{}
>  };
>  
> -static const match_table_t tokens = {
> -	{Opt_bsd_df, "bsddf"},
> -	{Opt_minix_df, "minixdf"},
> -	{Opt_grpid, "grpid"},
> -	{Opt_grpid, "bsdgroups"},
> -	{Opt_nogrpid, "nogrpid"},
> -	{Opt_nogrpid, "sysvgroups"},
> -	{Opt_resgid, "resgid=%u"},
> -	{Opt_resuid, "resuid=%u"},
> -	{Opt_sb, "sb=%u"},
> -	{Opt_err_cont, "errors=continue"},
> -	{Opt_err_panic, "errors=panic"},
> -	{Opt_err_ro, "errors=remount-ro"},
> -	{Opt_nouid32, "nouid32"},
> -	{Opt_debug, "debug"},
> -	{Opt_oldalloc, "oldalloc"},
> -	{Opt_orlov, "orlov"},
> -	{Opt_nobh, "nobh"},
> -	{Opt_user_xattr, "user_xattr"},
> -	{Opt_nouser_xattr, "nouser_xattr"},
> -	{Opt_acl, "acl"},
> -	{Opt_noacl, "noacl"},
> -	{Opt_xip, "xip"},
> -	{Opt_dax, "dax"},
> -	{Opt_grpquota, "grpquota"},
> -	{Opt_ignore, "noquota"},
> -	{Opt_quota, "quota"},
> -	{Opt_usrquota, "usrquota"},
> -	{Opt_reservation, "reservation"},
> -	{Opt_noreservation, "noreservation"},
> -	{Opt_err, NULL}
> +#define EXT2_SPEC_s_resuid                      (1 << 0)
> +#define EXT2_SPEC_s_resgid                      (1 << 1)
> +
> +struct ext2_fs_context {
> +	unsigned long	vals_s_flags;	/* Bits to set in s_flags */
> +	unsigned long	mask_s_flags;	/* Bits changed in s_flags */
> +	unsigned int	vals_s_mount_opt;
> +	unsigned int	mask_s_mount_opt;
> +	kuid_t		s_resuid;
> +	kgid_t		s_resgid;
> +	unsigned long	s_sb_block;
> +	unsigned int	spec;
> +
>  };
>  
> -static int parse_options(char *options, struct super_block *sb,
> -			 struct ext2_mount_options *opts)
> +static inline void ctx_set_mount_opt(struct ext2_fs_context *ctx,
> +				  unsigned long flag)
> +{
> +	ctx->mask_s_mount_opt |= flag;
> +	ctx->vals_s_mount_opt |= flag;
> +}
> +
> +static inline void ctx_clear_mount_opt(struct ext2_fs_context *ctx,
> +				    unsigned long flag)
> +{
> +	ctx->mask_s_mount_opt |= flag;
> +	ctx->vals_s_mount_opt &= ~flag;
> +}
> +
> +static inline unsigned long
> +ctx_test_mount_opt(struct ext2_fs_context *ctx, unsigned long flag)
> +{
> +	return (ctx->vals_s_mount_opt & flag);
> +}
> +
> +static inline bool
> +ctx_parsed_mount_opt(struct ext2_fs_context *ctx, unsigned long flag)
> +{
> +	return (ctx->mask_s_mount_opt & flag);
> +}
> +
> +static void ext2_free_fc(struct fs_context *fc)
>  {
> -	char *p;
> -	substring_t args[MAX_OPT_ARGS];
> -	int option;
> -	kuid_t uid;
> -	kgid_t gid;
> -
> -	if (!options)
> -		return 1;
> -
> -	while ((p = strsep (&options, ",")) != NULL) {
> -		int token;
> -		if (!*p)
> -			continue;
> -
> -		token = match_token(p, tokens, args);
> -		switch (token) {
> -		case Opt_bsd_df:
> -			clear_opt (opts->s_mount_opt, MINIX_DF);
> -			break;
> -		case Opt_minix_df:
> -			set_opt (opts->s_mount_opt, MINIX_DF);
> -			break;
> -		case Opt_grpid:
> -			set_opt (opts->s_mount_opt, GRPID);
> -			break;
> -		case Opt_nogrpid:
> -			clear_opt (opts->s_mount_opt, GRPID);
> -			break;
> -		case Opt_resuid:
> -			if (match_int(&args[0], &option))
> -				return 0;
> -			uid = make_kuid(current_user_ns(), option);
> -			if (!uid_valid(uid)) {
> -				ext2_msg(sb, KERN_ERR, "Invalid uid value %d", option);
> -				return 0;
> -
> -			}
> -			opts->s_resuid = uid;
> -			break;
> -		case Opt_resgid:
> -			if (match_int(&args[0], &option))
> -				return 0;
> -			gid = make_kgid(current_user_ns(), option);
> -			if (!gid_valid(gid)) {
> -				ext2_msg(sb, KERN_ERR, "Invalid gid value %d", option);
> -				return 0;
> -			}
> -			opts->s_resgid = gid;
> -			break;
> -		case Opt_sb:
> -			/* handled by get_sb_block() instead of here */
> -			/* *sb_block = match_int(&args[0]); */
> -			break;
> -		case Opt_err_panic:
> -			clear_opt (opts->s_mount_opt, ERRORS_CONT);
> -			clear_opt (opts->s_mount_opt, ERRORS_RO);
> -			set_opt (opts->s_mount_opt, ERRORS_PANIC);
> -			break;
> -		case Opt_err_ro:
> -			clear_opt (opts->s_mount_opt, ERRORS_CONT);
> -			clear_opt (opts->s_mount_opt, ERRORS_PANIC);
> -			set_opt (opts->s_mount_opt, ERRORS_RO);
> -			break;
> -		case Opt_err_cont:
> -			clear_opt (opts->s_mount_opt, ERRORS_RO);
> -			clear_opt (opts->s_mount_opt, ERRORS_PANIC);
> -			set_opt (opts->s_mount_opt, ERRORS_CONT);
> -			break;
> -		case Opt_nouid32:
> -			set_opt (opts->s_mount_opt, NO_UID32);
> -			break;
> -		case Opt_debug:
> -			set_opt (opts->s_mount_opt, DEBUG);
> -			break;
> -		case Opt_oldalloc:
> -			set_opt (opts->s_mount_opt, OLDALLOC);
> -			break;
> -		case Opt_orlov:
> -			clear_opt (opts->s_mount_opt, OLDALLOC);
> -			break;
> -		case Opt_nobh:
> -			ext2_msg(sb, KERN_INFO,
> -				"nobh option not supported");
> -			break;
> +	kfree(fc->fs_private);
> +}
> +
> +static int ext2_parse_param(struct fs_context *fc, struct fs_parameter *param)
> +{
> +	struct ext2_fs_context *ctx = fc->fs_private;
> +	int opt;
> +	struct fs_parse_result result;
> +
> +	opt = fs_parse(fc, ext2_param_spec, param, &result);
> +	if (opt < 0)
> +		return opt;
> +
> +	switch (opt) {
> +	case Opt_bsd_df:
> +		ctx_clear_mount_opt(ctx, EXT2_MOUNT_MINIX_DF);
> +		break;
> +	case Opt_minix_df:
> +		ctx_set_mount_opt(ctx, EXT2_MOUNT_MINIX_DF);
> +		break;
> +	case Opt_grpid:
> +		ctx_set_mount_opt(ctx, EXT2_MOUNT_GRPID);
> +		break;
> +	case Opt_nogrpid:
> +		ctx_clear_mount_opt(ctx, EXT2_MOUNT_GRPID);
> +		break;
> +	case Opt_resuid:
> +		ctx->s_resuid = result.uid;
> +		ctx->spec |= EXT2_SPEC_s_resuid;
> +		break;
> +	case Opt_resgid:
> +		ctx->s_resgid = result.gid;
> +		ctx->spec |= EXT2_SPEC_s_resgid;
> +		break;
> +	case Opt_sb:
> +		/* Note that this is silently ignored on remount */
> +		ctx->s_sb_block = result.uint_32;
> +		break;
> +	case Opt_errors:
> +		ctx_clear_mount_opt(ctx, EXT2_MOUNT_ERRORS_MASK);
> +		ctx_set_mount_opt(ctx, result.uint_32);
> +		break;
> +	case Opt_nouid32:
> +		ctx_set_mount_opt(ctx, EXT2_MOUNT_NO_UID32);
> +		break;
> +	case Opt_debug:
> +		ctx_set_mount_opt(ctx, EXT2_MOUNT_DEBUG);
> +		break;
> +	case Opt_oldalloc:
> +		ctx_set_mount_opt(ctx, EXT2_MOUNT_OLDALLOC);
> +		break;
> +	case Opt_orlov:
> +		ctx_clear_mount_opt(ctx, EXT2_MOUNT_OLDALLOC);
> +		break;
> +	case Opt_nobh:
> +		ext2_msg(NULL, KERN_INFO, "nobh option not supported\n");
> +		break;
>  #ifdef CONFIG_EXT2_FS_XATTR
> -		case Opt_user_xattr:
> -			set_opt (opts->s_mount_opt, XATTR_USER);
> -			break;
> -		case Opt_nouser_xattr:
> -			clear_opt (opts->s_mount_opt, XATTR_USER);
> -			break;
> +	case Opt_user_xattr:
> +		if (!result.negated)
> +			ctx_set_mount_opt(ctx, EXT2_MOUNT_XATTR_USER);
> +		else
> +			ctx_clear_mount_opt(ctx, EXT2_MOUNT_XATTR_USER);
> +		break;
>  #else
> -		case Opt_user_xattr:
> -		case Opt_nouser_xattr:
> -			ext2_msg(sb, KERN_INFO, "(no)user_xattr options"
> -				"not supported");
> -			break;
> +	case Opt_user_xattr:
> +		ext2_msg(NULL, KERN_INFO, "(no)user_xattr options not supported");
> +		break;
>  #endif
>  #ifdef CONFIG_EXT2_FS_POSIX_ACL
> -		case Opt_acl:
> -			set_opt(opts->s_mount_opt, POSIX_ACL);
> -			break;
> -		case Opt_noacl:
> -			clear_opt(opts->s_mount_opt, POSIX_ACL);
> -			break;
> +	case Opt_acl:
> +		if (!result.negated)
> +			ctx_set_mount_opt(ctx, EXT2_MOUNT_POSIX_ACL);
> +		else
> +			ctx_clear_mount_opt(ctx, EXT2_MOUNT_POSIX_ACL);
> +		break;
>  #else
> -		case Opt_acl:
> -		case Opt_noacl:
> -			ext2_msg(sb, KERN_INFO,
> -				"(no)acl options not supported");
> -			break;
> +	case Opt_acl:
> +		ext2_msg(NULL, KERN_INFO, "(no)acl options not supported");
> +		break;
>  #endif
> -		case Opt_xip:
> -			ext2_msg(sb, KERN_INFO, "use dax instead of xip");
> -			set_opt(opts->s_mount_opt, XIP);
> -			fallthrough;
> -		case Opt_dax:
> +	case Opt_xip:
> +		ext2_msg(NULL, KERN_INFO, "use dax instead of xip");
> +		ctx_set_mount_opt(ctx, EXT2_MOUNT_XIP);
> +		fallthrough;
> +	case Opt_dax:
>  #ifdef CONFIG_FS_DAX
> -			ext2_msg(sb, KERN_WARNING,
> -		"DAX enabled. Warning: EXPERIMENTAL, use at your own risk");
> -			set_opt(opts->s_mount_opt, DAX);
> +		ext2_msg(NULL, KERN_WARNING,
> +		    "DAX enabled. Warning: EXPERIMENTAL, use at your own risk");
> +		ctx_set_mount_opt(ctx, EXT2_MOUNT_DAX);
>  #else
> -			ext2_msg(sb, KERN_INFO, "dax option not supported");
> +		ext2_msg(NULL, KERN_INFO, "dax option not supported");
>  #endif
> -			break;
> +		break;
>  
>  #if defined(CONFIG_QUOTA)
> -		case Opt_quota:
> -		case Opt_usrquota:
> -			set_opt(opts->s_mount_opt, USRQUOTA);
> -			break;
> -
> -		case Opt_grpquota:
> -			set_opt(opts->s_mount_opt, GRPQUOTA);
> -			break;
> +	case Opt_quota:
> +	case Opt_usrquota:
> +		ctx_set_mount_opt(ctx, EXT2_MOUNT_USRQUOTA);
> +		break;
> +
> +	case Opt_grpquota:
> +		ctx_set_mount_opt(ctx, EXT2_MOUNT_GRPQUOTA);
> +		break;
>  #else
> -		case Opt_quota:
> -		case Opt_usrquota:
> -		case Opt_grpquota:
> -			ext2_msg(sb, KERN_INFO,
> -				"quota operations not supported");
> -			break;
> +	case Opt_quota:
> +	case Opt_usrquota:
> +	case Opt_grpquota:
> +		ext2_msg(NULL, KERN_INFO, "quota operations not supported");
> +		break;
>  #endif
> -
> -		case Opt_reservation:
> -			set_opt(opts->s_mount_opt, RESERVATION);
> -			ext2_msg(sb, KERN_INFO, "reservations ON");
> -			break;
> -		case Opt_noreservation:
> -			clear_opt(opts->s_mount_opt, RESERVATION);
> -			ext2_msg(sb, KERN_INFO, "reservations OFF");
> -			break;
> -		case Opt_ignore:
> -			break;
> -		default:
> -			return 0;
> +	case Opt_reservation:
> +		if (!result.negated) {
> +			ctx_set_mount_opt(ctx, EXT2_MOUNT_RESERVATION);
> +			ext2_msg(NULL, KERN_INFO, "reservations ON");
> +		} else {
> +			ctx_clear_mount_opt(ctx, EXT2_MOUNT_RESERVATION);
> +			ext2_msg(NULL, KERN_INFO, "reservations OFF");
>  		}
> +		break;
> +	case Opt_ignore:
> +		break;
> +	default:
> +		return -EINVAL;
>  	}
> -	return 1;
> +	return 0;
>  }
>  
>  static int ext2_setup_super (struct super_block * sb,
> @@ -801,24 +790,83 @@ static unsigned long descriptor_loc(struct super_block *sb,
>  	return ext2_group_first_block_no(sb, bg) + ext2_bg_has_super(sb, bg);
>  }
>  
> -static int ext2_fill_super(struct super_block *sb, void *data, int silent)
> +/*
> + * Set all mount options either from defaults on disk, or from parsed
> + * options. Parsed/specified options override on-disk defaults.
> + */
> +static void ext2_set_options(struct fs_context *fc, struct ext2_sb_info *sbi)
>  {
> +	struct ext2_fs_context *ctx = fc->fs_private;
> +	struct ext2_super_block *es = sbi->s_es;
> +	unsigned long def_mount_opts = le32_to_cpu(es->s_default_mount_opts);
> +
> +	/* Copy parsed mount options to sbi */
> +	sbi->s_mount_opt = ctx->vals_s_mount_opt;
> +
> +	/* Use in-superblock defaults only if not specified during parsing */
> +	if (!ctx_parsed_mount_opt(ctx, EXT2_MOUNT_DEBUG) &&
> +	    def_mount_opts & EXT2_DEFM_DEBUG)
> +		set_opt(sbi->s_mount_opt, DEBUG);
> +
> +	if (!ctx_parsed_mount_opt(ctx, EXT2_MOUNT_GRPID) &&
> +	    def_mount_opts & EXT2_DEFM_BSDGROUPS)
> +		set_opt(sbi->s_mount_opt, GRPID);
> +
> +	if (!ctx_parsed_mount_opt(ctx, EXT2_MOUNT_NO_UID32) &&
> +	    def_mount_opts & EXT2_DEFM_UID16)
> +		set_opt(sbi->s_mount_opt, NO_UID32);
> +
> +#ifdef CONFIG_EXT2_FS_XATTR
> +	if (!ctx_parsed_mount_opt(ctx, EXT2_MOUNT_XATTR_USER) &&
> +	    def_mount_opts & EXT2_DEFM_XATTR_USER)
> +		set_opt(sbi->s_mount_opt, XATTR_USER);
> +#endif
> +#ifdef CONFIG_EXT2_FS_POSIX_ACL
> +	if (!ctx_parsed_mount_opt(ctx, EXT2_MOUNT_POSIX_ACL) &&
> +	    def_mount_opts & EXT2_DEFM_ACL)
> +		set_opt(sbi->s_mount_opt, POSIX_ACL);
> +#endif
> +
> +	if (!ctx_parsed_mount_opt(ctx, EXT2_MOUNT_ERRORS_MASK)) {
> +		if (le16_to_cpu(sbi->s_es->s_errors) == EXT2_ERRORS_PANIC)
> +			set_opt(sbi->s_mount_opt, ERRORS_PANIC);
> +		else if (le16_to_cpu(sbi->s_es->s_errors) == EXT2_ERRORS_CONTINUE)
> +			set_opt(sbi->s_mount_opt, ERRORS_CONT);
> +		else
> +			set_opt(sbi->s_mount_opt, ERRORS_RO);
> +	}
> +
> +	if (ctx->spec & EXT2_SPEC_s_resuid)
> +		sbi->s_resuid = ctx->s_resuid;
> +	else
> +		sbi->s_resuid = make_kuid(&init_user_ns,
> +					   le16_to_cpu(es->s_def_resuid));
> +
> +	if (ctx->spec & EXT2_SPEC_s_resgid)
> +		sbi->s_resgid = ctx->s_resgid;
> +	else
> +		sbi->s_resgid = make_kgid(&init_user_ns,
> +					   le16_to_cpu(es->s_def_resgid));
> +}
> +
> +static int ext2_fill_super(struct super_block *sb, struct fs_context *fc)
> +{
> +	struct ext2_fs_context *ctx = fc->fs_private;
> +	int silent = fc->sb_flags & SB_SILENT;
>  	struct buffer_head * bh;
>  	struct ext2_sb_info * sbi;
>  	struct ext2_super_block * es;
>  	struct inode *root;
>  	unsigned long block;
> -	unsigned long sb_block = get_sb_block(&data);
> +	unsigned long sb_block = ctx->s_sb_block;
>  	unsigned long logic_sb_block;
>  	unsigned long offset = 0;
> -	unsigned long def_mount_opts;
>  	long ret = -ENOMEM;
>  	int blocksize = BLOCK_SIZE;
>  	int db_count;
>  	int i, j;
>  	__le32 features;
>  	int err;
> -	struct ext2_mount_options opts;
>  
>  	sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
>  	if (!sbi)
> @@ -877,42 +925,7 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
>  	if (sb->s_magic != EXT2_SUPER_MAGIC)
>  		goto cantfind_ext2;
>  
> -	opts.s_mount_opt = 0;
> -	/* Set defaults before we parse the mount options */
> -	def_mount_opts = le32_to_cpu(es->s_default_mount_opts);
> -	if (def_mount_opts & EXT2_DEFM_DEBUG)
> -		set_opt(opts.s_mount_opt, DEBUG);
> -	if (def_mount_opts & EXT2_DEFM_BSDGROUPS)
> -		set_opt(opts.s_mount_opt, GRPID);
> -	if (def_mount_opts & EXT2_DEFM_UID16)
> -		set_opt(opts.s_mount_opt, NO_UID32);
> -#ifdef CONFIG_EXT2_FS_XATTR
> -	if (def_mount_opts & EXT2_DEFM_XATTR_USER)
> -		set_opt(opts.s_mount_opt, XATTR_USER);
> -#endif
> -#ifdef CONFIG_EXT2_FS_POSIX_ACL
> -	if (def_mount_opts & EXT2_DEFM_ACL)
> -		set_opt(opts.s_mount_opt, POSIX_ACL);
> -#endif
> -	
> -	if (le16_to_cpu(sbi->s_es->s_errors) == EXT2_ERRORS_PANIC)
> -		set_opt(opts.s_mount_opt, ERRORS_PANIC);
> -	else if (le16_to_cpu(sbi->s_es->s_errors) == EXT2_ERRORS_CONTINUE)
> -		set_opt(opts.s_mount_opt, ERRORS_CONT);
> -	else
> -		set_opt(opts.s_mount_opt, ERRORS_RO);
> -
> -	opts.s_resuid = make_kuid(&init_user_ns, le16_to_cpu(es->s_def_resuid));
> -	opts.s_resgid = make_kgid(&init_user_ns, le16_to_cpu(es->s_def_resgid));
> -	
> -	set_opt(opts.s_mount_opt, RESERVATION);
> -
> -	if (!parse_options((char *) data, sb, &opts))
> -		goto failed_mount;
> -
> -	sbi->s_mount_opt = opts.s_mount_opt;
> -	sbi->s_resuid = opts.s_resuid;
> -	sbi->s_resgid = opts.s_resgid;
> +	ext2_set_options(fc, sbi);
>  
>  	sb->s_flags = (sb->s_flags & ~SB_POSIXACL) |
>  		(test_opt(sb, POSIX_ACL) ? SB_POSIXACL : 0);
> @@ -1324,23 +1337,21 @@ static void ext2_write_super(struct super_block *sb)
>  		ext2_sync_fs(sb, 1);
>  }
>  
> -static int ext2_remount (struct super_block * sb, int * flags, char * data)
> +static int ext2_reconfigure(struct fs_context *fc)
>  {
> +	struct ext2_fs_context *ctx = fc->fs_private;
> +	struct super_block *sb = fc->root->d_sb;
>  	struct ext2_sb_info * sbi = EXT2_SB(sb);
>  	struct ext2_super_block * es;
>  	struct ext2_mount_options new_opts;
> +	int flags = fc->sb_flags;
>  	int err;
>  
>  	sync_filesystem(sb);
>  
> -	spin_lock(&sbi->s_lock);
> -	new_opts.s_mount_opt = sbi->s_mount_opt;
> -	new_opts.s_resuid = sbi->s_resuid;
> -	new_opts.s_resgid = sbi->s_resgid;
> -	spin_unlock(&sbi->s_lock);
> -
> -	if (!parse_options(data, sb, &new_opts))
> -		return -EINVAL;
> +	new_opts.s_mount_opt = ctx->vals_s_mount_opt;
> +	new_opts.s_resuid = ctx->s_resuid;
> +	new_opts.s_resgid = ctx->s_resgid;
>  
>  	spin_lock(&sbi->s_lock);
>  	es = sbi->s_es;
> @@ -1349,9 +1360,9 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data)
>  			 "dax flag with busy inodes while remounting");
>  		new_opts.s_mount_opt ^= EXT2_MOUNT_DAX;
>  	}
> -	if ((bool)(*flags & SB_RDONLY) == sb_rdonly(sb))
> +	if ((bool)(flags & SB_RDONLY) == sb_rdonly(sb))
>  		goto out_set;
> -	if (*flags & SB_RDONLY) {
> +	if (flags & SB_RDONLY) {
>  		if (le16_to_cpu(es->s_state) & EXT2_VALID_FS ||
>  		    !(sbi->s_mount_state & EXT2_VALID_FS))
>  			goto out_set;
> @@ -1470,10 +1481,9 @@ static int ext2_statfs (struct dentry * dentry, struct kstatfs * buf)
>  	return 0;
>  }
>  
> -static struct dentry *ext2_mount(struct file_system_type *fs_type,
> -	int flags, const char *dev_name, void *data)
> +static int ext2_get_tree(struct fs_context *fc)
>  {
> -	return mount_bdev(fs_type, flags, dev_name, data, ext2_fill_super);
> +	return get_tree_bdev(fc, ext2_fill_super);
>  }
>  
>  #ifdef CONFIG_QUOTA
> @@ -1624,12 +1634,49 @@ static int ext2_quota_off(struct super_block *sb, int type)
>  
>  #endif
>  
> +static const struct fs_context_operations ext2_context_ops = {
> +	.parse_param	= ext2_parse_param,
> +	.get_tree	= ext2_get_tree,
> +	.reconfigure	= ext2_reconfigure,
> +	.free		= ext2_free_fc,
> +};
> +
> +static int ext2_init_fs_context(struct fs_context *fc)
> +{
> +	struct ext2_fs_context *ctx;
> +
> +	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
> +	if (!ctx)
> +		return -ENOMEM;
> +
> +	if (fc->purpose == FS_CONTEXT_FOR_RECONFIGURE) {
> +		struct super_block *sb = fc->root->d_sb;
> +		struct ext2_sb_info *sbi = EXT2_SB(sb);
> +
> +		spin_lock(&sbi->s_lock);
> +		ctx->vals_s_mount_opt = sbi->s_mount_opt;
> +		ctx->vals_s_flags = sb->s_flags;
> +		ctx->s_resuid = sbi->s_resuid;
> +		ctx->s_resgid = sbi->s_resgid;
> +		spin_unlock(&sbi->s_lock);
> +	} else {
> +		ctx->s_sb_block = 1;
> +		ctx_set_mount_opt(ctx, EXT2_MOUNT_RESERVATION);
> +	}
> +
> +	fc->fs_private = ctx;
> +	fc->ops = &ext2_context_ops;
> +
> +	return 0;
> +}
> +
>  static struct file_system_type ext2_fs_type = {
>  	.owner		= THIS_MODULE,
>  	.name		= "ext2",
> -	.mount		= ext2_mount,
>  	.kill_sb	= kill_block_super,
>  	.fs_flags	= FS_REQUIRES_DEV,
> +	.init_fs_context = ext2_init_fs_context,
> +	.parameters	= ext2_param_spec,
>  };
>  MODULE_ALIAS_FS("ext2");
>  
> -- 
> 2.48.0
> 
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/2] ext2: convert to the new mount API
  2025-02-24 16:02   ` Jan Kara
@ 2025-02-26 16:42     ` Eric Sandeen
  2025-02-26 17:03       ` Jan Kara
  0 siblings, 1 reply; 7+ messages in thread
From: Eric Sandeen @ 2025-02-26 16:42 UTC (permalink / raw)
  To: Jan Kara, Eric Sandeen; +Cc: jack, linux-ext4

On 2/24/25 8:02 AM, Jan Kara wrote:
> On Sun 23-02-25 13:57:40, Eric Sandeen wrote:
>> Convert ext2 to the new mount API.
>>
>> Note that this makes the sb= option more accepting than it was before;
>> previosly, sb= was only accepted if it was the first specified option.
>> Now it can exist anywhere, and if respecified, the last specified value
>> is used.
>>
>> Parse-time messages here are sent to ext2_msg with a NULL sb, and
>> ext2_msg is adjusted to accept that, as ext4 does today as well.
>>
>> Signed-off-by: Eric Sandeen <sandeen@redhat.com>
> 
> Looks good to me. Thanks!

Thanks Jan - You probably saw the minor nit from the kernel test robot,
"const struct fs_parameter_spec ext2_param_spec" should be static, too.

Sorry about that! 

-Eric

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/2] ext2: convert to the new mount API
  2025-02-26 16:42     ` Eric Sandeen
@ 2025-02-26 17:03       ` Jan Kara
  0 siblings, 0 replies; 7+ messages in thread
From: Jan Kara @ 2025-02-26 17:03 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: Jan Kara, Eric Sandeen, jack, linux-ext4

On Wed 26-02-25 10:42:11, Eric Sandeen wrote:
> On 2/24/25 8:02 AM, Jan Kara wrote:
> > On Sun 23-02-25 13:57:40, Eric Sandeen wrote:
> >> Convert ext2 to the new mount API.
> >>
> >> Note that this makes the sb= option more accepting than it was before;
> >> previosly, sb= was only accepted if it was the first specified option.
> >> Now it can exist anywhere, and if respecified, the last specified value
> >> is used.
> >>
> >> Parse-time messages here are sent to ext2_msg with a NULL sb, and
> >> ext2_msg is adjusted to accept that, as ext4 does today as well.
> >>
> >> Signed-off-by: Eric Sandeen <sandeen@redhat.com>
> > 
> > Looks good to me. Thanks!
> 
> Thanks Jan - You probably saw the minor nit from the kernel test robot,
> "const struct fs_parameter_spec ext2_param_spec" should be static, too.

Yep, fixed now.

> Sorry about that! 

No problem :).

								Honza
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2025-02-26 17:03 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-02-23 19:57 [PATCH 0/2] ext2: convert to the new mount API Eric Sandeen
2025-02-23 19:57 ` [PATCH 1/2] " Eric Sandeen
2025-02-24 16:02   ` Jan Kara
2025-02-26 16:42     ` Eric Sandeen
2025-02-26 17:03       ` Jan Kara
2025-02-23 19:57 ` [PATCH 2/2] ext2: create ext2_msg_fc for use during parsing Eric Sandeen
2025-02-24 16:01   ` Jan Kara

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox