linux-ext4.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Lukas Czerner <lczerner@redhat.com>
To: linux-ext4@vger.kernel.org
Cc: Theodore Ts'o <tytso@mit.edu>,
	David Howells <dhowells@redhat.com>,
	Al Viro <viro@zeniv.linux.org.uk>
Subject: [PATCH 04/17] ext4: Change handle_mount_opt() to use fs_parameter
Date: Wed,  6 Nov 2019 11:14:44 +0100	[thread overview]
Message-ID: <20191106101457.11237-5-lczerner@redhat.com> (raw)
In-Reply-To: <20191106101457.11237-1-lczerner@redhat.com>

Signed-off-by: Lukas Czerner <lczerner@redhat.com>
---
 fs/ext4/super.c | 217 +++++++++++++++++++++++++++++-------------------
 1 file changed, 131 insertions(+), 86 deletions(-)

diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index b155257e2a4e..63a06dcb2807 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -1692,7 +1692,8 @@ static const char deprecated_msg[] =
 	"Contact linux-ext4@vger.kernel.org if you think we should keep it.\n";
 
 #ifdef CONFIG_QUOTA
-static int set_qf_name(struct super_block *sb, int qtype, substring_t *args)
+static int set_qf_name(struct super_block *sb, int qtype,
+		       struct fs_parameter *param)
 {
 	struct ext4_sb_info *sbi = EXT4_SB(sb);
 	char *qname, *old_qname = get_qf_name(sb, sbi, qtype);
@@ -1709,7 +1710,7 @@ static int set_qf_name(struct super_block *sb, int qtype, substring_t *args)
 			 "ignored when QUOTA feature is enabled");
 		return 1;
 	}
-	qname = match_strdup(args);
+	qname = kmemdup_nul(param->string, param->size, GFP_KERNEL);
 	if (!qname) {
 		ext4_msg(sb, KERN_ERR,
 			"Not enough memory for storing quotafile name");
@@ -1898,35 +1899,49 @@ static int ext4_sb_read_encoding(const struct ext4_super_block *es,
 }
 #endif
 
-static int handle_mount_opt(struct super_block *sb, char *opt, int token,
-			    substring_t *args, unsigned long *journal_devnum,
-			    unsigned int *journal_ioprio, int is_remount)
+struct ext4_fs_context {
+	unsigned long journal_devnum;
+	unsigned int journal_ioprio;
+};
+
+static int handle_mount_opt(struct fs_context *fc, struct fs_parameter *param)
 {
-	struct ext4_sb_info *sbi = EXT4_SB(sb);
+	struct ext4_fs_context *ctx = fc->fs_private;
+	struct ext4_sb_info *sbi = fc->s_fs_info;
+	struct super_block *sb = sbi->s_sb;
 	const struct mount_opts *m;
+	struct fs_parse_result result;
 	kuid_t uid;
 	kgid_t gid;
-	int arg = 0;
+	int token;
+
+	token = fs_parse(fc, &ext4_fs_parameters, param, &result);
+	if (token < 0)
+		return token;
 
 #ifdef CONFIG_QUOTA
-	if (token == Opt_usrjquota)
-		return set_qf_name(sb, USRQUOTA, &args[0]);
-	else if (token == Opt_grpjquota)
-		return set_qf_name(sb, GRPQUOTA, &args[0]);
-	else if (token == Opt_offusrjquota)
-		return clear_qf_name(sb, USRQUOTA);
-	else if (token == Opt_offgrpjquota)
-		return clear_qf_name(sb, GRPQUOTA);
+	if (token == Opt_usrjquota) {
+		if (result.negated)
+			return clear_qf_name(sb, USRQUOTA);
+		else
+			return set_qf_name(sb, USRQUOTA, param);
+	} else if (token == Opt_grpjquota) {
+		if (result.negated)
+			return clear_qf_name(sb, GRPQUOTA);
+		else
+			return set_qf_name(sb, GRPQUOTA, param);
+	}
 #endif
 	switch (token) {
 	case Opt_noacl:
 	case Opt_nouser_xattr:
-		ext4_msg(sb, KERN_WARNING, deprecated_msg, opt, "3.5");
+		ext4_msg(sb, KERN_WARNING, deprecated_msg, param->key, "3.5");
 		break;
 	case Opt_sb:
 		return 1;	/* handled by get_sb_block() */
 	case Opt_removed:
-		ext4_msg(sb, KERN_WARNING, "Ignoring removed %s option", opt);
+		ext4_msg(sb, KERN_WARNING, "Ignoring removed %s option",
+			 param->key);
 		return 1;
 	case Opt_abort:
 		sbi->s_mount_flags |= EXT4_MF_FS_ABORTED;
@@ -1940,6 +1955,11 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
 	case Opt_nolazytime:
 		sb->s_flags &= ~SB_LAZYTIME;
 		return 1;
+	case Opt_errors:
+	case Opt_data:
+	case Opt_data_err:
+	case Opt_jqfmt:
+		token = result.uint_32;
 	}
 
 	for (m = ext4_mount_opts; m->token != Opt_err; m++)
@@ -1948,25 +1968,23 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
 
 	if (m->token == Opt_err) {
 		ext4_msg(sb, KERN_ERR, "Unrecognized mount option \"%s\" "
-			 "or missing value", opt);
+			 "or missing value", param->key);
 		return -1;
 	}
 
 	if ((m->flags & MOPT_NO_EXT2) && IS_EXT2_SB(sb)) {
 		ext4_msg(sb, KERN_ERR,
-			 "Mount option \"%s\" incompatible with ext2", opt);
+			 "Mount option \"%s\" incompatible with ext2",
+			 param->string);
 		return -1;
 	}
 	if ((m->flags & MOPT_NO_EXT3) && IS_EXT3_SB(sb)) {
 		ext4_msg(sb, KERN_ERR,
-			 "Mount option \"%s\" incompatible with ext3", opt);
+			 "Mount option \"%s\" incompatible with ext3",
+			 param->string);
 		return -1;
 	}
 
-	if (args->from && !(m->flags & MOPT_STRING) && match_int(args, &arg))
-		return -1;
-	if (args->from && (m->flags & MOPT_GTE0) && (arg < 0))
-		return -1;
 	if (m->flags & MOPT_EXPLICIT) {
 		if (m->mount_opt & EXT4_MOUNT_DELALLOC) {
 			set_opt2(sb, EXPLICIT_DELALLOC);
@@ -1984,108 +2002,96 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
 	}
 
 	if (m->flags & MOPT_NOSUPPORT) {
-		ext4_msg(sb, KERN_ERR, "%s option not supported", opt);
+		ext4_msg(sb, KERN_ERR, "%s option not supported",
+			 param->key);
 	} else if (token == Opt_commit) {
-		if (arg == 0)
-			arg = JBD2_DEFAULT_MAX_COMMIT_AGE;
-		else if (arg > INT_MAX / HZ) {
+		if (result.uint_32 == 0)
+			sbi->s_commit_interval = JBD2_DEFAULT_MAX_COMMIT_AGE;
+		else if (result.uint_32 > INT_MAX / HZ) {
 			ext4_msg(sb, KERN_ERR,
 				 "Invalid commit interval %d, "
 				 "must be smaller than %d",
-				 arg, INT_MAX / HZ);
+				 result.uint_32, INT_MAX / HZ);
 			return -1;
 		}
-		sbi->s_commit_interval = HZ * arg;
+		sbi->s_commit_interval = HZ * result.uint_32;
 	} else if (token == Opt_debug_want_extra_isize) {
-		sbi->s_want_extra_isize = arg;
+		sbi->s_want_extra_isize = result.uint_32;
 	} else if (token == Opt_max_batch_time) {
-		sbi->s_max_batch_time = arg;
+		sbi->s_max_batch_time = result.uint_32;
 	} else if (token == Opt_min_batch_time) {
-		sbi->s_min_batch_time = arg;
+		sbi->s_min_batch_time = result.uint_32;
 	} else if (token == Opt_inode_readahead_blks) {
-		if (arg && (arg > (1 << 30) || !is_power_of_2(arg))) {
+		if (result.uint_32 &&
+		    (result.uint_32 > (1 << 30) ||
+		     !is_power_of_2(result.uint_32))) {
 			ext4_msg(sb, KERN_ERR,
 				 "EXT4-fs: inode_readahead_blks must be "
 				 "0 or a power of 2 smaller than 2^31");
 			return -1;
 		}
-		sbi->s_inode_readahead_blks = arg;
+		sbi->s_inode_readahead_blks = result.uint_32;
 	} else if (token == Opt_init_itable) {
 		set_opt(sb, INIT_INODE_TABLE);
-		if (!args->from)
-			arg = EXT4_DEF_LI_WAIT_MULT;
-		sbi->s_li_wait_mult = arg;
+		sbi->s_li_wait_mult = EXT4_DEF_LI_WAIT_MULT;
+		if (result.has_value)
+			sbi->s_li_wait_mult = result.uint_32;
 	} else if (token == Opt_max_dir_size_kb) {
-		sbi->s_max_dir_size_kb = arg;
+		sbi->s_max_dir_size_kb = result.uint_32;
 	} else if (token == Opt_stripe) {
-		sbi->s_stripe = arg;
+		sbi->s_stripe = result.uint_32;
 	} else if (token == Opt_resuid) {
-		uid = make_kuid(current_user_ns(), arg);
+		uid = make_kuid(current_user_ns(), result.uint_32);
 		if (!uid_valid(uid)) {
-			ext4_msg(sb, KERN_ERR, "Invalid uid value %d", arg);
+			ext4_msg(sb, KERN_ERR, "Invalid uid value %d",
+				 result.uint_32);
 			return -1;
 		}
 		sbi->s_resuid = uid;
 	} else if (token == Opt_resgid) {
-		gid = make_kgid(current_user_ns(), arg);
+		gid = make_kgid(current_user_ns(), result.uint_32);
 		if (!gid_valid(gid)) {
-			ext4_msg(sb, KERN_ERR, "Invalid gid value %d", arg);
+			ext4_msg(sb, KERN_ERR, "Invalid gid value %d",
+				 result.uint_32);
 			return -1;
 		}
 		sbi->s_resgid = gid;
 	} else if (token == Opt_journal_dev) {
-		if (is_remount) {
+		if (fc->purpose == FS_CONTEXT_FOR_RECONFIGURE) {
 			ext4_msg(sb, KERN_ERR,
 				 "Cannot specify journal on remount");
 			return -1;
 		}
-		*journal_devnum = arg;
+		ctx->journal_devnum = result.uint_32;
 	} else if (token == Opt_journal_path) {
-		char *journal_path;
 		struct inode *journal_inode;
 		struct path path;
 		int error;
 
-		if (is_remount) {
+		if (fc->purpose == FS_CONTEXT_FOR_RECONFIGURE) {
 			ext4_msg(sb, KERN_ERR,
 				 "Cannot specify journal on remount");
 			return -1;
 		}
-		journal_path = match_strdup(&args[0]);
-		if (!journal_path) {
-			ext4_msg(sb, KERN_ERR, "error: could not dup "
-				"journal device string");
-			return -1;
-		}
 
-		error = kern_path(journal_path, LOOKUP_FOLLOW, &path);
+		error = fs_lookup_param(fc, param, 1, &path);
 		if (error) {
 			ext4_msg(sb, KERN_ERR, "error: could not find "
-				"journal device path: error %d", error);
-			kfree(journal_path);
+				"journal device path");
 			return -1;
 		}
 
 		journal_inode = d_inode(path.dentry);
-		if (!S_ISBLK(journal_inode->i_mode)) {
-			ext4_msg(sb, KERN_ERR, "error: journal path %s "
-				"is not a block device", journal_path);
-			path_put(&path);
-			kfree(journal_path);
-			return -1;
-		}
-
-		*journal_devnum = new_encode_dev(journal_inode->i_rdev);
+		ctx->journal_devnum = new_encode_dev(journal_inode->i_rdev);
 		path_put(&path);
-		kfree(journal_path);
 	} else if (token == Opt_journal_ioprio) {
-		if (arg > 7) {
+		if (result.uint_32 > 7) {
 			ext4_msg(sb, KERN_ERR, "Invalid journal IO priority"
 				 " (must be 0-7)");
 			return -1;
 		}
-		*journal_ioprio =
-			IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, arg);
+		ctx->journal_ioprio =
+			IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, result.uint_32);
 	} else if (token == Opt_test_dummy_encryption) {
 #ifdef CONFIG_FS_ENCRYPTION
 		sbi->s_mount_flags |= EXT4_MF_TEST_DUMMY_ENCRYPTION;
@@ -2096,7 +2102,7 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
 			 "Test dummy encryption mount option ignored");
 #endif
 	} else if (m->flags & MOPT_DATAJ) {
-		if (is_remount) {
+		if (fc->purpose == FS_CONTEXT_FOR_RECONFIGURE) {
 			if (!sbi->s_journal)
 				ext4_msg(sb, KERN_WARNING, "Remounting file system with no journal so ignoring journalled data option");
 			else if (test_opt(sb, DATA_FLAGS) != m->mount_opt) {
@@ -2138,17 +2144,22 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
 	} else if (token == Opt_data_err_ignore) {
 		sbi->s_mount_opt &= ~m->mount_opt;
 	} else {
-		if (!args->from)
-			arg = 1;
+		bool set;
+
+		if (result.has_value)
+			set = result.boolean;
+		else
+			set = true;
 		if (m->flags & MOPT_CLEAR)
-			arg = !arg;
+			set = !set;
 		else if (unlikely(!(m->flags & MOPT_SET))) {
 			ext4_msg(sb, KERN_WARNING,
-				 "buggy handling of option %s", opt);
+				 "buggy handling of option %s",
+				 param->key);
 			WARN_ON(1);
 			return -1;
 		}
-		if (arg != 0)
+		if (set)
 			sbi->s_mount_opt |= m->mount_opt;
 		else
 			sbi->s_mount_opt &= ~m->mount_opt;
@@ -2161,26 +2172,60 @@ static int parse_options(char *options, struct super_block *sb,
 			 unsigned int *journal_ioprio,
 			 int is_remount)
 {
-	substring_t args[MAX_OPT_ARGS];
-	int token;
+	struct ext4_fs_context ctx;
+	struct fs_parameter param;
+	struct fs_context fc;
+	char *value;
+	int ret;
 	char *p;
 
 	if (!options)
 		return 1;
 
+	memset(&fc, 0, sizeof(fc));
+	memset(&ctx, 0, sizeof(ctx));
+	fc.fs_private = &ctx;
+	fc.s_fs_info = EXT4_SB(sb);
+
+	if (is_remount)
+		fc.purpose = FS_CONTEXT_FOR_RECONFIGURE;
+
 	while ((p = strsep(&options, ",")) != NULL) {
+
 		if (!*p)
 			continue;
-		/*
-		 * Initialize args struct so we know whether arg was
-		 * found; some options take optional arguments.
-		 */
-		args[0].to = args[0].from = NULL;
-		token = match_token(p, tokens, args);
-		if (handle_mount_opt(sb, p, token, args, journal_devnum,
-				     journal_ioprio, is_remount) < 0)
+
+		param.key = p;
+		param.type = fs_value_is_string;
+		param.size = 0;
+		param.string = NULL;
+
+		value = strchr(p, '=');
+		if (value) {
+			if (value == p)
+				continue;
+			*value++ = 0;
+			param.size = strlen(value);
+			if (param.size > 0) {
+				param.string = kmemdup_nul(value,
+							   param.size,
+							   GFP_KERNEL);
+				if (!param.string)
+					return -ENOMEM;
+			}
+		}
+
+		ret = handle_mount_opt(&fc, &param);
+		kfree(param.string);
+		if (ret < 0)
 			return 0;
 	}
+
+	if (journal_devnum)
+		*journal_devnum = ctx.journal_devnum;
+	if (journal_ioprio)
+		*journal_ioprio = ctx.journal_ioprio;
+
 	return ext4_validate_options(sb);
 }
 
-- 
2.21.0


  parent reply	other threads:[~2019-11-06 10:15 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-11-06 10:14 ext4: new mount API conversion Lukas Czerner
2019-11-06 10:14 ` [PATCH 01/17] vfs: Handle fs_param_neg_with_empty Lukas Czerner
2019-11-06 10:14 ` [PATCH 02/17] ext4: Add fs parameter description Lukas Czerner
2019-12-17  0:44   ` Al Viro
2019-12-17 12:19     ` Lukas Czerner
2019-12-17 15:20       ` Al Viro
2019-12-17 16:34         ` Lukas Czerner
2019-12-24 17:18           ` Al Viro
2019-11-06 10:14 ` [PATCH 03/17] ext4: move option validation to a separate function Lukas Czerner
2019-11-06 10:14 ` Lukas Czerner [this message]
2019-11-06 10:14 ` [PATCH 05/17] ext4: Allow sb to be NULL in ext4_msg() Lukas Czerner
2019-11-06 10:14 ` [PATCH 06/17] ext4: move quota configuration out of handle_mount_opt() Lukas Czerner
2019-11-06 10:14 ` [PATCH 07/17] ext4: check ext2/3 compatibility outside handle_mount_opt() Lukas Czerner
2019-11-06 10:14 ` [PATCH 08/17] ext4: get rid of super block and sbi from handle_mount_ops() Lukas Czerner
2019-11-06 10:14 ` [PATCH 09/17] ext4: parse Opt_sb in handle_mount_opt() Lukas Czerner
2019-11-06 10:14 ` [PATCH 10/17] ext4: clean up return values " Lukas Czerner
2019-11-06 10:14 ` [PATCH 11/17] ext4: add ext4_get_tree for the new mount API Lukas Czerner
2019-11-06 10:14 ` [PATCH 12/17] ext4: refactor ext4_remount() Lukas Czerner
2019-11-06 10:14 ` [PATCH 13/17] ext4: add ext4_reconfigure for the new mount API Lukas Czerner
2019-11-06 10:14 ` [PATCH 14/17] ext4: add ext4_fc_free " Lukas Czerner
2019-11-06 10:14 ` [PATCH 15/17] ext4: switch to " Lukas Czerner
2019-11-06 10:14 ` [PATCH 16/17] ext4: change token2str() to use ext4_param_specs Lukas Czerner
2019-11-06 10:14 ` [PATCH 17/17] ext4: Remove unused code from old mount api Lukas Czerner

Reply instructions:

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

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

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

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

  git send-email \
    --in-reply-to=20191106101457.11237-5-lczerner@redhat.com \
    --to=lczerner@redhat.com \
    --cc=dhowells@redhat.com \
    --cc=linux-ext4@vger.kernel.org \
    --cc=tytso@mit.edu \
    --cc=viro@zeniv.linux.org.uk \
    /path/to/YOUR_REPLY

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

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