All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/6 v2] mkfs: save user input into opts table
@ 2017-08-11 12:30 Jan Tulak
  2017-08-11 12:30 ` [PATCH 1/6] mkfs: Save raw user input field to the opts struct Jan Tulak
                   ` (6 more replies)
  0 siblings, 7 replies; 37+ messages in thread
From: Jan Tulak @ 2017-08-11 12:30 UTC (permalink / raw)
  To: linux-xfs; +Cc: Jan Tulak

Hi guys

Second version of this set. All issues raised so far should be addressed. The
last patch from this set was moved to the other set per Eric's suggestion and
see changelog in every patch for specific changes. Plus rebasing changes in
every patch.

Text from v1 follows:

This is a respin of https://www.spinics.net/lists/linux-xfs/msg06158.html, but
I decided to split that set in two smaller ones. This first one implements the
infrastructure, but does not replace standalone variables with the opts table
fields, that happens in the other set.

To reiterate: The main goal of this set is to save user input into the opts
struct, instead of various ad-hoc variables.  I'm adding the set and get
functions to do this and applying them where appropriate. Once all the values
are in a single place, we can expand the automated validation and use it e.g.
for loading up optional config file like Luis wants to do.

This set is now is based on for-next and not on my type-chaning set (which
will come some time later). Then there are some fixes in specific commits --
all issues you raised should be addressed.

You can see the tree for both sets at:
https://github.com/jtulak/xfsprogs-dev/tree/setters

Cheers,
Jan

Jan Tulak (6):
  mkfs: Save raw user input field to the opts struct
  mkfs: rename defaultval to flagval in opts
  mkfs: remove intermediate getstr followed by getnum
  mkfs: merge tables for opts parsing into one table
  mkfs: move getnum within the file
  mkfs: extend opt_params with a value field

 mkfs/xfs_mkfs.c | 1865 ++++++++++++++++++++++++++++++++-----------------------
 1 file changed, 1076 insertions(+), 789 deletions(-)

-- 
2.13.3


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

* [PATCH 1/6] mkfs: Save raw user input field to the opts struct
  2017-08-11 12:30 [PATCH 0/6 v2] mkfs: save user input into opts table Jan Tulak
@ 2017-08-11 12:30 ` Jan Tulak
  2017-08-14 22:56   ` Darrick J. Wong
  2017-08-11 12:30 ` [PATCH 2/6] mkfs: rename defaultval to flagval in opts Jan Tulak
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 37+ messages in thread
From: Jan Tulak @ 2017-08-11 12:30 UTC (permalink / raw)
  To: linux-xfs; +Cc: Jan Tulak

Save exactly what the user gave us for every option.  This way, we will
never lose the information if we need it to print back an issue.
(Just add the infrastructure now, used in the next patches.)

Signed-off-by: Jan Tulak <jtulak@redhat.com>

---
CHANGE:
* added strdup
* added boundary checks to set/get functions
---
 mkfs/xfs_mkfs.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 69 insertions(+)

diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
index 7bb6408f..fa0b475c 100644
--- a/mkfs/xfs_mkfs.c
+++ b/mkfs/xfs_mkfs.c
@@ -107,6 +107,11 @@ unsigned int		sectorsize;
  *     sets what is used with simple specifying the subopt (-d file).
  *     A special SUBOPT_NEEDS_VAL can be used to require a user-given
  *     value in any case.
+ *
+ *   raw_input INTERNAL
+ *     Filled raw string from the user, so we never lose that information e.g.
+ *     to print it back in case of an issue.
+ *
  */
 struct opt_params {
 	const char	name;
@@ -122,6 +127,7 @@ struct opt_params {
 		long long	minval;
 		long long	maxval;
 		long long	defaultval;
+		char		*raw_input;
 	}		subopt_params[MAX_SUBOPTS];
 };
 
@@ -730,6 +736,69 @@ struct opt_params mopts = {
 #define WHACK_SIZE (128 * 1024)
 
 /*
+ * Return 0 on success, -ENOMEM if it could not allocate enough memory for
+ * the string to be saved.
+ */
+static int
+set_conf_raw(struct opt_params *opt, const int subopt, const char *value)
+{
+	if (subopt < 0 || subopt >= MAX_SUBOPTS) {
+		fprintf(stderr,
+		"This is a bug: set_conf_raw called with invalid opt/subopt: %c/%d\n",
+		opt->name, subopt);
+		return -EINVAL;
+	}
+	if (value == NULL) {
+		if (opt->subopt_params[subopt].raw_input != NULL)
+			free(opt->subopt_params[subopt].raw_input);
+		opt->subopt_params[subopt].raw_input = NULL;
+	} else {
+		opt->subopt_params[subopt].raw_input = strdup(value);
+		if (opt->subopt_params[subopt].raw_input == NULL)
+			return -ENOMEM;
+	}
+	return 0;
+}
+
+/*
+ * Return 0 on success, -ENOMEM if it could not allocate enough memory for
+ * the string to be saved into the out pointer.
+ */
+static int
+get_conf_raw(const struct opt_params *opt, const int subopt, char **out)
+{
+	if (subopt < 0 || subopt >= MAX_SUBOPTS) {
+		fprintf(stderr,
+		"This is a bug: get_conf_raw called with invalid opt/subopt: %c/%d\n",
+		opt->name, subopt);
+		return -EINVAL;
+	}
+	*out = strdup(opt->subopt_params[subopt].raw_input);
+	if (*out == NULL)
+		return -ENOMEM;
+	return 0;
+
+}
+
+/*
+ * Same as get_conf_raw(), except it returns the string through return.
+ * If any error occurs, return NULL.
+ */
+static char *
+get_conf_raw_safe(const struct opt_params *opt, const int subopt)
+{
+	char *str;
+
+	str = NULL;
+
+	if (get_conf_raw(opt, subopt, &str) == -ENOMEM) {
+		fprintf(stderr, "Out of memory!");
+		return NULL;
+	}
+	return str;
+}
+
+/*
  * Convert lsu to lsunit for 512 bytes blocks and check validity of the values.
  */
 static void
-- 
2.13.3


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

* [PATCH 2/6] mkfs: rename defaultval to flagval in opts
  2017-08-11 12:30 [PATCH 0/6 v2] mkfs: save user input into opts table Jan Tulak
  2017-08-11 12:30 ` [PATCH 1/6] mkfs: Save raw user input field to the opts struct Jan Tulak
@ 2017-08-11 12:30 ` Jan Tulak
  2017-08-14 22:56   ` Darrick J. Wong
  2017-08-11 12:30 ` [PATCH 3/6] mkfs: remove intermediate getstr followed by getnum Jan Tulak
                   ` (4 subsequent siblings)
  6 siblings, 1 reply; 37+ messages in thread
From: Jan Tulak @ 2017-08-11 12:30 UTC (permalink / raw)
  To: linux-xfs; +Cc: Jan Tulak

The old name 'defaultval' was misleading - it is not the default value,
but the value the option has when used as a flag by an user.

Signed-off-by: Jan Tulak <jtulak@redhat.com>
Reviewed-by: Luis R. Rodriguez <mcgrof@kernel.org>
---
 mkfs/xfs_mkfs.c | 120 ++++++++++++++++++++++++++++----------------------------
 1 file changed, 60 insertions(+), 60 deletions(-)

diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
index fa0b475c..9431f010 100644
--- a/mkfs/xfs_mkfs.c
+++ b/mkfs/xfs_mkfs.c
@@ -101,7 +101,7 @@ unsigned int		sectorsize;
  *     to zero. But if one value is different: minval=0 and maxval=1,
  *     then it is OK.)
  *
- *   defaultval MANDATORY
+ *   flagval MANDATORY
  *     The value used if user specifies the subopt, but no value.
  *     If the subopt accepts some values (-d file=[1|0]), then this
  *     sets what is used with simple specifying the subopt (-d file).
@@ -126,7 +126,7 @@ struct opt_params {
 		int		conflicts[MAX_CONFLICTS];
 		long long	minval;
 		long long	maxval;
-		long long	defaultval;
+		long long	flagval;
 		char		*raw_input;
 	}		subopt_params[MAX_SUBOPTS];
 };
@@ -146,7 +146,7 @@ struct opt_params bopts = {
 				 LAST_CONFLICT },
 		  .minval = XFS_MIN_BLOCKSIZE_LOG,
 		  .maxval = XFS_MAX_BLOCKSIZE_LOG,
-		  .defaultval = SUBOPT_NEEDS_VAL,
+		  .flagval = SUBOPT_NEEDS_VAL,
 		},
 		{ .index = B_SIZE,
 		  .convert = true,
@@ -155,7 +155,7 @@ struct opt_params bopts = {
 				 LAST_CONFLICT },
 		  .minval = XFS_MIN_BLOCKSIZE,
 		  .maxval = XFS_MAX_BLOCKSIZE,
-		  .defaultval = SUBOPT_NEEDS_VAL,
+		  .flagval = SUBOPT_NEEDS_VAL,
 		},
 	},
 };
@@ -201,24 +201,24 @@ struct opt_params dopts = {
 				 LAST_CONFLICT },
 		  .minval = 1,
 		  .maxval = XFS_MAX_AGNUMBER,
-		  .defaultval = SUBOPT_NEEDS_VAL,
+		  .flagval = SUBOPT_NEEDS_VAL,
 		},
 		{ .index = D_FILE,
 		  .conflicts = { LAST_CONFLICT },
 		  .minval = 0,
 		  .maxval = 1,
-		  .defaultval = 1,
+		  .flagval = 1,
 		},
 		{ .index = D_NAME,
 		  .conflicts = { LAST_CONFLICT },
-		  .defaultval = SUBOPT_NEEDS_VAL,
+		  .flagval = SUBOPT_NEEDS_VAL,
 		},
 		{ .index = D_SIZE,
 		  .conflicts = { LAST_CONFLICT },
 		  .convert = true,
 		  .minval = XFS_AG_MIN_BYTES,
 		  .maxval = LLONG_MAX,
-		  .defaultval = SUBOPT_NEEDS_VAL,
+		  .flagval = SUBOPT_NEEDS_VAL,
 		},
 		{ .index = D_SUNIT,
 		  .conflicts = { D_NOALIGN,
@@ -227,7 +227,7 @@ struct opt_params dopts = {
 				 LAST_CONFLICT },
 		  .minval = 0,
 		  .maxval = UINT_MAX,
-		  .defaultval = SUBOPT_NEEDS_VAL,
+		  .flagval = SUBOPT_NEEDS_VAL,
 		},
 		{ .index = D_SWIDTH,
 		  .conflicts = { D_NOALIGN,
@@ -236,7 +236,7 @@ struct opt_params dopts = {
 				 LAST_CONFLICT },
 		  .minval = 0,
 		  .maxval = UINT_MAX,
-		  .defaultval = SUBOPT_NEEDS_VAL,
+		  .flagval = SUBOPT_NEEDS_VAL,
 		},
 		{ .index = D_AGSIZE,
 		  .conflicts = { D_AGCOUNT,
@@ -244,7 +244,7 @@ struct opt_params dopts = {
 		  .convert = true,
 		  .minval = XFS_AG_MIN_BYTES,
 		  .maxval = XFS_AG_MAX_BYTES,
-		  .defaultval = SUBOPT_NEEDS_VAL,
+		  .flagval = SUBOPT_NEEDS_VAL,
 		},
 		{ .index = D_SU,
 		  .conflicts = { D_NOALIGN,
@@ -254,7 +254,7 @@ struct opt_params dopts = {
 		  .convert = true,
 		  .minval = 0,
 		  .maxval = UINT_MAX,
-		  .defaultval = SUBOPT_NEEDS_VAL,
+		  .flagval = SUBOPT_NEEDS_VAL,
 		},
 		{ .index = D_SW,
 		  .conflicts = { D_NOALIGN,
@@ -263,14 +263,14 @@ struct opt_params dopts = {
 				 LAST_CONFLICT },
 		  .minval = 0,
 		  .maxval = UINT_MAX,
-		  .defaultval = SUBOPT_NEEDS_VAL,
+		  .flagval = SUBOPT_NEEDS_VAL,
 		},
 		{ .index = D_SECTLOG,
 		  .conflicts = { D_SECTSIZE,
 				 LAST_CONFLICT },
 		  .minval = XFS_MIN_SECTORSIZE_LOG,
 		  .maxval = XFS_MAX_SECTORSIZE_LOG,
-		  .defaultval = SUBOPT_NEEDS_VAL,
+		  .flagval = SUBOPT_NEEDS_VAL,
 		},
 		{ .index = D_SECTSIZE,
 		  .conflicts = { D_SECTLOG,
@@ -279,7 +279,7 @@ struct opt_params dopts = {
 		  .is_power_2 = true,
 		  .minval = XFS_MIN_SECTORSIZE,
 		  .maxval = XFS_MAX_SECTORSIZE,
-		  .defaultval = SUBOPT_NEEDS_VAL,
+		  .flagval = SUBOPT_NEEDS_VAL,
 		},
 		{ .index = D_NOALIGN,
 		  .conflicts = { D_SU,
@@ -289,25 +289,25 @@ struct opt_params dopts = {
 				 LAST_CONFLICT },
 		  .minval = 0,
 		  .maxval = 1,
-		  .defaultval = 1,
+		  .flagval = 1,
 		},
 		{ .index = D_RTINHERIT,
 		  .conflicts = { LAST_CONFLICT },
 		  .minval = 1,
 		  .maxval = 1,
-		  .defaultval = 1,
+		  .flagval = 1,
 		},
 		{ .index = D_PROJINHERIT,
 		  .conflicts = { LAST_CONFLICT },
 		  .minval = 0,
 		  .maxval = UINT_MAX,
-		  .defaultval = SUBOPT_NEEDS_VAL,
+		  .flagval = SUBOPT_NEEDS_VAL,
 		},
 		{ .index = D_EXTSZINHERIT,
 		  .conflicts = { LAST_CONFLICT },
 		  .minval = 0,
 		  .maxval = UINT_MAX,
-		  .defaultval = SUBOPT_NEEDS_VAL,
+		  .flagval = SUBOPT_NEEDS_VAL,
 		},
 	},
 };
@@ -339,7 +339,7 @@ struct opt_params iopts = {
 		  .conflicts = { LAST_CONFLICT },
 		  .minval = 0,
 		  .maxval = 1,
-		  .defaultval = 1,
+		  .flagval = 1,
 		},
 		{ .index = I_LOG,
 		  .conflicts = { I_PERBLOCK,
@@ -347,13 +347,13 @@ struct opt_params iopts = {
 				 LAST_CONFLICT },
 		  .minval = XFS_DINODE_MIN_LOG,
 		  .maxval = XFS_DINODE_MAX_LOG,
-		  .defaultval = SUBOPT_NEEDS_VAL,
+		  .flagval = SUBOPT_NEEDS_VAL,
 		},
 		{ .index = I_MAXPCT,
 		  .conflicts = { LAST_CONFLICT },
 		  .minval = 0,
 		  .maxval = 100,
-		  .defaultval = SUBOPT_NEEDS_VAL,
+		  .flagval = SUBOPT_NEEDS_VAL,
 		},
 		{ .index = I_PERBLOCK,
 		  .conflicts = { I_LOG,
@@ -362,7 +362,7 @@ struct opt_params iopts = {
 		  .is_power_2 = true,
 		  .minval = XFS_MIN_INODE_PERBLOCK,
 		  .maxval = XFS_MAX_BLOCKSIZE / XFS_DINODE_MIN_SIZE,
-		  .defaultval = SUBOPT_NEEDS_VAL,
+		  .flagval = SUBOPT_NEEDS_VAL,
 		},
 		{ .index = I_SIZE,
 		  .conflicts = { I_PERBLOCK,
@@ -371,25 +371,25 @@ struct opt_params iopts = {
 		  .is_power_2 = true,
 		  .minval = XFS_DINODE_MIN_SIZE,
 		  .maxval = XFS_DINODE_MAX_SIZE,
-		  .defaultval = SUBOPT_NEEDS_VAL,
+		  .flagval = SUBOPT_NEEDS_VAL,
 		},
 		{ .index = I_ATTR,
 		  .conflicts = { LAST_CONFLICT },
 		  .minval = 0,
 		  .maxval = 2,
-		  .defaultval = SUBOPT_NEEDS_VAL,
+		  .flagval = SUBOPT_NEEDS_VAL,
 		},
 		{ .index = I_PROJID32BIT,
 		  .conflicts = { LAST_CONFLICT },
 		  .minval = 0,
 		  .maxval = 1,
-		  .defaultval = 1,
+		  .flagval = 1,
 		},
 		{ .index = I_SPINODES,
 		  .conflicts = { LAST_CONFLICT },
 		  .minval = 0,
 		  .maxval = 1,
-		  .defaultval = 1,
+		  .flagval = 1,
 		},
 	},
 };
@@ -429,7 +429,7 @@ struct opt_params lopts = {
 				 LAST_CONFLICT },
 		  .minval = 0,
 		  .maxval = UINT_MAX,
-		  .defaultval = SUBOPT_NEEDS_VAL,
+		  .flagval = SUBOPT_NEEDS_VAL,
 		},
 		{ .index = L_INTERNAL,
 		  .conflicts = { L_FILE,
@@ -437,27 +437,27 @@ struct opt_params lopts = {
 				 LAST_CONFLICT },
 		  .minval = 0,
 		  .maxval = 1,
-		  .defaultval = 1,
+		  .flagval = 1,
 		},
 		{ .index = L_SIZE,
 		  .conflicts = { LAST_CONFLICT },
 		  .convert = true,
 		  .minval = 2 * 1024 * 1024LL,	/* XXX: XFS_MIN_LOG_BYTES */
 		  .maxval = XFS_MAX_LOG_BYTES,
-		  .defaultval = SUBOPT_NEEDS_VAL,
+		  .flagval = SUBOPT_NEEDS_VAL,
 		},
 		{ .index = L_VERSION,
 		  .conflicts = { LAST_CONFLICT },
 		  .minval = 1,
 		  .maxval = 2,
-		  .defaultval = SUBOPT_NEEDS_VAL,
+		  .flagval = SUBOPT_NEEDS_VAL,
 		},
 		{ .index = L_SUNIT,
 		  .conflicts = { L_SU,
 				 LAST_CONFLICT },
 		  .minval = 1,
 		  .maxval = BTOBB(XLOG_MAX_RECORD_BSIZE),
-		  .defaultval = SUBOPT_NEEDS_VAL,
+		  .flagval = SUBOPT_NEEDS_VAL,
 		},
 		{ .index = L_SU,
 		  .conflicts = { L_SUNIT,
@@ -465,20 +465,20 @@ struct opt_params lopts = {
 		  .convert = true,
 		  .minval = BBTOB(1),
 		  .maxval = XLOG_MAX_RECORD_BSIZE,
-		  .defaultval = SUBOPT_NEEDS_VAL,
+		  .flagval = SUBOPT_NEEDS_VAL,
 		},
 		{ .index = L_DEV,
 		  .conflicts = { L_AGNUM,
 				 L_INTERNAL,
 				 LAST_CONFLICT },
-		  .defaultval = SUBOPT_NEEDS_VAL,
+		  .flagval = SUBOPT_NEEDS_VAL,
 		},
 		{ .index = L_SECTLOG,
 		  .conflicts = { L_SECTSIZE,
 				 LAST_CONFLICT },
 		  .minval = XFS_MIN_SECTORSIZE_LOG,
 		  .maxval = XFS_MAX_SECTORSIZE_LOG,
-		  .defaultval = SUBOPT_NEEDS_VAL,
+		  .flagval = SUBOPT_NEEDS_VAL,
 		},
 		{ .index = L_SECTSIZE,
 		  .conflicts = { L_SECTLOG,
@@ -487,26 +487,26 @@ struct opt_params lopts = {
 		  .is_power_2 = true,
 		  .minval = XFS_MIN_SECTORSIZE,
 		  .maxval = XFS_MAX_SECTORSIZE,
-		  .defaultval = SUBOPT_NEEDS_VAL,
+		  .flagval = SUBOPT_NEEDS_VAL,
 		},
 		{ .index = L_FILE,
 		  .conflicts = { L_INTERNAL,
 				 LAST_CONFLICT },
 		  .minval = 0,
 		  .maxval = 1,
-		  .defaultval = 1,
+		  .flagval = 1,
 		},
 		{ .index = L_NAME,
 		  .conflicts = { L_AGNUM,
 				 L_INTERNAL,
 				 LAST_CONFLICT },
-		  .defaultval = SUBOPT_NEEDS_VAL,
+		  .flagval = SUBOPT_NEEDS_VAL,
 		},
 		{ .index = L_LAZYSBCNTR,
 		  .conflicts = { LAST_CONFLICT },
 		  .minval = 0,
 		  .maxval = 1,
-		  .defaultval = 1,
+		  .flagval = 1,
 		},
 	},
 };
@@ -530,7 +530,7 @@ struct opt_params nopts = {
 				 LAST_CONFLICT },
 		  .minval = XFS_MIN_REC_DIRSIZE,
 		  .maxval = XFS_MAX_BLOCKSIZE_LOG,
-		  .defaultval = SUBOPT_NEEDS_VAL,
+		  .flagval = SUBOPT_NEEDS_VAL,
 		},
 		{ .index = N_SIZE,
 		  .conflicts = { N_LOG,
@@ -539,19 +539,19 @@ struct opt_params nopts = {
 		  .is_power_2 = true,
 		  .minval = 1 << XFS_MIN_REC_DIRSIZE,
 		  .maxval = XFS_MAX_BLOCKSIZE,
-		  .defaultval = SUBOPT_NEEDS_VAL,
+		  .flagval = SUBOPT_NEEDS_VAL,
 		},
 		{ .index = N_VERSION,
 		  .conflicts = { LAST_CONFLICT },
 		  .minval = 2,
 		  .maxval = 2,
-		  .defaultval = SUBOPT_NEEDS_VAL,
+		  .flagval = SUBOPT_NEEDS_VAL,
 		},
 		{ .index = N_FTYPE,
 		  .conflicts = { LAST_CONFLICT },
 		  .minval = 0,
 		  .maxval = 1,
-		  .defaultval = 1,
+		  .flagval = 1,
 		},
 	},
 };
@@ -579,33 +579,33 @@ struct opt_params ropts = {
 		  .convert = true,
 		  .minval = XFS_MIN_RTEXTSIZE,
 		  .maxval = XFS_MAX_RTEXTSIZE,
-		  .defaultval = SUBOPT_NEEDS_VAL,
+		  .flagval = SUBOPT_NEEDS_VAL,
 		},
 		{ .index = R_SIZE,
 		  .conflicts = { LAST_CONFLICT },
 		  .convert = true,
 		  .minval = 0,
 		  .maxval = LLONG_MAX,
-		  .defaultval = SUBOPT_NEEDS_VAL,
+		  .flagval = SUBOPT_NEEDS_VAL,
 		},
 		{ .index = R_DEV,
 		  .conflicts = { LAST_CONFLICT },
-		  .defaultval = SUBOPT_NEEDS_VAL,
+		  .flagval = SUBOPT_NEEDS_VAL,
 		},
 		{ .index = R_FILE,
 		  .minval = 0,
 		  .maxval = 1,
-		  .defaultval = 1,
+		  .flagval = 1,
 		  .conflicts = { LAST_CONFLICT },
 		},
 		{ .index = R_NAME,
 		  .conflicts = { LAST_CONFLICT },
-		  .defaultval = SUBOPT_NEEDS_VAL,
+		  .flagval = SUBOPT_NEEDS_VAL,
 		},
 		{ .index = R_NOALIGN,
 		  .minval = 0,
 		  .maxval = 1,
-		  .defaultval = 1,
+		  .flagval = 1,
 		  .conflicts = { LAST_CONFLICT },
 		},
 	},
@@ -631,7 +631,7 @@ struct opt_params sopts = {
 				 LAST_CONFLICT },
 		  .minval = XFS_MIN_SECTORSIZE_LOG,
 		  .maxval = XFS_MAX_SECTORSIZE_LOG,
-		  .defaultval = SUBOPT_NEEDS_VAL,
+		  .flagval = SUBOPT_NEEDS_VAL,
 		},
 		{ .index = S_SECTLOG,
 		  .conflicts = { S_SIZE,
@@ -639,7 +639,7 @@ struct opt_params sopts = {
 				 LAST_CONFLICT },
 		  .minval = XFS_MIN_SECTORSIZE_LOG,
 		  .maxval = XFS_MAX_SECTORSIZE_LOG,
-		  .defaultval = SUBOPT_NEEDS_VAL,
+		  .flagval = SUBOPT_NEEDS_VAL,
 		},
 		{ .index = S_SIZE,
 		  .conflicts = { S_LOG,
@@ -649,7 +649,7 @@ struct opt_params sopts = {
 		  .is_power_2 = true,
 		  .minval = XFS_MIN_SECTORSIZE,
 		  .maxval = XFS_MAX_SECTORSIZE,
-		  .defaultval = SUBOPT_NEEDS_VAL,
+		  .flagval = SUBOPT_NEEDS_VAL,
 		},
 		{ .index = S_SECTSIZE,
 		  .conflicts = { S_LOG,
@@ -659,7 +659,7 @@ struct opt_params sopts = {
 		  .is_power_2 = true,
 		  .minval = XFS_MIN_SECTORSIZE,
 		  .maxval = XFS_MAX_SECTORSIZE,
-		  .defaultval = SUBOPT_NEEDS_VAL,
+		  .flagval = SUBOPT_NEEDS_VAL,
 		},
 	},
 };
@@ -684,29 +684,29 @@ struct opt_params mopts = {
 		  .conflicts = { LAST_CONFLICT },
 		  .minval = 0,
 		  .maxval = 1,
-		  .defaultval = 1,
+		  .flagval = 1,
 		},
 		{ .index = M_FINOBT,
 		  .conflicts = { LAST_CONFLICT },
 		  .minval = 0,
 		  .maxval = 1,
-		  .defaultval = 1,
+		  .flagval = 1,
 		},
 		{ .index = M_UUID,
 		  .conflicts = { LAST_CONFLICT },
-		  .defaultval = SUBOPT_NEEDS_VAL,
+		  .flagval = SUBOPT_NEEDS_VAL,
 		},
 		{ .index = M_RMAPBT,
 		  .conflicts = { LAST_CONFLICT },
 		  .minval = 0,
 		  .maxval = 1,
-		  .defaultval = 1,
+		  .flagval = 1,
 		},
 		{ .index = M_REFLINK,
 		  .conflicts = { LAST_CONFLICT },
 		  .minval = 0,
 		  .maxval = 1,
-		  .defaultval = 1,
+		  .flagval = 1,
 		},
 	},
 };
@@ -1398,9 +1398,9 @@ getnum(
 	check_opt(opts, index, false);
 	/* empty strings might just return a default value */
 	if (!str || *str == '\0') {
-		if (sp->defaultval == SUBOPT_NEEDS_VAL)
+		if (sp->flagval == SUBOPT_NEEDS_VAL)
 			reqval(opts->name, (char **)opts->subopts, index);
-		return sp->defaultval;
+		return sp->flagval;
 	}
 
 	if (sp->minval == 0 && sp->maxval == 0) {
-- 
2.13.3


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

* [PATCH 3/6] mkfs: remove intermediate getstr followed by getnum
  2017-08-11 12:30 [PATCH 0/6 v2] mkfs: save user input into opts table Jan Tulak
  2017-08-11 12:30 ` [PATCH 1/6] mkfs: Save raw user input field to the opts struct Jan Tulak
  2017-08-11 12:30 ` [PATCH 2/6] mkfs: rename defaultval to flagval in opts Jan Tulak
@ 2017-08-11 12:30 ` Jan Tulak
  2017-08-14 22:58   ` Darrick J. Wong
  2017-08-11 12:30 ` [PATCH 4/6] mkfs: merge tables for opts parsing into one table Jan Tulak
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 37+ messages in thread
From: Jan Tulak @ 2017-08-11 12:30 UTC (permalink / raw)
  To: linux-xfs; +Cc: Jan Tulak

Some options loaded a number as a string with getstr and converted it to
number with getnum later in the code, without any reason for this
approach.  (They were probably forgotten in some past cleaning.)

This patch changes them to skip the string and use getnum directly in
the main option-parsing loop, as do all the other numerical options.
And as we now have two variables of the same type for the same value,
merge them together. (e.g. former string dsize and number dbytes).

Signed-off-by: Jan Tulak <jtulak@redhat.com>

---

This patch has to be applied after "mkfs: Save raw user input ...",
because otherwise we would temporary lose the access to strings
with user-given values and thus wouldn't be able to report them in
case of an issue. (In reply to Eric's comment.)

UPDATE:
 * fix dbytes, rtbytes, rtextbytes and logbytes - these variables should
   be uint64, as the local old ones they are replacing, but were
   unintentionally created as int
---
 mkfs/xfs_mkfs.c | 90 ++++++++++++++++++++++++++-------------------------------
 1 file changed, 41 insertions(+), 49 deletions(-)

diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
index 9431f010..78e27498 100644
--- a/mkfs/xfs_mkfs.c
+++ b/mkfs/xfs_mkfs.c
@@ -1396,6 +1396,7 @@ getnum(
 	long long		c;
 
 	check_opt(opts, index, false);
+	set_conf_raw(opts, index, str);
 	/* empty strings might just return a default value */
 	if (!str || *str == '\0') {
 		if (sp->flagval == SUBOPT_NEEDS_VAL)
@@ -1483,13 +1484,13 @@ main(
 	char			*dfile;
 	int			dirblocklog;
 	int			dirblocksize;
-	char			*dsize;
+	uint64_t		dbytes;
 	int			dsu;
 	int			dsw;
 	int			dsunit;
 	int			dswidth;
 	int			dsflag;
-	int			force_overwrite;
+	bool			force_overwrite;
 	struct fsxattr		fsx;
 	int			ilflag;
 	int			imaxpct;
@@ -1508,7 +1509,7 @@ main(
 	xfs_rfsblock_t		logblocks;
 	char			*logfile;
 	int			loginternal;
-	char			*logsize;
+	uint64_t		logbytes;
 	xfs_fsblock_t		logstart;
 	int			lvflag;
 	int			lsflag;
@@ -1537,11 +1538,11 @@ main(
 	char			*protostring;
 	int			qflag;
 	xfs_rfsblock_t		rtblocks;
+	uint64_t		rtbytes;
 	xfs_extlen_t		rtextblocks;
 	xfs_rtblock_t		rtextents;
-	char			*rtextsize;
+	uint64_t		rtextbytes;
 	char			*rtfile;
-	char			*rtsize;
 	xfs_sb_t		*sbp;
 	int			sectorlog;
 	uint64_t		sector_mask;
@@ -1589,7 +1590,8 @@ main(
 	qflag = 0;
 	imaxpct = inodelog = inopblock = isize = 0;
 	dfile = logfile = rtfile = NULL;
-	dsize = logsize = rtsize = rtextsize = protofile = NULL;
+	protofile = NULL;
+	rtbytes = rtextbytes = logbytes = dbytes = 0;
 	dsu = dsw = dsunit = dswidth = lalign = lsu = lsunit = 0;
 	dsflag = nodsflag = norsflag = 0;
 	force_overwrite = 0;
@@ -1653,7 +1655,7 @@ main(
 					xi.dname = getstr(value, &dopts, D_NAME);
 					break;
 				case D_SIZE:
-					dsize = getstr(value, &dopts, D_SIZE);
+					dbytes = getnum(value, &dopts, D_SIZE);
 					break;
 				case D_SUNIT:
 					dsunit = getnum(value, &dopts, D_SUNIT);
@@ -1802,7 +1804,7 @@ main(
 					lvflag = 1;
 					break;
 				case L_SIZE:
-					logsize = getstr(value, &lopts, L_SIZE);
+					logbytes = getnum(value, &lopts, L_SIZE);
 					break;
 				case L_SECTLOG:
 					lsectorlog = getnum(value, &lopts,
@@ -1931,8 +1933,7 @@ main(
 
 				switch (getsubopt(&p, subopts, &value)) {
 				case R_EXTSIZE:
-					rtextsize = getstr(value, &ropts,
-							   R_EXTSIZE);
+					rtextbytes = getnum(value, &ropts, R_EXTSIZE);
 					break;
 				case R_FILE:
 					xi.risfile = getnum(value, &ropts,
@@ -1944,7 +1945,7 @@ main(
 							   R_NAME);
 					break;
 				case R_SIZE:
-					rtsize = getstr(value, &ropts, R_SIZE);
+					rtbytes = getnum(value, &ropts, R_SIZE);
 					break;
 				case R_NOALIGN:
 					norsflag = getnum(value, &ropts,
@@ -2047,14 +2048,14 @@ _("Minimum block size for CRC enabled filesystems is %d bytes.\n"),
 	 * sector size mismatches between the new filesystem and the underlying
 	 * host filesystem.
 	 */
-	check_device_type(dfile, &xi.disfile, !dsize, !dfile,
+	check_device_type(dfile, &xi.disfile, !dbytes, !dfile,
 			  Nflag ? NULL : &xi.dcreat, force_overwrite, "d");
 	if (!loginternal)
-		check_device_type(xi.logname, &xi.lisfile, !logsize, !xi.logname,
-				  Nflag ? NULL : &xi.lcreat,
+		check_device_type(xi.logname, &xi.lisfile, !logbytes,
+				  !xi.logname, Nflag ? NULL : &xi.lcreat,
 				  force_overwrite, "l");
 	if (xi.rtname)
-		check_device_type(xi.rtname, &xi.risfile, !rtsize, !xi.rtname,
+		check_device_type(xi.rtname, &xi.risfile, !rtbytes, !xi.rtname,
 				  Nflag ? NULL : &xi.rcreat,
 				  force_overwrite, "r");
 	if (xi.disfile || xi.lisfile || xi.risfile)
@@ -2235,10 +2236,7 @@ _("rmapbt not supported with realtime devices\n"));
 	}
 
 
-	if (dsize) {
-		uint64_t dbytes;
-
-		dbytes = getnum(dsize, &dopts, D_SIZE);
+	if (dbytes) {
 		if (dbytes % XFS_MIN_BLOCKSIZE) {
 			fprintf(stderr,
 			_("illegal data length %lld, not a multiple of %d\n"),
@@ -2267,10 +2265,7 @@ _("rmapbt not supported with realtime devices\n"));
 		usage();
 	}
 
-	if (logsize) {
-		uint64_t logbytes;
-
-		logbytes = getnum(logsize, &lopts, L_SIZE);
+	if (logbytes) {
 		if (logbytes % XFS_MIN_BLOCKSIZE) {
 			fprintf(stderr,
 			_("illegal log length %lld, not a multiple of %d\n"),
@@ -2284,10 +2279,7 @@ _("rmapbt not supported with realtime devices\n"));
 				(long long)logbytes, blocksize,
 				(long long)(logblocks << blocklog));
 	}
-	if (rtsize) {
-		uint64_t rtbytes;
-
-		rtbytes = getnum(rtsize, &ropts, R_SIZE);
+	if (rtbytes) {
 		if (rtbytes % XFS_MIN_BLOCKSIZE) {
 			fprintf(stderr,
 			_("illegal rt length %lld, not a multiple of %d\n"),
@@ -2304,10 +2296,7 @@ _("rmapbt not supported with realtime devices\n"));
 	/*
 	 * If specified, check rt extent size against its constraints.
 	 */
-	if (rtextsize) {
-		uint64_t rtextbytes;
-
-		rtextbytes = getnum(rtextsize, &ropts, R_EXTSIZE);
+	if (rtextbytes) {
 		if (rtextbytes % blocksize) {
 			fprintf(stderr,
 		_("illegal rt extent size %lld, not a multiple of %d\n"),
@@ -2324,7 +2313,7 @@ _("rmapbt not supported with realtime devices\n"));
 		uint64_t	rswidth;
 		uint64_t	rtextbytes;
 
-		if (!norsflag && !xi.risfile && !(!rtsize && xi.disfile))
+		if (!norsflag && !xi.risfile && !(!rtbytes && xi.disfile))
 			rswidth = ft.rtswidth;
 		else
 			rswidth = 0;
@@ -2439,15 +2428,16 @@ _("rmapbt not supported with realtime devices\n"));
 		rtfile = _("volume rt");
 	else if (!xi.rtdev)
 		rtfile = _("none");
-	if (dsize && xi.dsize > 0 && dblocks > DTOBT(xi.dsize)) {
+	if (dbytes && xi.dsize > 0 && dblocks > DTOBT(xi.dsize)) {
 		fprintf(stderr,
 			_("size %s specified for data subvolume is too large, "
 			"maximum is %lld blocks\n"),
-			dsize, (long long)DTOBT(xi.dsize));
+			get_conf_raw_safe(&dopts, D_SIZE),
+			(long long)DTOBT(xi.dsize));
 		usage();
-	} else if (!dsize && xi.dsize > 0)
+	} else if (!dbytes && xi.dsize > 0)
 		dblocks = DTOBT(xi.dsize);
-	else if (!dsize) {
+	else if (!dbytes) {
 		fprintf(stderr, _("can't get size of data subvolume\n"));
 		usage();
 	}
@@ -2480,22 +2470,23 @@ reported by the device (%u).\n"),
 reported by the device (%u).\n"),
 			lsectorsize, xi.lbsize);
 	}
-	if (rtsize && xi.rtsize > 0 && xi.rtbsize > sectorsize) {
+	if (rtbytes && xi.rtsize > 0 && xi.rtbsize > sectorsize) {
 		fprintf(stderr, _(
 "Warning: the realtime subvolume sector size %u is less than the sector size\n\
 reported by the device (%u).\n"),
 			sectorsize, xi.rtbsize);
 	}
 
-	if (rtsize && xi.rtsize > 0 && rtblocks > DTOBT(xi.rtsize)) {
+	if (rtbytes && xi.rtsize > 0 && rtblocks > DTOBT(xi.rtsize)) {
 		fprintf(stderr,
 			_("size %s specified for rt subvolume is too large, "
 			"maximum is %lld blocks\n"),
-			rtsize, (long long)DTOBT(xi.rtsize));
+			get_conf_raw_safe(&ropts, R_SIZE),
+			(long long)DTOBT(xi.rtsize));
 		usage();
-	} else if (!rtsize && xi.rtsize > 0)
+	} else if (!rtbytes && xi.rtsize > 0)
 		rtblocks = DTOBT(xi.rtsize);
-	else if (rtsize && !xi.rtdev) {
+	else if (rtbytes && !xi.rtdev) {
 		fprintf(stderr,
 			_("size specified for non-existent rt subvolume\n"));
 		usage();
@@ -2701,26 +2692,27 @@ an AG size that is one stripe unit smaller, for example %llu.\n"),
 				   sb_feat.inode_align);
 	ASSERT(min_logblocks);
 	min_logblocks = MAX(XFS_MIN_LOG_BLOCKS, min_logblocks);
-	if (!logsize && dblocks >= (1024*1024*1024) >> blocklog)
+	if (!logbytes && dblocks >= (1024*1024*1024) >> blocklog)
 		min_logblocks = MAX(min_logblocks, XFS_MIN_LOG_BYTES>>blocklog);
-	if (logsize && xi.logBBsize > 0 && logblocks > DTOBT(xi.logBBsize)) {
+	if (logbytes && xi.logBBsize > 0 && logblocks > DTOBT(xi.logBBsize)) {
 		fprintf(stderr,
 _("size %s specified for log subvolume is too large, maximum is %lld blocks\n"),
-			logsize, (long long)DTOBT(xi.logBBsize));
+			get_conf_raw_safe(&lopts, L_SIZE),
+			(long long)DTOBT(xi.logBBsize));
 		usage();
-	} else if (!logsize && xi.logBBsize > 0) {
+	} else if (!logbytes && xi.logBBsize > 0) {
 		logblocks = DTOBT(xi.logBBsize);
-	} else if (logsize && !xi.logdev && !loginternal) {
+	} else if (logbytes && !xi.logdev && !loginternal) {
 		fprintf(stderr,
 			_("size specified for non-existent log subvolume\n"));
 		usage();
-	} else if (loginternal && logsize && logblocks >= dblocks) {
+	} else if (loginternal && logbytes && logblocks >= dblocks) {
 		fprintf(stderr, _("size %lld too large for internal log\n"),
 			(long long)logblocks);
 		usage();
 	} else if (!loginternal && !xi.logdev) {
 		logblocks = 0;
-	} else if (loginternal && !logsize) {
+	} else if (loginternal && !logbytes) {
 
 		if (dblocks < GIGABYTES(1, blocklog)) {
 			/* tiny filesystems get minimum sized logs. */
@@ -2784,7 +2776,7 @@ _("size %s specified for log subvolume is too large, maximum is %lld blocks\n"),
 		 * Readjust the log size to fit within an AG if it was sized
 		 * automatically.
 		 */
-		if (!logsize) {
+		if (!logbytes) {
 			logblocks = MIN(logblocks,
 					libxfs_alloc_ag_max_usable(mp));
 
-- 
2.13.3


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

* [PATCH 4/6] mkfs: merge tables for opts parsing into one table
  2017-08-11 12:30 [PATCH 0/6 v2] mkfs: save user input into opts table Jan Tulak
                   ` (2 preceding siblings ...)
  2017-08-11 12:30 ` [PATCH 3/6] mkfs: remove intermediate getstr followed by getnum Jan Tulak
@ 2017-08-11 12:30 ` Jan Tulak
  2017-08-14 23:06   ` Darrick J. Wong
  2017-08-11 12:30 ` [PATCH 5/6] mkfs: move getnum within the file Jan Tulak
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 37+ messages in thread
From: Jan Tulak @ 2017-08-11 12:30 UTC (permalink / raw)
  To: linux-xfs; +Cc: Jan Tulak

Merge separate instances of opt_params into one indexable table. Git
makes this patch looks a bit more complicated, but it does not change
values or structure of anything else. It only moves all the "struct
opt_params dopts = {...}", changes indentation for these substructures
and replaces their usage (dopts -> opts[OPT_D]).

The reason for this is to be able to address all options from any single
one, even across OPT_X. Right now, we can do automated conflict checks
only within one OPT_X, but after this, it is possible to extend the
conflict declaration to other options as well.

Signed-off-by: Jan Tulak <jtulak@redhat.com>
---
Change:
 * expand bounds check to newly added opt parameter in get/set functions
 * updated description
---
 mkfs/xfs_mkfs.c | 1341 +++++++++++++++++++++++++++++--------------------------
 1 file changed, 696 insertions(+), 645 deletions(-)

diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
index 78e27498..e3f7d345 100644
--- a/mkfs/xfs_mkfs.c
+++ b/mkfs/xfs_mkfs.c
@@ -39,6 +39,7 @@ static int  ispow2(unsigned int i);
 unsigned int		blocksize;
 unsigned int		sectorsize;
 
+#define MAX_OPTS	16
 #define MAX_SUBOPTS	16
 #define SUBOPT_NEEDS_VAL	(-1LL)
 #define MAX_CONFLICTS	8
@@ -49,6 +50,10 @@ unsigned int		sectorsize;
  *
  * Description of the structure members follows:
  *
+ * index MANDATORY
+ *   An integer denoting the position of the specific option in opts array,
+ *   counting from 0 up to MAX_OPTS.
+ *
  * name MANDATORY
  *   Name is a single char, e.g., for '-d file', name is 'd'.
  *
@@ -114,6 +119,7 @@ unsigned int		sectorsize;
  *
  */
 struct opt_params {
+	int		index;
 	const char	name;
 	const char	*subopts[MAX_SUBOPTS];
 
@@ -129,584 +135,592 @@ struct opt_params {
 		long long	flagval;
 		char		*raw_input;
 	}		subopt_params[MAX_SUBOPTS];
-};
-
-struct opt_params bopts = {
-	.name = 'b',
-	.subopts = {
+} opts[MAX_OPTS] = {
+#define OPT_B	0
+	{
+		.index = OPT_B,
+		.name = 'b',
+		.subopts = {
 #define	B_LOG		0
-		"log",
+			"log",
 #define	B_SIZE		1
-		"size",
-		NULL
-	},
-	.subopt_params = {
-		{ .index = B_LOG,
-		  .conflicts = { B_SIZE,
-				 LAST_CONFLICT },
-		  .minval = XFS_MIN_BLOCKSIZE_LOG,
-		  .maxval = XFS_MAX_BLOCKSIZE_LOG,
-		  .flagval = SUBOPT_NEEDS_VAL,
+			"size",
+			NULL
 		},
-		{ .index = B_SIZE,
-		  .convert = true,
-		  .is_power_2 = true,
-		  .conflicts = { B_LOG,
-				 LAST_CONFLICT },
-		  .minval = XFS_MIN_BLOCKSIZE,
-		  .maxval = XFS_MAX_BLOCKSIZE,
-		  .flagval = SUBOPT_NEEDS_VAL,
+		.subopt_params = {
+			{ .index = B_LOG,
+			  .conflicts = { B_SIZE,
+					 LAST_CONFLICT },
+			  .minval = XFS_MIN_BLOCKSIZE_LOG,
+			  .maxval = XFS_MAX_BLOCKSIZE_LOG,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = B_SIZE,
+			  .convert = true,
+			  .is_power_2 = true,
+			  .conflicts = { B_LOG,
+					 LAST_CONFLICT },
+			  .minval = XFS_MIN_BLOCKSIZE,
+			  .maxval = XFS_MAX_BLOCKSIZE,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
 		},
 	},
-};
-
-struct opt_params dopts = {
-	.name = 'd',
-	.subopts = {
-#define	D_AGCOUNT	0
-		"agcount",
-#define	D_FILE		1
-		"file",
-#define	D_NAME		2
-		"name",
-#define	D_SIZE		3
-		"size",
-#define D_SUNIT		4
-		"sunit",
-#define D_SWIDTH	5
-		"swidth",
-#define D_AGSIZE	6
-		"agsize",
-#define D_SU		7
-		"su",
-#define D_SW		8
-		"sw",
-#define D_SECTLOG	9
-		"sectlog",
-#define D_SECTSIZE	10
-		"sectsize",
-#define D_NOALIGN	11
-		"noalign",
-#define D_RTINHERIT	12
-		"rtinherit",
-#define D_PROJINHERIT	13
-		"projinherit",
-#define D_EXTSZINHERIT	14
-		"extszinherit",
-		NULL
-	},
-	.subopt_params = {
-		{ .index = D_AGCOUNT,
-		  .conflicts = { D_AGSIZE,
-				 LAST_CONFLICT },
-		  .minval = 1,
-		  .maxval = XFS_MAX_AGNUMBER,
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = D_FILE,
-		  .conflicts = { LAST_CONFLICT },
-		  .minval = 0,
-		  .maxval = 1,
-		  .flagval = 1,
-		},
-		{ .index = D_NAME,
-		  .conflicts = { LAST_CONFLICT },
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = D_SIZE,
-		  .conflicts = { LAST_CONFLICT },
-		  .convert = true,
-		  .minval = XFS_AG_MIN_BYTES,
-		  .maxval = LLONG_MAX,
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = D_SUNIT,
-		  .conflicts = { D_NOALIGN,
-				 D_SU,
-				 D_SW,
-				 LAST_CONFLICT },
-		  .minval = 0,
-		  .maxval = UINT_MAX,
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = D_SWIDTH,
-		  .conflicts = { D_NOALIGN,
-				 D_SU,
-				 D_SW,
-				 LAST_CONFLICT },
-		  .minval = 0,
-		  .maxval = UINT_MAX,
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = D_AGSIZE,
-		  .conflicts = { D_AGCOUNT,
-				 LAST_CONFLICT },
-		  .convert = true,
-		  .minval = XFS_AG_MIN_BYTES,
-		  .maxval = XFS_AG_MAX_BYTES,
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = D_SU,
-		  .conflicts = { D_NOALIGN,
-				 D_SUNIT,
-				 D_SWIDTH,
-				 LAST_CONFLICT },
-		  .convert = true,
-		  .minval = 0,
-		  .maxval = UINT_MAX,
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = D_SW,
-		  .conflicts = { D_NOALIGN,
-				 D_SUNIT,
-				 D_SWIDTH,
-				 LAST_CONFLICT },
-		  .minval = 0,
-		  .maxval = UINT_MAX,
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = D_SECTLOG,
-		  .conflicts = { D_SECTSIZE,
-				 LAST_CONFLICT },
-		  .minval = XFS_MIN_SECTORSIZE_LOG,
-		  .maxval = XFS_MAX_SECTORSIZE_LOG,
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = D_SECTSIZE,
-		  .conflicts = { D_SECTLOG,
-				 LAST_CONFLICT },
-		  .convert = true,
-		  .is_power_2 = true,
-		  .minval = XFS_MIN_SECTORSIZE,
-		  .maxval = XFS_MAX_SECTORSIZE,
-		  .flagval = SUBOPT_NEEDS_VAL,
+#define OPT_D	1
+	{
+		.index = OPT_D,
+		.name = 'd',
+		.subopts = {
+	#define	D_AGCOUNT	0
+			"agcount",
+	#define	D_FILE		1
+			"file",
+	#define	D_NAME		2
+			"name",
+	#define	D_SIZE		3
+			"size",
+	#define D_SUNIT		4
+			"sunit",
+	#define D_SWIDTH	5
+			"swidth",
+	#define D_AGSIZE	6
+			"agsize",
+	#define D_SU		7
+			"su",
+	#define D_SW		8
+			"sw",
+	#define D_SECTLOG	9
+			"sectlog",
+	#define D_SECTSIZE	10
+			"sectsize",
+	#define D_NOALIGN	11
+			"noalign",
+	#define D_RTINHERIT	12
+			"rtinherit",
+	#define D_PROJINHERIT	13
+			"projinherit",
+	#define D_EXTSZINHERIT	14
+			"extszinherit",
+			NULL
 		},
-		{ .index = D_NOALIGN,
-		  .conflicts = { D_SU,
-				 D_SW,
-				 D_SUNIT,
-				 D_SWIDTH,
-				 LAST_CONFLICT },
-		  .minval = 0,
-		  .maxval = 1,
-		  .flagval = 1,
-		},
-		{ .index = D_RTINHERIT,
-		  .conflicts = { LAST_CONFLICT },
-		  .minval = 1,
-		  .maxval = 1,
-		  .flagval = 1,
-		},
-		{ .index = D_PROJINHERIT,
-		  .conflicts = { LAST_CONFLICT },
-		  .minval = 0,
-		  .maxval = UINT_MAX,
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = D_EXTSZINHERIT,
-		  .conflicts = { LAST_CONFLICT },
-		  .minval = 0,
-		  .maxval = UINT_MAX,
-		  .flagval = SUBOPT_NEEDS_VAL,
+		.subopt_params = {
+			{ .index = D_AGCOUNT,
+			  .conflicts = { D_AGSIZE,
+					 LAST_CONFLICT },
+			  .minval = 1,
+			  .maxval = XFS_MAX_AGNUMBER,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = D_FILE,
+			  .conflicts = { LAST_CONFLICT },
+			  .minval = 0,
+			  .maxval = 1,
+			  .flagval = 1,
+			},
+			{ .index = D_NAME,
+			  .conflicts = { LAST_CONFLICT },
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = D_SIZE,
+			  .conflicts = { LAST_CONFLICT },
+			  .convert = true,
+			  .minval = XFS_AG_MIN_BYTES,
+			  .maxval = LLONG_MAX,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = D_SUNIT,
+			  .conflicts = { D_NOALIGN,
+					 D_SU,
+					 D_SW,
+					 LAST_CONFLICT },
+			  .minval = 0,
+			  .maxval = UINT_MAX,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = D_SWIDTH,
+			  .conflicts = { D_NOALIGN,
+					 D_SU,
+					 D_SW,
+					 LAST_CONFLICT },
+			  .minval = 0,
+			  .maxval = UINT_MAX,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = D_AGSIZE,
+			  .conflicts = { D_AGCOUNT,
+					 LAST_CONFLICT },
+			  .convert = true,
+			  .minval = XFS_AG_MIN_BYTES,
+			  .maxval = XFS_AG_MAX_BYTES,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = D_SU,
+			  .conflicts = { D_NOALIGN,
+					 D_SUNIT,
+					 D_SWIDTH,
+					 LAST_CONFLICT },
+			  .convert = true,
+			  .minval = 0,
+			  .maxval = UINT_MAX,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = D_SW,
+			  .conflicts = { D_NOALIGN,
+					 D_SUNIT,
+					 D_SWIDTH,
+					 LAST_CONFLICT },
+			  .minval = 0,
+			  .maxval = UINT_MAX,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = D_SECTLOG,
+			  .conflicts = { D_SECTSIZE,
+					 LAST_CONFLICT },
+			  .minval = XFS_MIN_SECTORSIZE_LOG,
+			  .maxval = XFS_MAX_SECTORSIZE_LOG,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = D_SECTSIZE,
+			  .conflicts = { D_SECTLOG,
+					 LAST_CONFLICT },
+			  .convert = true,
+			  .is_power_2 = true,
+			  .minval = XFS_MIN_SECTORSIZE,
+			  .maxval = XFS_MAX_SECTORSIZE,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = D_NOALIGN,
+			  .conflicts = { D_SU,
+					 D_SW,
+					 D_SUNIT,
+					 D_SWIDTH,
+					 LAST_CONFLICT },
+			  .minval = 0,
+			  .maxval = 1,
+			  .flagval = 1,
+			},
+			{ .index = D_RTINHERIT,
+			  .conflicts = { LAST_CONFLICT },
+			  .minval = 0,
+			  .maxval = 1,
+			  .flagval = 1,
+			},
+			{ .index = D_PROJINHERIT,
+			  .conflicts = { LAST_CONFLICT },
+			  .minval = 0,
+			  .maxval = UINT_MAX,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = D_EXTSZINHERIT,
+			  .conflicts = { LAST_CONFLICT },
+			  .minval = 0,
+			  .maxval = UINT_MAX,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
 		},
 	},
-};
-
-
-struct opt_params iopts = {
-	.name = 'i',
-	.subopts = {
+#define OPT_I	2
+	{
+		.index = OPT_I,
+		.name = 'i',
+		.subopts = {
 #define	I_ALIGN		0
-		"align",
+			"align",
 #define	I_LOG		1
-		"log",
+			"log",
 #define	I_MAXPCT	2
-		"maxpct",
+			"maxpct",
 #define	I_PERBLOCK	3
-		"perblock",
+			"perblock",
 #define	I_SIZE		4
-		"size",
+			"size",
 #define	I_ATTR		5
-		"attr",
+			"attr",
 #define	I_PROJID32BIT	6
-		"projid32bit",
+			"projid32bit",
 #define I_SPINODES	7
-		"sparse",
-		NULL
-	},
-	.subopt_params = {
-		{ .index = I_ALIGN,
-		  .conflicts = { LAST_CONFLICT },
-		  .minval = 0,
-		  .maxval = 1,
-		  .flagval = 1,
-		},
-		{ .index = I_LOG,
-		  .conflicts = { I_PERBLOCK,
-				 I_SIZE,
-				 LAST_CONFLICT },
-		  .minval = XFS_DINODE_MIN_LOG,
-		  .maxval = XFS_DINODE_MAX_LOG,
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = I_MAXPCT,
-		  .conflicts = { LAST_CONFLICT },
-		  .minval = 0,
-		  .maxval = 100,
-		  .flagval = SUBOPT_NEEDS_VAL,
+			"sparse",
+			NULL
 		},
-		{ .index = I_PERBLOCK,
-		  .conflicts = { I_LOG,
-				 I_SIZE,
-				 LAST_CONFLICT },
-		  .is_power_2 = true,
-		  .minval = XFS_MIN_INODE_PERBLOCK,
-		  .maxval = XFS_MAX_BLOCKSIZE / XFS_DINODE_MIN_SIZE,
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = I_SIZE,
-		  .conflicts = { I_PERBLOCK,
-				 I_LOG,
-				 LAST_CONFLICT },
-		  .is_power_2 = true,
-		  .minval = XFS_DINODE_MIN_SIZE,
-		  .maxval = XFS_DINODE_MAX_SIZE,
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = I_ATTR,
-		  .conflicts = { LAST_CONFLICT },
-		  .minval = 0,
-		  .maxval = 2,
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = I_PROJID32BIT,
-		  .conflicts = { LAST_CONFLICT },
-		  .minval = 0,
-		  .maxval = 1,
-		  .flagval = 1,
-		},
-		{ .index = I_SPINODES,
-		  .conflicts = { LAST_CONFLICT },
-		  .minval = 0,
-		  .maxval = 1,
-		  .flagval = 1,
+		.subopt_params = {
+			{ .index = I_ALIGN,
+			  .conflicts = { LAST_CONFLICT },
+			  .minval = 0,
+			  .maxval = 1,
+			  .flagval = 1,
+			},
+			{ .index = I_LOG,
+			  .conflicts = { I_PERBLOCK,
+					 I_SIZE,
+					 LAST_CONFLICT },
+			  .minval = XFS_DINODE_MIN_LOG,
+			  .maxval = XFS_DINODE_MAX_LOG,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = I_MAXPCT,
+			  .conflicts = { LAST_CONFLICT },
+			  .minval = 0,
+			  .maxval = 100,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = I_PERBLOCK,
+			  .conflicts = { I_LOG,
+					 I_SIZE,
+					 LAST_CONFLICT },
+			  .is_power_2 = true,
+			  .minval = XFS_MIN_INODE_PERBLOCK,
+			  .maxval = XFS_MAX_BLOCKSIZE / XFS_DINODE_MIN_SIZE,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = I_SIZE,
+			  .conflicts = { I_PERBLOCK,
+					 I_LOG,
+					 LAST_CONFLICT },
+			  .is_power_2 = true,
+			  .minval = XFS_DINODE_MIN_SIZE,
+			  .maxval = XFS_DINODE_MAX_SIZE,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = I_ATTR,
+			  .conflicts = { LAST_CONFLICT },
+			  .minval = 0,
+			  .maxval = 2,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = I_PROJID32BIT,
+			  .conflicts = { LAST_CONFLICT },
+			  .minval = 0,
+			  .maxval = 1,
+			  .flagval = 1,
+			},
+			{ .index = I_SPINODES,
+			  .conflicts = { LAST_CONFLICT },
+			  .minval = 0,
+			  .maxval = 1,
+			  .flagval = 1,
+			},
 		},
 	},
-};
-
-struct opt_params lopts = {
-	.name = 'l',
-	.subopts = {
-#define	L_AGNUM		0
-		"agnum",
-#define	L_INTERNAL	1
-		"internal",
-#define	L_SIZE		2
-		"size",
-#define L_VERSION	3
-		"version",
-#define L_SUNIT		4
-		"sunit",
-#define L_SU		5
-		"su",
-#define L_DEV		6
-		"logdev",
-#define	L_SECTLOG	7
-		"sectlog",
-#define	L_SECTSIZE	8
-		"sectsize",
-#define	L_FILE		9
-		"file",
-#define	L_NAME		10
-		"name",
-#define	L_LAZYSBCNTR	11
-		"lazy-count",
-		NULL
-	},
-	.subopt_params = {
-		{ .index = L_AGNUM,
-		  .conflicts = { L_DEV,
-				 LAST_CONFLICT },
-		  .minval = 0,
-		  .maxval = UINT_MAX,
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = L_INTERNAL,
-		  .conflicts = { L_FILE,
-				 L_DEV,
-				 LAST_CONFLICT },
-		  .minval = 0,
-		  .maxval = 1,
-		  .flagval = 1,
+#define OPT_L	3
+	{
+		.index = OPT_L,
+		.name = 'l',
+		.subopts = {
+	#define	L_AGNUM		0
+			"agnum",
+	#define	L_INTERNAL	1
+			"internal",
+	#define	L_SIZE		2
+			"size",
+	#define L_VERSION	3
+			"version",
+	#define L_SUNIT		4
+			"sunit",
+	#define L_SU		5
+			"su",
+	#define L_DEV		6
+			"logdev",
+	#define	L_SECTLOG	7
+			"sectlog",
+	#define	L_SECTSIZE	8
+			"sectsize",
+	#define	L_FILE		9
+			"file",
+	#define	L_NAME		10
+			"name",
+	#define	L_LAZYSBCNTR	11
+			"lazy-count",
+			NULL
 		},
-		{ .index = L_SIZE,
-		  .conflicts = { LAST_CONFLICT },
-		  .convert = true,
-		  .minval = 2 * 1024 * 1024LL,	/* XXX: XFS_MIN_LOG_BYTES */
-		  .maxval = XFS_MAX_LOG_BYTES,
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = L_VERSION,
-		  .conflicts = { LAST_CONFLICT },
-		  .minval = 1,
-		  .maxval = 2,
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = L_SUNIT,
-		  .conflicts = { L_SU,
-				 LAST_CONFLICT },
-		  .minval = 1,
-		  .maxval = BTOBB(XLOG_MAX_RECORD_BSIZE),
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = L_SU,
-		  .conflicts = { L_SUNIT,
-				 LAST_CONFLICT },
-		  .convert = true,
-		  .minval = BBTOB(1),
-		  .maxval = XLOG_MAX_RECORD_BSIZE,
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = L_DEV,
-		  .conflicts = { L_AGNUM,
-				 L_INTERNAL,
-				 LAST_CONFLICT },
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = L_SECTLOG,
-		  .conflicts = { L_SECTSIZE,
-				 LAST_CONFLICT },
-		  .minval = XFS_MIN_SECTORSIZE_LOG,
-		  .maxval = XFS_MAX_SECTORSIZE_LOG,
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = L_SECTSIZE,
-		  .conflicts = { L_SECTLOG,
-				 LAST_CONFLICT },
-		  .convert = true,
-		  .is_power_2 = true,
-		  .minval = XFS_MIN_SECTORSIZE,
-		  .maxval = XFS_MAX_SECTORSIZE,
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = L_FILE,
-		  .conflicts = { L_INTERNAL,
-				 LAST_CONFLICT },
-		  .minval = 0,
-		  .maxval = 1,
-		  .flagval = 1,
-		},
-		{ .index = L_NAME,
-		  .conflicts = { L_AGNUM,
-				 L_INTERNAL,
-				 LAST_CONFLICT },
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = L_LAZYSBCNTR,
-		  .conflicts = { LAST_CONFLICT },
-		  .minval = 0,
-		  .maxval = 1,
-		  .flagval = 1,
+		.subopt_params = {
+			{ .index = L_AGNUM,
+			  .conflicts = { L_DEV,
+					 LAST_CONFLICT },
+			  .minval = 0,
+			  .maxval = UINT_MAX,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = L_INTERNAL,
+			  .conflicts = { L_FILE,
+					 L_DEV,
+					 LAST_CONFLICT },
+			  .minval = 0,
+			  .maxval = 1,
+			  .flagval = 1,
+			},
+			{ .index = L_SIZE,
+			  .conflicts = { LAST_CONFLICT },
+			  .convert = true,
+			  .minval = 2 * 1024 * 1024LL,	/* XXX: XFS_MIN_LOG_BYTES */
+			  .maxval = XFS_MAX_LOG_BYTES,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = L_VERSION,
+			  .conflicts = { LAST_CONFLICT },
+			  .minval = 1,
+			  .maxval = 2,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = L_SUNIT,
+			  .conflicts = { L_SU,
+					 LAST_CONFLICT },
+			  .minval = 1,
+			  .maxval = BTOBB(XLOG_MAX_RECORD_BSIZE),
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = L_SU,
+			  .conflicts = { L_SUNIT,
+					 LAST_CONFLICT },
+			  .convert = true,
+			  .minval = BBTOB(1),
+			  .maxval = XLOG_MAX_RECORD_BSIZE,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = L_DEV,
+			  .conflicts = { L_AGNUM,
+					 L_INTERNAL,
+					 LAST_CONFLICT },
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = L_SECTLOG,
+			  .conflicts = { L_SECTSIZE,
+					 LAST_CONFLICT },
+			  .minval = XFS_MIN_SECTORSIZE_LOG,
+			  .maxval = XFS_MAX_SECTORSIZE_LOG,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = L_SECTSIZE,
+			  .conflicts = { L_SECTLOG,
+					 LAST_CONFLICT },
+			  .convert = true,
+			  .is_power_2 = true,
+			  .minval = XFS_MIN_SECTORSIZE,
+			  .maxval = XFS_MAX_SECTORSIZE,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = L_FILE,
+			  .conflicts = { L_INTERNAL,
+					 LAST_CONFLICT },
+			  .minval = 0,
+			  .maxval = 1,
+			  .flagval = 1,
+			},
+			{ .index = L_NAME,
+			  .conflicts = { L_AGNUM,
+					 L_INTERNAL,
+					 LAST_CONFLICT },
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = L_LAZYSBCNTR,
+			  .conflicts = { LAST_CONFLICT },
+			  .minval = 0,
+			  .maxval = 1,
+			  .flagval = 1,
+			},
 		},
 	},
-};
-
-struct opt_params nopts = {
-	.name = 'n',
-	.subopts = {
-#define	N_LOG		0
-		"log",
-#define	N_SIZE		1
-		"size",
-#define	N_VERSION	2
-		"version",
-#define	N_FTYPE		3
-		"ftype",
-	NULL,
-	},
-	.subopt_params = {
-		{ .index = N_LOG,
-		  .conflicts = { N_SIZE,
-				 LAST_CONFLICT },
-		  .minval = XFS_MIN_REC_DIRSIZE,
-		  .maxval = XFS_MAX_BLOCKSIZE_LOG,
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = N_SIZE,
-		  .conflicts = { N_LOG,
-				 LAST_CONFLICT },
-		  .convert = true,
-		  .is_power_2 = true,
-		  .minval = 1 << XFS_MIN_REC_DIRSIZE,
-		  .maxval = XFS_MAX_BLOCKSIZE,
-		  .flagval = SUBOPT_NEEDS_VAL,
+#define OPT_N	4
+	{
+		.index = OPT_N,
+		.name = 'n',
+		.subopts = {
+	#define	N_LOG		0
+			"log",
+	#define	N_SIZE		1
+			"size",
+	#define	N_VERSION	2
+			"version",
+	#define	N_FTYPE		3
+			"ftype",
+		NULL,
 		},
-		{ .index = N_VERSION,
-		  .conflicts = { LAST_CONFLICT },
-		  .minval = 2,
-		  .maxval = 2,
-		  .flagval = SUBOPT_NEEDS_VAL,
+		.subopt_params = {
+			{ .index = N_LOG,
+			  .conflicts = { N_SIZE,
+					 LAST_CONFLICT },
+			  .minval = XFS_MIN_REC_DIRSIZE,
+			  .maxval = XFS_MAX_BLOCKSIZE_LOG,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = N_SIZE,
+			  .conflicts = { N_LOG,
+					 LAST_CONFLICT },
+			  .convert = true,
+			  .is_power_2 = true,
+			  .minval = 1 << XFS_MIN_REC_DIRSIZE,
+			  .maxval = XFS_MAX_BLOCKSIZE,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = N_VERSION,
+			  .conflicts = { LAST_CONFLICT },
+			  .minval = 2,
+			  .maxval = 2,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = N_FTYPE,
+			  .conflicts = { LAST_CONFLICT },
+			  .minval = 0,
+			  .maxval = 1,
+			  .flagval = 1,
+			},
 		},
-		{ .index = N_FTYPE,
-		  .conflicts = { LAST_CONFLICT },
-		  .minval = 0,
-		  .maxval = 1,
-		  .flagval = 1,
-		},
-	},
-};
-
-struct opt_params ropts = {
-	.name = 'r',
-	.subopts = {
-#define	R_EXTSIZE	0
-		"extsize",
-#define	R_SIZE		1
-		"size",
-#define	R_DEV		2
-		"rtdev",
-#define	R_FILE		3
-		"file",
-#define	R_NAME		4
-		"name",
-#define R_NOALIGN	5
-		"noalign",
-		NULL
 	},
-	.subopt_params = {
-		{ .index = R_EXTSIZE,
-		  .conflicts = { LAST_CONFLICT },
-		  .convert = true,
-		  .minval = XFS_MIN_RTEXTSIZE,
-		  .maxval = XFS_MAX_RTEXTSIZE,
-		  .flagval = SUBOPT_NEEDS_VAL,
+#define OPT_R	5
+	{
+		.index = OPT_R,
+		.name = 'r',
+		.subopts = {
+	#define	R_EXTSIZE	0
+			"extsize",
+	#define	R_SIZE		1
+			"size",
+	#define	R_DEV		2
+			"rtdev",
+	#define	R_FILE		3
+			"file",
+	#define	R_NAME		4
+			"name",
+	#define R_NOALIGN	5
+			"noalign",
+			NULL
 		},
-		{ .index = R_SIZE,
-		  .conflicts = { LAST_CONFLICT },
-		  .convert = true,
-		  .minval = 0,
-		  .maxval = LLONG_MAX,
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = R_DEV,
-		  .conflicts = { LAST_CONFLICT },
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = R_FILE,
-		  .minval = 0,
-		  .maxval = 1,
-		  .flagval = 1,
-		  .conflicts = { LAST_CONFLICT },
-		},
-		{ .index = R_NAME,
-		  .conflicts = { LAST_CONFLICT },
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = R_NOALIGN,
-		  .minval = 0,
-		  .maxval = 1,
-		  .flagval = 1,
-		  .conflicts = { LAST_CONFLICT },
+		.subopt_params = {
+			{ .index = R_EXTSIZE,
+			  .conflicts = { LAST_CONFLICT },
+			  .convert = true,
+			  .minval = XFS_MIN_RTEXTSIZE,
+			  .maxval = XFS_MAX_RTEXTSIZE,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = R_SIZE,
+			  .conflicts = { LAST_CONFLICT },
+			  .convert = true,
+			  .minval = 0,
+			  .maxval = LLONG_MAX,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = R_DEV,
+			  .conflicts = { LAST_CONFLICT },
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = R_FILE,
+			  .minval = 0,
+			  .maxval = 1,
+			  .flagval = 1,
+			  .conflicts = { LAST_CONFLICT },
+			},
+			{ .index = R_NAME,
+			  .conflicts = { LAST_CONFLICT },
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = R_NOALIGN,
+			  .minval = 0,
+			  .maxval = 1,
+			  .flagval = 1,
+			  .conflicts = { LAST_CONFLICT },
+			},
 		},
 	},
-};
-
-struct opt_params sopts = {
-	.name = 's',
-	.subopts = {
-#define	S_LOG		0
-		"log",
-#define	S_SECTLOG	1
-		"sectlog",
-#define	S_SIZE		2
-		"size",
-#define	S_SECTSIZE	3
-		"sectsize",
-		NULL
-	},
-	.subopt_params = {
-		{ .index = S_LOG,
-		  .conflicts = { S_SIZE,
-				 S_SECTSIZE,
-				 LAST_CONFLICT },
-		  .minval = XFS_MIN_SECTORSIZE_LOG,
-		  .maxval = XFS_MAX_SECTORSIZE_LOG,
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = S_SECTLOG,
-		  .conflicts = { S_SIZE,
-				 S_SECTSIZE,
-				 LAST_CONFLICT },
-		  .minval = XFS_MIN_SECTORSIZE_LOG,
-		  .maxval = XFS_MAX_SECTORSIZE_LOG,
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = S_SIZE,
-		  .conflicts = { S_LOG,
-				 S_SECTLOG,
-				 LAST_CONFLICT },
-		  .convert = true,
-		  .is_power_2 = true,
-		  .minval = XFS_MIN_SECTORSIZE,
-		  .maxval = XFS_MAX_SECTORSIZE,
-		  .flagval = SUBOPT_NEEDS_VAL,
+#define OPT_S	6
+	{
+		.index = OPT_S,
+		.name = 's',
+		.subopts = {
+	#define	S_LOG		0
+			"log",
+	#define	S_SECTLOG	1
+			"sectlog",
+	#define	S_SIZE		2
+			"size",
+	#define	S_SECTSIZE	3
+			"sectsize",
+			NULL
 		},
-		{ .index = S_SECTSIZE,
-		  .conflicts = { S_LOG,
-				 S_SECTLOG,
-				 LAST_CONFLICT },
-		  .convert = true,
-		  .is_power_2 = true,
-		  .minval = XFS_MIN_SECTORSIZE,
-		  .maxval = XFS_MAX_SECTORSIZE,
-		  .flagval = SUBOPT_NEEDS_VAL,
+		.subopt_params = {
+			{ .index = S_LOG,
+			  .conflicts = { S_SIZE,
+					 S_SECTSIZE,
+					 LAST_CONFLICT },
+			  .minval = XFS_MIN_SECTORSIZE_LOG,
+			  .maxval = XFS_MAX_SECTORSIZE_LOG,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = S_SECTLOG,
+			  .conflicts = { S_SIZE,
+					 S_SECTSIZE,
+					 LAST_CONFLICT },
+			  .minval = XFS_MIN_SECTORSIZE_LOG,
+			  .maxval = XFS_MAX_SECTORSIZE_LOG,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = S_SIZE,
+			  .conflicts = { S_LOG,
+					 S_SECTLOG,
+					 LAST_CONFLICT },
+			  .convert = true,
+			  .is_power_2 = true,
+			  .minval = XFS_MIN_SECTORSIZE,
+			  .maxval = XFS_MAX_SECTORSIZE,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = S_SECTSIZE,
+			  .conflicts = { S_LOG,
+					 S_SECTLOG,
+					 LAST_CONFLICT },
+			  .convert = true,
+			  .is_power_2 = true,
+			  .minval = XFS_MIN_SECTORSIZE,
+			  .maxval = XFS_MAX_SECTORSIZE,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
 		},
 	},
-};
-
-struct opt_params mopts = {
-	.name = 'm',
-	.subopts = {
-#define	M_CRC		0
-		"crc",
-#define M_FINOBT	1
-		"finobt",
-#define M_UUID		2
-		"uuid",
-#define M_RMAPBT	3
-		"rmapbt",
-#define M_REFLINK	4
-		"reflink",
-		NULL
-	},
-	.subopt_params = {
-		{ .index = M_CRC,
-		  .conflicts = { LAST_CONFLICT },
-		  .minval = 0,
-		  .maxval = 1,
-		  .flagval = 1,
-		},
-		{ .index = M_FINOBT,
-		  .conflicts = { LAST_CONFLICT },
-		  .minval = 0,
-		  .maxval = 1,
-		  .flagval = 1,
+#define OPT_M	7
+	{
+		.index = OPT_M,
+		.name = 'm',
+		.subopts = {
+	#define	M_CRC		0
+			"crc",
+	#define M_FINOBT	1
+			"finobt",
+	#define M_UUID		2
+			"uuid",
+	#define M_RMAPBT	3
+			"rmapbt",
+	#define M_REFLINK	4
+			"reflink",
+			NULL
 		},
-		{ .index = M_UUID,
-		  .conflicts = { LAST_CONFLICT },
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = M_RMAPBT,
-		  .conflicts = { LAST_CONFLICT },
-		  .minval = 0,
-		  .maxval = 1,
-		  .flagval = 1,
-		},
-		{ .index = M_REFLINK,
-		  .conflicts = { LAST_CONFLICT },
-		  .minval = 0,
-		  .maxval = 1,
-		  .flagval = 1,
+		.subopt_params = {
+			{ .index = M_CRC,
+			  .conflicts = { LAST_CONFLICT },
+			  .minval = 0,
+			  .maxval = 1,
+			  .flagval = 1,
+			},
+			{ .index = M_FINOBT,
+			  .conflicts = { LAST_CONFLICT },
+			  .minval = 0,
+			  .maxval = 1,
+			  .flagval = 1,
+			},
+			{ .index = M_UUID,
+			  .conflicts = { LAST_CONFLICT },
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = M_RMAPBT,
+			.conflicts = { LAST_CONFLICT },
+			.minval = 0,
+			.maxval = 1,
+			.flagval = 1,
+			},
+			{ .index = M_REFLINK,
+			  .conflicts = { LAST_CONFLICT },
+			  .minval = 0,
+			  .maxval = 1,
+			  .flagval = 1,
+			},
 		},
 	},
 };
@@ -740,21 +754,22 @@ struct opt_params mopts = {
  * the string to be saved.
  */
 static int
-set_conf_raw(struct opt_params *opt, const int subopt, const char *value)
+set_conf_raw(const int opt, const int subopt, const char *value)
 {
-	if (subopt < 0 || subopt >= MAX_SUBOPTS) {
+	if (subopt < 0 || subopt >= MAX_SUBOPTS ||
+	    opt < 0 || opt >= MAX_OPTS) {
 		fprintf(stderr,
-		"This is a bug: set_conf_raw called with invalid opt/subopt: %c/%d\n",
-		opt->name, subopt);
+		"This is a bug: set_conf_raw called with invalid opt/subopt: %d/%d\n",
+		opt, subopt);
 		return -EINVAL;
 	}
 	if (value == NULL) {
-		if (opt->subopt_params[subopt].raw_input != NULL)
-			free(opt->subopt_params[subopt].raw_input);
-		opt->subopt_params[subopt].raw_input = NULL;
+		if (opts[opt].subopt_params[subopt].raw_input != NULL)
+			free(opts[opt].subopt_params[subopt].raw_input);
+		opts[opt].subopt_params[subopt].raw_input = NULL;
 	} else {
-		opt->subopt_params[subopt].raw_input = strdup(value);
-		if (opt->subopt_params[subopt].raw_input == NULL)
+		opts[opt].subopt_params[subopt].raw_input = strdup(value);
+		if (opts[opt].subopt_params[subopt].raw_input == NULL)
 			return -ENOMEM;
 	}
 	return 0;
@@ -765,19 +780,19 @@ set_conf_raw(struct opt_params *opt, const int subopt, const char *value)
  * the string to be saved into the out pointer.
  */
 static int
-get_conf_raw(const struct opt_params *opt, const int subopt, char **out)
+get_conf_raw(const int opt, const int subopt, char **out)
 {
-	if (subopt < 0 || subopt >= MAX_SUBOPTS) {
+	if (subopt < 0 || subopt >= MAX_SUBOPTS ||
+	    opt < 0 || opt >= MAX_OPTS) {
 		fprintf(stderr,
-		"This is a bug: get_conf_raw called with invalid opt/subopt: %c/%d\n",
-		opt->name, subopt);
+		"This is a bug: get_conf_raw called with invalid opt/subopt: %d/%d\n",
+		opt, subopt);
 		return -EINVAL;
 	}
-	*out = strdup(opt->subopt_params[subopt].raw_input);
+	*out = strdup(opts[opt].subopt_params[subopt].raw_input);
 	if (*out == NULL)
 		return -ENOMEM;
 	return 0;
-
 }
 
 /*
@@ -785,7 +800,7 @@ get_conf_raw(const struct opt_params *opt, const int subopt, char **out)
  * If any error occurs, return NULL.
  */
 static char *
-get_conf_raw_safe(const struct opt_params *opt, const int subopt)
+get_conf_raw_safe(const int opt, const int subopt)
 {
 	char *str;
 
@@ -1396,7 +1411,7 @@ getnum(
 	long long		c;
 
 	check_opt(opts, index, false);
-	set_conf_raw(opts, index, str);
+	set_conf_raw(opts->index, index, str);
 	/* empty strings might just return a default value */
 	if (!str || *str == '\0') {
 		if (sp->flagval == SUBOPT_NEEDS_VAL)
@@ -1611,17 +1626,19 @@ main(
 		case 'b':
 			p = optarg;
 			while (*p != '\0') {
-				char	**subopts = (char **)bopts.subopts;
+				char	**subopts =
+						(char **)opts[OPT_B].subopts;
 				char	*value;
 
 				switch (getsubopt(&p, subopts, &value)) {
 				case B_LOG:
-					blocklog = getnum(value, &bopts, B_LOG);
+					blocklog = getnum(value, &opts[OPT_B],
+								B_LOG);
 					blocksize = 1 << blocklog;
 					blflag = 1;
 					break;
 				case B_SIZE:
-					blocksize = getnum(value, &bopts,
+					blocksize = getnum(value, &opts[OPT_B],
 							   B_SIZE);
 					blocklog = libxfs_highbit32(blocksize);
 					bsflag = 1;
@@ -1634,78 +1651,86 @@ main(
 		case 'd':
 			p = optarg;
 			while (*p != '\0') {
-				char	**subopts = (char **)dopts.subopts;
+				char	**subopts =
+						(char **)opts[OPT_D].subopts;
 				char	*value;
 
 				switch (getsubopt(&p, subopts, &value)) {
 				case D_AGCOUNT:
-					agcount = getnum(value, &dopts,
+					agcount = getnum(value, &opts[OPT_D],
 							 D_AGCOUNT);
 					daflag = 1;
 					break;
 				case D_AGSIZE:
-					agsize = getnum(value, &dopts, D_AGSIZE);
+					agsize = getnum(value, &opts[OPT_D],
+								D_AGSIZE);
 					dasize = 1;
 					break;
 				case D_FILE:
-					xi.disfile = getnum(value, &dopts,
-							    D_FILE);
+					xi.disfile = getnum(value,
+						&opts[OPT_D], D_FILE);
 					break;
 				case D_NAME:
-					xi.dname = getstr(value, &dopts, D_NAME);
+					xi.dname = getstr(value, &opts[OPT_D],
+								D_NAME);
 					break;
 				case D_SIZE:
-					dbytes = getnum(value, &dopts, D_SIZE);
+					dbytes = getnum(value, &opts[OPT_D],
+								D_SIZE);
 					break;
 				case D_SUNIT:
-					dsunit = getnum(value, &dopts, D_SUNIT);
+					dsunit = getnum(value, &opts[OPT_D],
+								D_SUNIT);
 					dsflag = 1;
 					break;
 				case D_SWIDTH:
-					dswidth = getnum(value, &dopts,
+					dswidth = getnum(value, &opts[OPT_D],
 							 D_SWIDTH);
 					dsflag = 1;
 					break;
 				case D_SU:
-					dsu = getnum(value, &dopts, D_SU);
+					dsu = getnum(value, &opts[OPT_D],
+								D_SU);
 					dsflag = 1;
 					break;
 				case D_SW:
-					dsw = getnum(value, &dopts, D_SW);
+					dsw = getnum(value, &opts[OPT_D],
+								D_SW);
 					dsflag = 1;
 					break;
 				case D_NOALIGN:
-					nodsflag = getnum(value, &dopts,
+					nodsflag = getnum(value, &opts[OPT_D],
 								D_NOALIGN);
 					break;
 				case D_SECTLOG:
-					sectorlog = getnum(value, &dopts,
+					sectorlog = getnum(value, &opts[OPT_D],
 							   D_SECTLOG);
 					sectorsize = 1 << sectorlog;
 					slflag = 1;
 					break;
 				case D_SECTSIZE:
-					sectorsize = getnum(value, &dopts,
-							    D_SECTSIZE);
+					sectorsize = getnum(value,
+						&opts[OPT_D], D_SECTSIZE);
 					sectorlog =
 						libxfs_highbit32(sectorsize);
 					ssflag = 1;
 					break;
 				case D_RTINHERIT:
-					c = getnum(value, &dopts, D_RTINHERIT);
+					c = getnum(value, &opts[OPT_D],
+								D_RTINHERIT);
 					if (c)
 						fsx.fsx_xflags |=
 							XFS_DIFLAG_RTINHERIT;
 					break;
 				case D_PROJINHERIT:
-					fsx.fsx_projid = getnum(value, &dopts,
-								D_PROJINHERIT);
+					fsx.fsx_projid = getnum(value,
+						&opts[OPT_D], D_PROJINHERIT);
 					fsx.fsx_xflags |=
 						XFS_DIFLAG_PROJINHERIT;
 					break;
 				case D_EXTSZINHERIT:
-					fsx.fsx_extsize = getnum(value, &dopts,
-								 D_EXTSZINHERIT);
+					fsx.fsx_extsize = getnum(value,
+						&opts[OPT_D], D_EXTSZINHERIT);
 					fsx.fsx_xflags |=
 						XFS_DIFLAG_EXTSZINHERIT;
 					break;
@@ -1717,46 +1742,51 @@ main(
 		case 'i':
 			p = optarg;
 			while (*p != '\0') {
-				char	**subopts = (char **)iopts.subopts;
+				char	**subopts =
+						(char **)opts[OPT_I].subopts;
 				char	*value;
 
 				switch (getsubopt(&p, subopts, &value)) {
 				case I_ALIGN:
 					sb_feat.inode_align = getnum(value,
-								&iopts, I_ALIGN);
+						&opts[OPT_I], I_ALIGN);
 					break;
 				case I_LOG:
-					inodelog = getnum(value, &iopts, I_LOG);
+					inodelog = getnum(value, &opts[OPT_I],
+								I_LOG);
 					isize = 1 << inodelog;
 					ilflag = 1;
 					break;
 				case I_MAXPCT:
-					imaxpct = getnum(value, &iopts,
+					imaxpct = getnum(value, &opts[OPT_I],
 							 I_MAXPCT);
 					imflag = 1;
 					break;
 				case I_PERBLOCK:
-					inopblock = getnum(value, &iopts,
+					inopblock = getnum(value, &opts[OPT_I],
 							   I_PERBLOCK);
 					ipflag = 1;
 					break;
 				case I_SIZE:
-					isize = getnum(value, &iopts, I_SIZE);
+					isize = getnum(value, &opts[OPT_I],
+								I_SIZE);
 					inodelog = libxfs_highbit32(isize);
 					isflag = 1;
 					break;
 				case I_ATTR:
 					sb_feat.attr_version =
-						getnum(value, &iopts, I_ATTR);
+						getnum(value, &opts[OPT_I],
+								I_ATTR);
 					break;
 				case I_PROJID32BIT:
 					sb_feat.projid16bit =
-						!getnum(value, &iopts,
+						!getnum(value, &opts[OPT_I],
 							I_PROJID32BIT);
 					break;
 				case I_SPINODES:
 					sb_feat.spinodes = getnum(value,
-							&iopts, I_SPINODES);
+								&opts[OPT_I],
+								I_SPINODES);
 					break;
 				default:
 					unknown('i', value);
@@ -1766,63 +1796,70 @@ main(
 		case 'l':
 			p = optarg;
 			while (*p != '\0') {
-				char	**subopts = (char **)lopts.subopts;
+				char	**subopts =
+						(char **)opts[OPT_L].subopts;
 				char	*value;
 
 				switch (getsubopt(&p, subopts, &value)) {
 				case L_AGNUM:
-					logagno = getnum(value, &lopts, L_AGNUM);
+					logagno = getnum(value, &opts[OPT_L],
+								L_AGNUM);
 					laflag = 1;
 					break;
 				case L_FILE:
-					xi.lisfile = getnum(value, &lopts,
-							    L_FILE);
+					xi.lisfile = getnum(value,
+						&opts[OPT_L], L_FILE);
 					break;
 				case L_INTERNAL:
-					loginternal = getnum(value, &lopts,
-							     L_INTERNAL);
+					loginternal = getnum(value,
+						&opts[OPT_L], L_INTERNAL);
 					liflag = 1;
 					break;
 				case L_SU:
-					lsu = getnum(value, &lopts, L_SU);
+					lsu = getnum(value, &opts[OPT_L],
+								L_SU);
 					lsuflag = 1;
 					break;
 				case L_SUNIT:
-					lsunit = getnum(value, &lopts, L_SUNIT);
+					lsunit = getnum(value, &opts[OPT_L],
+								L_SUNIT);
 					lsunitflag = 1;
 					break;
 				case L_NAME:
 				case L_DEV:
-					logfile = getstr(value, &lopts, L_NAME);
+					logfile = getstr(value, &opts[OPT_L],
+								L_NAME);
 					xi.logname = logfile;
 					ldflag = 1;
 					loginternal = 0;
 					break;
 				case L_VERSION:
 					sb_feat.log_version =
-						getnum(value, &lopts, L_VERSION);
+						getnum(value, &opts[OPT_L],
+								L_VERSION);
 					lvflag = 1;
 					break;
 				case L_SIZE:
-					logbytes = getnum(value, &lopts, L_SIZE);
+					logbytes = getnum(value,
+						&opts[OPT_L], L_SIZE);
 					break;
 				case L_SECTLOG:
-					lsectorlog = getnum(value, &lopts,
-							    L_SECTLOG);
+					lsectorlog = getnum(value,
+						&opts[OPT_L], L_SECTLOG);
 					lsectorsize = 1 << lsectorlog;
 					lslflag = 1;
 					break;
 				case L_SECTSIZE:
-					lsectorsize = getnum(value, &lopts,
-							     L_SECTSIZE);
+					lsectorsize = getnum(value,
+						&opts[OPT_L], L_SECTSIZE);
 					lsectorlog =
 						libxfs_highbit32(lsectorsize);
 					lssflag = 1;
 					break;
 				case L_LAZYSBCNTR:
 					sb_feat.lazy_sb_counters =
-							getnum(value, &lopts,
-							       L_LAZYSBCNTR);
+						getnum(value, &opts[OPT_L],
+							L_LAZYSBCNTR);
 					break;
 				default:
 					unknown('l', value);
@@ -1837,19 +1874,21 @@ main(
 		case 'm':
 			p = optarg;
 			while (*p != '\0') {
-				char	**subopts = (char **)mopts.subopts;
+				char	**subopts =
+						(char **)opts[OPT_M].subopts;
 				char	*value;
 
 				switch (getsubopt(&p, subopts, &value)) {
 				case M_CRC:
 					sb_feat.crcs_enabled =
-						getnum(value, &mopts, M_CRC);
+						getnum(value, &opts[OPT_M],
+								M_CRC);
 					if (sb_feat.crcs_enabled)
 						sb_feat.dirftype = true;
 					break;
 				case M_FINOBT:
 					sb_feat.finobt = getnum(
-						value, &mopts, M_FINOBT);
+						value, &opts[OPT_M], M_FINOBT);
 					break;
 				case M_UUID:
 					if (!value || *value == '\0')
@@ -1859,11 +1898,12 @@ main(
 					break;
 				case M_RMAPBT:
 					sb_feat.rmapbt = getnum(
-						value, &mopts, M_RMAPBT);
+						value, &opts[OPT_M], M_RMAPBT);
 					break;
 				case M_REFLINK:
-					sb_feat.reflink = getnum(
-						value, &mopts, M_REFLINK);
+					sb_feat.reflink =
+						getnum(value, &opts[OPT_M],
+							M_REFLINK);
 					break;
 				default:
 					unknown('m', value);
@@ -1873,38 +1913,41 @@ main(
 		case 'n':
 			p = optarg;
 			while (*p != '\0') {
-				char	**subopts = (char **)nopts.subopts;
+				char	**subopts =
+						(char **)opts[OPT_N].subopts;
 				char	*value;
 
 				switch (getsubopt(&p, subopts, &value)) {
 				case N_LOG:
-					dirblocklog = getnum(value, &nopts,
-							     N_LOG);
+					dirblocklog = getnum(value,
+						&opts[OPT_N], N_LOG);
 					dirblocksize = 1 << dirblocklog;
 					nlflag = 1;
 					break;
 				case N_SIZE:
-					dirblocksize = getnum(value, &nopts,
-							      N_SIZE);
+					dirblocksize = getnum(value,
+						&opts[OPT_N], N_SIZE);
 					dirblocklog =
 						libxfs_highbit32(dirblocksize);
 					nsflag = 1;
 					break;
 				case N_VERSION:
-					value = getstr(value, &nopts, N_VERSION);
+					value = getstr(value, &opts[OPT_N],
+								N_VERSION);
 					if (!strcasecmp(value, "ci")) {
 						/* ASCII CI mode */
 						sb_feat.nci = true;
 					} else {
 						sb_feat.dir_version =
-							getnum(value, &nopts,
+							getnum(value,
+							       &opts[OPT_N],
 							       N_VERSION);
 					}
 					nvflag = 1;
 					break;
 				case N_FTYPE:
-					sb_feat.dirftype = getnum(value, &nopts,
-								  N_FTYPE);
+					sb_feat.dirftype = getnum(value,
+						&opts[OPT_N], N_FTYPE);
 					break;
 				default:
 					unknown('n', value);
@@ -1928,27 +1971,30 @@ main(
 		case 'r':
 			p = optarg;
 			while (*p != '\0') {
-				char	**subopts = (char **)ropts.subopts;
+				char	**subopts =
+						(char **)opts[OPT_R].subopts;
 				char	*value;
 
 				switch (getsubopt(&p, subopts, &value)) {
 				case R_EXTSIZE:
-					rtextbytes = getnum(value, &ropts, R_EXTSIZE);
+					rtextbytes = getnum(value,
+						&opts[OPT_R], R_EXTSIZE);
 					break;
 				case R_FILE:
-					xi.risfile = getnum(value, &ropts,
-							    R_FILE);
+					xi.risfile = getnum(value,
+						&opts[OPT_R], R_FILE);
 					break;
 				case R_NAME:
 				case R_DEV:
-					xi.rtname = getstr(value, &ropts,
+					xi.rtname = getstr(value, &opts[OPT_R],
 							   R_NAME);
 					break;
 				case R_SIZE:
-					rtbytes = getnum(value, &ropts, R_SIZE);
+					rtbytes = getnum(value, &opts[OPT_R],
+								R_SIZE);
 					break;
 				case R_NOALIGN:
-					norsflag = getnum(value, &ropts,
+					norsflag = getnum(value, &opts[OPT_R],
 								R_NOALIGN);
 					break;
 				default:
@@ -1959,7 +2005,8 @@ main(
 		case 's':
 			p = optarg;
 			while (*p != '\0') {
-				char	**subopts = (char **)sopts.subopts;
+				char	**subopts =
+						(char **)opts[OPT_S].subopts;
 				char	*value;
 
 				switch (getsubopt(&p, subopts, &value)) {
@@ -1967,8 +2014,9 @@ main(
 				case S_SECTLOG:
 					if (lssflag)
 						conflict('s', subopts,
-							 S_SECTSIZE, S_SECTLOG);
-					sectorlog = getnum(value, &sopts,
+							 S_SECTSIZE,
+							 S_SECTLOG);
+					sectorlog = getnum(value, &opts[OPT_S],
 							   S_SECTLOG);
 					lsectorlog = sectorlog;
 					sectorsize = 1 << sectorlog;
@@ -1978,10 +2026,11 @@ main(
 				case S_SIZE:
 				case S_SECTSIZE:
 					if (lslflag)
-						conflict('s', subopts, S_SECTLOG,
+						conflict('s', subopts,
+							 S_SECTLOG,
 							 S_SECTSIZE);
-					sectorsize = getnum(value, &sopts,
-							    S_SECTSIZE);
+					sectorsize = getnum(value,
+						&opts[OPT_S], S_SECTSIZE);
 					lsectorsize = sectorsize;
 					sectorlog =
 						libxfs_highbit32(sectorsize);
@@ -2004,7 +2053,8 @@ main(
 		fprintf(stderr, _("extra arguments\n"));
 		usage();
 	} else if (argc - optind == 1) {
-		dfile = xi.volname = getstr(argv[optind], &dopts, D_NAME);
+		dfile = xi.volname = getstr(argv[optind],
+					&opts[OPT_D], D_NAME);
 	} else
 		dfile = xi.dname;
 
@@ -2183,7 +2233,8 @@ _("32 bit Project IDs always enabled on CRC enabled filesytems\n"));
 		 * then issue an error.
 		 * The same is also for sparse inodes.
 		 */
-		if (sb_feat.finobt && mopts.subopt_params[M_FINOBT].seen) {
+		if (sb_feat.finobt &&
+		    opts[OPT_M].subopt_params[M_FINOBT].seen) {
 			fprintf(stderr,
 _("finobt not supported without CRC support\n"));
 			usage();
@@ -2432,7 +2483,7 @@ _("rmapbt not supported with realtime devices\n"));
 		fprintf(stderr,
 			_("size %s specified for data subvolume is too large, "
 			"maximum is %lld blocks\n"),
-			get_conf_raw_safe(&dopts, D_SIZE),
+			get_conf_raw_safe(OPT_D, D_SIZE),
 			(long long)DTOBT(xi.dsize));
 		usage();
 	} else if (!dbytes && xi.dsize > 0)
@@ -2481,7 +2532,7 @@ reported by the device (%u).\n"),
 		fprintf(stderr,
 			_("size %s specified for rt subvolume is too large, "
 			"maximum is %lld blocks\n"),
-			get_conf_raw_safe(&ropts, R_SIZE),
+			get_conf_raw_safe(OPT_R, R_SIZE),
 			(long long)DTOBT(xi.rtsize));
 		usage();
 	} else if (!rtbytes && xi.rtsize > 0)
@@ -2697,7 +2748,7 @@ an AG size that is one stripe unit smaller, for example %llu.\n"),
 	if (logbytes && xi.logBBsize > 0 && logblocks > DTOBT(xi.logBBsize)) {
 		fprintf(stderr,
 _("size %s specified for log subvolume is too large, maximum is %lld blocks\n"),
-			get_conf_raw_safe(&lopts, L_SIZE),
+			get_conf_raw_safe(OPT_L, L_SIZE),
 			(long long)DTOBT(xi.logBBsize));
 		usage();
 	} else if (!logbytes && xi.logBBsize > 0) {
-- 
2.13.3


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

* [PATCH 5/6] mkfs: move getnum within the file
  2017-08-11 12:30 [PATCH 0/6 v2] mkfs: save user input into opts table Jan Tulak
                   ` (3 preceding siblings ...)
  2017-08-11 12:30 ` [PATCH 4/6] mkfs: merge tables for opts parsing into one table Jan Tulak
@ 2017-08-11 12:30 ` Jan Tulak
  2017-08-14 23:07   ` Darrick J. Wong
  2017-08-11 12:30 ` [PATCH 6/6] mkfs: extend opt_params with a value field Jan Tulak
  2017-08-15 15:08 ` [PATCH 1/6 v2] mkfs: Save raw user input field to the opts struct Jan Tulak
  6 siblings, 1 reply; 37+ messages in thread
From: Jan Tulak @ 2017-08-11 12:30 UTC (permalink / raw)
  To: linux-xfs; +Cc: Jan Tulak

Move getnum, check_opt and illegal_option within the file. We have to do
this to avoid dependency issues with the following patch. There is no
other change in this patch, just cut&paste of these functions.

Signed-off-by: Jan Tulak <jtulak@redhat.com>
---
 mkfs/xfs_mkfs.c | 236 ++++++++++++++++++++++++++++----------------------------
 1 file changed, 118 insertions(+), 118 deletions(-)

diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
index e3f7d345..3e7ba5f0 100644
--- a/mkfs/xfs_mkfs.c
+++ b/mkfs/xfs_mkfs.c
@@ -813,6 +813,124 @@ get_conf_raw_safe(const int opt, const int subopt)
 	return str;
 }
 
+static __attribute__((noreturn)) void
+illegal_option(
+	const char		*value,
+	struct opt_params	*opts,
+	int			index,
+	const char		*reason)
+{
+	fprintf(stderr,
+		_("Illegal value %s for -%c %s option. %s\n"),
+		value, opts->name, opts->subopts[index],
+		reason ? reason : "");
+	usage();
+}
+
+/*
+ * Check for conflicts and option respecification.
+ */
+static void
+check_opt(
+	struct opt_params	*opts,
+	int			index,
+	bool			str_seen)
+{
+	struct subopt_param	*sp = &opts->subopt_params[index];
+	int			i;
+
+	if (sp->index != index) {
+		fprintf(stderr,
+	("Developer screwed up option parsing (%d/%d)! Please report!\n"),
+			sp->index, index);
+		reqval(opts->name, (char **)opts->subopts, index);
+	}
+
+	/*
+	 * Check for respecification of the option. This is more complex than it
+	 * seems because some options are parsed twice - once as a string during
+	 * input parsing, then later the string is passed to getnum for
+	 * conversion into a number and bounds checking. Hence the two variables
+	 * used to track the different uses based on the @str parameter passed
+	 * to us.
+	 */
+	if (!str_seen) {
+		if (sp->seen)
+			respec(opts->name, (char **)opts->subopts, index);
+		sp->seen = true;
+	} else {
+		if (sp->str_seen)
+			respec(opts->name, (char **)opts->subopts, index);
+		sp->str_seen = true;
+	}
+
+	/* check for conflicts with the option */
+	for (i = 0; i < MAX_CONFLICTS; i++) {
+		int conflict_opt = sp->conflicts[i];
+
+		if (conflict_opt == LAST_CONFLICT)
+			break;
+		if (opts->subopt_params[conflict_opt].seen ||
+		    opts->subopt_params[conflict_opt].str_seen)
+			conflict(opts->name, (char **)opts->subopts,
+				 conflict_opt, index);
+	}
+}
+
+static long long
+getnum(
+	const char		*str,
+	struct opt_params	*opts,
+	int			index)
+{
+	struct subopt_param	*sp = &opts->subopt_params[index];
+	long long		c;
+
+	check_opt(opts, index, false);
+	set_conf_raw(opts->index, index, str);
+	/* empty strings might just return a default value */
+	if (!str || *str == '\0') {
+		if (sp->flagval == SUBOPT_NEEDS_VAL)
+			reqval(opts->name, (char **)opts->subopts, index);
+		return sp->flagval;
+	}
+
+	if (sp->minval == 0 && sp->maxval == 0) {
+		fprintf(stderr,
+			_("Option -%c %s has undefined minval/maxval."
+			  "Can't verify value range. This is a bug.\n"),
+			opts->name, opts->subopts[index]);
+		exit(1);
+	}
+
+	/*
+	 * Some values are pure numbers, others can have suffixes that define
+	 * the units of the number. Those get passed to cvtnum(), otherwise we
+	 * convert it ourselves to guarantee there is no trailing garbage in the
+	 * number.
+	 */
+	if (sp->convert)
+		c = cvtnum(blocksize, sectorsize, str);
+	else {
+		char		*str_end;
+
+		c = strtoll(str, &str_end, 0);
+		if (c == 0 && str_end == str)
+			illegal_option(str, opts, index, NULL);
+		if (*str_end != '\0')
+			illegal_option(str, opts, index, NULL);
+	}
+
+	/* Validity check the result. */
+	if (c < sp->minval)
+		illegal_option(str, opts, index, _("value is too small"));
+	else if (c > sp->maxval)
+		illegal_option(str, opts, index, _("value is too large"));
+	if (sp->is_power_2 && !ispow2(c))
+		illegal_option(str, opts, index, _("value must be a power of 2"));
+	return c;
+}
+
 /*
  * Convert lsu to lsunit for 512 bytes blocks and check validity of the values.
  */
@@ -1337,124 +1455,6 @@ sb_set_features(
 
 }
 
-static __attribute__((noreturn)) void
-illegal_option(
-	const char		*value,
-	struct opt_params	*opts,
-	int			index,
-	const char		*reason)
-{
-	fprintf(stderr,
-		_("Illegal value %s for -%c %s option. %s\n"),
-		value, opts->name, opts->subopts[index],
-		reason ? reason : "");
-	usage();
-}
-
-/*
- * Check for conflicts and option respecification.
- */
-static void
-check_opt(
-	struct opt_params	*opts,
-	int			index,
-	bool			str_seen)
-{
-	struct subopt_param	*sp = &opts->subopt_params[index];
-	int			i;
-
-	if (sp->index != index) {
-		fprintf(stderr,
-	("Developer screwed up option parsing (%d/%d)! Please report!\n"),
-			sp->index, index);
-		reqval(opts->name, (char **)opts->subopts, index);
-	}
-
-	/*
-	 * Check for respecification of the option. This is more complex than it
-	 * seems because some options are parsed twice - once as a string during
-	 * input parsing, then later the string is passed to getnum for
-	 * conversion into a number and bounds checking. Hence the two variables
-	 * used to track the different uses based on the @str parameter passed
-	 * to us.
-	 */
-	if (!str_seen) {
-		if (sp->seen)
-			respec(opts->name, (char **)opts->subopts, index);
-		sp->seen = true;
-	} else {
-		if (sp->str_seen)
-			respec(opts->name, (char **)opts->subopts, index);
-		sp->str_seen = true;
-	}
-
-	/* check for conflicts with the option */
-	for (i = 0; i < MAX_CONFLICTS; i++) {
-		int conflict_opt = sp->conflicts[i];
-
-		if (conflict_opt == LAST_CONFLICT)
-			break;
-		if (opts->subopt_params[conflict_opt].seen ||
-		    opts->subopt_params[conflict_opt].str_seen)
-			conflict(opts->name, (char **)opts->subopts,
-				 conflict_opt, index);
-	}
-}
-
-static long long
-getnum(
-	const char		*str,
-	struct opt_params	*opts,
-	int			index)
-{
-	struct subopt_param	*sp = &opts->subopt_params[index];
-	long long		c;
-
-	check_opt(opts, index, false);
-	set_conf_raw(opts->index, index, str);
-	/* empty strings might just return a default value */
-	if (!str || *str == '\0') {
-		if (sp->flagval == SUBOPT_NEEDS_VAL)
-			reqval(opts->name, (char **)opts->subopts, index);
-		return sp->flagval;
-	}
-
-	if (sp->minval == 0 && sp->maxval == 0) {
-		fprintf(stderr,
-			_("Option -%c %s has undefined minval/maxval."
-			  "Can't verify value range. This is a bug.\n"),
-			opts->name, opts->subopts[index]);
-		exit(1);
-	}
-
-	/*
-	 * Some values are pure numbers, others can have suffixes that define
-	 * the units of the number. Those get passed to cvtnum(), otherwise we
-	 * convert it ourselves to guarantee there is no trailing garbage in the
-	 * number.
-	 */
-	if (sp->convert)
-		c = cvtnum(blocksize, sectorsize, str);
-	else {
-		char		*str_end;
-
-		c = strtoll(str, &str_end, 0);
-		if (c == 0 && str_end == str)
-			illegal_option(str, opts, index, NULL);
-		if (*str_end != '\0')
-			illegal_option(str, opts, index, NULL);
-	}
-
-	/* Validity check the result. */
-	if (c < sp->minval)
-		illegal_option(str, opts, index, _("value is too small"));
-	else if (c > sp->maxval)
-		illegal_option(str, opts, index, _("value is too large"));
-	if (sp->is_power_2 && !ispow2(c))
-		illegal_option(str, opts, index, _("value must be a power of 2"));
-	return c;
-}
-
 /*
  * Option is a string - do all the option table work, and check there
  * is actually an option string. Otherwise we don't do anything with the string
-- 
2.13.3


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

* [PATCH 6/6] mkfs: extend opt_params with a value field
  2017-08-11 12:30 [PATCH 0/6 v2] mkfs: save user input into opts table Jan Tulak
                   ` (4 preceding siblings ...)
  2017-08-11 12:30 ` [PATCH 5/6] mkfs: move getnum within the file Jan Tulak
@ 2017-08-11 12:30 ` Jan Tulak
  2017-08-14 23:15   ` Darrick J. Wong
  2017-08-15 15:08 ` [PATCH 1/6 v2] mkfs: Save raw user input field to the opts struct Jan Tulak
  6 siblings, 1 reply; 37+ messages in thread
From: Jan Tulak @ 2017-08-11 12:30 UTC (permalink / raw)
  To: linux-xfs; +Cc: Jan Tulak

This patch adds infrastructure that will be used in subsequent patches.

The Value field is the actual value used in computations for creating
the filesystem.  This is initialized with sensible default values. If
initialized to 0, the value is considered disabled. User input will
override default values.  If the field is a string and not a number, the
value is set to a positive non-zero number when user input has been
supplied.

Add functions that can be used to get/set values to opts table.

Signed-off-by: Jan Tulak <jtulak@redhat.com>

---
Change:
* make the value type to be long long instead of uint64 for now
* add collateral updates
* add bounds to get/set functions
* update the description of commit/in code
* merge with another patch, which adds the get/set functions.
---
 mkfs/xfs_mkfs.c | 194 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 194 insertions(+)

diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
index 3e7ba5f0..61ef09e8 100644
--- a/mkfs/xfs_mkfs.c
+++ b/mkfs/xfs_mkfs.c
@@ -117,6 +117,13 @@ unsigned int		sectorsize;
  *     Filled raw string from the user, so we never lose that information e.g.
  *     to print it back in case of an issue.
  *
+ *   value OPTIONAL
+ *     The actual value used in computations for creating the filesystem.
+ *     This is initialized with sensible default values. If initialized to 0,
+ *     the value is considered disabled. User input will override default
+ *     values. If the field is a string and not a number, the value is set to
+ *     a positive non-zero number when user input has been supplied.
+ *
  */
 struct opt_params {
 	int		index;
@@ -134,6 +141,7 @@ struct opt_params {
 		long long	maxval;
 		long long	flagval;
 		char		*raw_input;
+		long long	value;
 	}		subopt_params[MAX_SUBOPTS];
 } opts[MAX_OPTS] = {
 #define OPT_B	0
@@ -750,6 +758,180 @@ struct opt_params {
 #define WHACK_SIZE (128 * 1024)
 
 /*
+ * Get and set values to the opts table.
+ */
+static int
+get_conf_val_unsafe(int opt, int subopt, uint64_t *output)
+{
+	if (subopt < 0 || subopt >= MAX_SUBOPTS ||
+	    opt < 0 || opt >= MAX_OPTS) {
+		fprintf(stderr,
+		"This is a bug: get_conf_val called with invalid opt/subopt: %d/%d\n",
+		opt, subopt);
+		return -EINVAL;
+	}
+	*output = opts[opt].subopt_params[subopt].value;
+	return 0;
+}
+
+static long long
+get_conf_val(int opt, int subopt)
+{
+	uint64_t res;
+	if (get_conf_val_unsafe(opt, subopt, &res) != 0)
+	    exit(1);
+	return res;
+}
+
+static int
+set_conf_val_unsafe(int opt, int subopt, uint64_t val)
+{
+	if (subopt < 0 || subopt >= MAX_SUBOPTS ||
+	    opt < 0 || opt >= MAX_OPTS) {
+		fprintf(stderr,
+		"This is a bug: set_conf_val called with invalid opt/subopt: %d/%d\n",
+		opt, subopt);
+		return -EINVAL;
+	}
+	struct subopt_param *sp = &opts[opt].subopt_params[subopt];
+	sp->value = val;
+
+	return 0;
+}
+
+static void
+set_conf_val(int opt, int subopt, uint64_t val)
+{
+	if (set_conf_val_unsafe(opt, subopt, val) != 0)
+		exit(1);
+}
+
+/*
+ * A wrapper around set_conf_val which updates also connected/collateral values.
+ * E.g. when changing S_LOG, update S_SIZE too.
+ */
+static void
+set_conf_val_collateral(int opt, int subopt, uint64_t val)
+{
+	set_conf_val(opt, subopt, val);
+
+	switch (opt) {
+	case OPT_B:
+		switch (subopt) {
+		case B_LOG:
+			set_conf_val(OPT_B, B_SIZE, 1 << val);
+			break;
+		case B_SIZE:
+			set_conf_val(OPT_B, B_LOG,
+				libxfs_highbit32(val));
+			break;
+		}
+		break;
+	case OPT_D:
+		switch (subopt) {
+		case D_SECTLOG:
+			set_conf_val(OPT_S, S_LOG, val);
+			set_conf_val(OPT_S, S_SECTLOG, val);
+			set_conf_val(OPT_D, D_SECTSIZE,
+					1 << val);
+			set_conf_val(OPT_S, S_SECTSIZE,
+					1 << val);
+			set_conf_val(OPT_S, S_SIZE,
+					1 << val);
+			break;
+		case D_SECTSIZE:
+			set_conf_val(OPT_S, S_SIZE, val);
+			set_conf_val(OPT_S, S_SECTSIZE, val);
+			set_conf_val(OPT_D, D_SECTLOG,
+				libxfs_highbit32(val));
+			set_conf_val(OPT_S, S_LOG,
+				libxfs_highbit32(val));
+			set_conf_val(OPT_S, S_SECTLOG,
+				libxfs_highbit32(val));
+			break;
+		}
+		break;
+	case OPT_I:
+		switch (subopt) {
+		case I_LOG:
+			set_conf_val(OPT_I, I_SIZE, 1 << val);
+			break;
+		case I_SIZE:
+			set_conf_val(OPT_I, I_LOG,
+				libxfs_highbit32(val));
+			break;
+		}
+		break;
+	case OPT_L:
+		switch (subopt) {
+		case L_SECTLOG:
+			set_conf_val(OPT_L, L_SECTSIZE,
+					1 << val);
+			break;
+		case L_SECTSIZE:
+			set_conf_val(OPT_L, L_SECTLOG,
+			     libxfs_highbit32(val));
+			break;
+		}
+		break;
+	case OPT_M:
+		switch (subopt) {
+		}
+		break;
+	case OPT_N:
+		switch (subopt) {
+		case N_LOG:
+			set_conf_val(OPT_N, N_SIZE, 1 << val);
+			break;
+		case N_SIZE:
+			set_conf_val(OPT_N, N_LOG,
+				libxfs_highbit32(val));
+			break;
+		}
+		break;
+	case OPT_R:
+		switch (subopt) {
+		}
+		break;
+	case OPT_S:
+		switch (subopt) {
+		case S_LOG:
+		case S_SECTLOG:
+			set_conf_val(OPT_S, S_LOG, val);
+			set_conf_val(OPT_D, D_SECTLOG, val);
+			set_conf_val(OPT_L, L_SECTLOG, val);
+			set_conf_val(OPT_D, D_SECTSIZE,
+					1 << val);
+			set_conf_val(OPT_S, S_SIZE, 1 << val);
+			set_conf_val(OPT_S, S_SECTSIZE,
+					1 << val);
+			set_conf_val(OPT_L, L_SECTLOG, val);
+			set_conf_val(OPT_L,
+					L_SECTSIZE, 1 << val);
+
+			set_conf_val(OPT_L, L_SECTSIZE, val);
+			break;
+		case S_SIZE:
+		case S_SECTSIZE:
+			set_conf_val(OPT_S, S_SIZE, val);
+			set_conf_val(OPT_D, D_SECTSIZE, val);
+			set_conf_val(OPT_D, D_SECTLOG,
+				libxfs_highbit32(val));
+			set_conf_val(OPT_S, S_LOG,
+				libxfs_highbit32(val));
+			set_conf_val(OPT_S, S_SECTLOG,
+				libxfs_highbit32(val));
+			set_conf_val(OPT_L,
+					L_SECTSIZE, val);
+			set_conf_val(OPT_L, L_SECTLOG,
+					libxfs_highbit32(val));
+			break;
+		}
+		break;
+	}
+}
+
+/*
  * Return 0 on success, -ENOMEM if it could not allocate enough memory for
  * the string to be saved.
  */
@@ -932,6 +1114,18 @@ getnum(
 }
 
 /*
+ * A wrapper for getnum and set_conf_val.
+ */
+static inline long long
+parse_conf_val(int opt, int subopt, char *value)
+{
+	long long num = getnum(value, &opts[opt], subopt);
+
+	set_conf_val_collateral(opt, subopt, num);
+	return num;
+}
+
+/*
  * Convert lsu to lsunit for 512 bytes blocks and check validity of the values.
  */
 static void
-- 
2.13.3


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

* Re: [PATCH 1/6] mkfs: Save raw user input field to the opts struct
  2017-08-11 12:30 ` [PATCH 1/6] mkfs: Save raw user input field to the opts struct Jan Tulak
@ 2017-08-14 22:56   ` Darrick J. Wong
  2017-08-15  9:47     ` Jan Tulak
  0 siblings, 1 reply; 37+ messages in thread
From: Darrick J. Wong @ 2017-08-14 22:56 UTC (permalink / raw)
  To: Jan Tulak; +Cc: linux-xfs

On Fri, Aug 11, 2017 at 02:30:32PM +0200, Jan Tulak wrote:
> Save exactly what the user gave us for every option.  This way, we will
> never lose the information if we need it to print back an issue.
> (Just add the infrastructure now, used in the next patches.)
> 
> Signed-off-by: Jan Tulak <jtulak@redhat.com>
> 
> ---
> CHANGE:
> * added strdup
> * added boundary checks to set/get functions
> ---
>  mkfs/xfs_mkfs.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 69 insertions(+)
> 
> diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
> index 7bb6408f..fa0b475c 100644
> --- a/mkfs/xfs_mkfs.c
> +++ b/mkfs/xfs_mkfs.c
> @@ -107,6 +107,11 @@ unsigned int		sectorsize;
>   *     sets what is used with simple specifying the subopt (-d file).
>   *     A special SUBOPT_NEEDS_VAL can be used to require a user-given
>   *     value in any case.
> + *
> + *   raw_input INTERNAL
> + *     Filled raw string from the user, so we never lose that information e.g.
> + *     to print it back in case of an issue.
> + *
>   */
>  struct opt_params {
>  	const char	name;
> @@ -122,6 +127,7 @@ struct opt_params {
>  		long long	minval;
>  		long long	maxval;
>  		long long	defaultval;
> +		char		*raw_input;
>  	}		subopt_params[MAX_SUBOPTS];
>  };
>  
> @@ -730,6 +736,69 @@ struct opt_params mopts = {
>  #define WHACK_SIZE (128 * 1024)
>  
>  /*
> + * Return 0 on success, -ENOMEM if it could not allocate enough memory for
> + * the string to be saved.
> + */
> +static int
> +set_conf_raw(struct opt_params *opt, const int subopt, const char *value)
> +{
> +	if (subopt < 0 || subopt >= MAX_SUBOPTS) {
> +		fprintf(stderr,
> +		"This is a bug: set_conf_raw called with invalid opt/subopt: %c/%d\n",
> +		opt->name, subopt);

ASSERT?  Or, if I'm just foolishly restarting an old bikeshed and the
fprintf/-EINVAL should stay, then the indentation of the arguments needs
fixing.

> +		return -EINVAL;
> +	}
> +	if (value == NULL) {
> +		if (opt->subopt_params[subopt].raw_input != NULL)
> +			free(opt->subopt_params[subopt].raw_input);
> +		opt->subopt_params[subopt].raw_input = NULL;
> +	} else {
> +		opt->subopt_params[subopt].raw_input = strdup(value);
> +		if (opt->subopt_params[subopt].raw_input == NULL)
> +			return -ENOMEM;
> +	}
> +	return 0;
> +}
> +
> +/*
> + * Return 0 on success, -ENOMEM if it could not allocate enough memory for
> + * the string to be saved into the out pointer.
> + */
> +static int
> +get_conf_raw(const struct opt_params *opt, const int subopt, char **out)
> +{
> +	if (subopt < 0 || subopt >= MAX_SUBOPTS) {
> +		fprintf(stderr,
> +		"This is a bug: get_conf_raw called with invalid opt/subopt: %c/%d\n",
> +		opt->name, subopt);
> +		return -EINVAL;

(Same here)

> +	}
> +	*out = strdup(opt->subopt_params[subopt].raw_input);

Given that raw_input can be set to NULL and strdup(NULL) segfaults on
glibc 2.23, do we need a null check of raw_input here?  Is it the case
that get_conf_raw is only called if we (somehow) know that there's a
value to get later?

--D

> +	if (*out == NULL)
> +		return -ENOMEM;
> +	return 0;
> +
> +}
> +
> +/*
> + * Same as get_conf_raw(), except it returns the string through return.
> + * If any error occurs, return NULL.
> + */
> +static char *
> +get_conf_raw_safe(const struct opt_params *opt, const int subopt)
> +{
> +	char *str;
> +
> +	str = NULL;
> +
> +	if (get_conf_raw(opt, subopt, &str) == -ENOMEM) {
> +		fprintf(stderr, "Out of memory!");
> +		return NULL;
> +	}
> +	return str;
> +}
> +
> +/*
>   * Convert lsu to lsunit for 512 bytes blocks and check validity of the values.
>   */
>  static void
> -- 
> 2.13.3
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 2/6] mkfs: rename defaultval to flagval in opts
  2017-08-11 12:30 ` [PATCH 2/6] mkfs: rename defaultval to flagval in opts Jan Tulak
@ 2017-08-14 22:56   ` Darrick J. Wong
  0 siblings, 0 replies; 37+ messages in thread
From: Darrick J. Wong @ 2017-08-14 22:56 UTC (permalink / raw)
  To: Jan Tulak; +Cc: linux-xfs

On Fri, Aug 11, 2017 at 02:30:33PM +0200, Jan Tulak wrote:
> The old name 'defaultval' was misleading - it is not the default value,
> but the value the option has when used as a flag by an user.
> 
> Signed-off-by: Jan Tulak <jtulak@redhat.com>
> Reviewed-by: Luis R. Rodriguez <mcgrof@kernel.org>

Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>

> ---
>  mkfs/xfs_mkfs.c | 120 ++++++++++++++++++++++++++++----------------------------
>  1 file changed, 60 insertions(+), 60 deletions(-)
> 
> diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
> index fa0b475c..9431f010 100644
> --- a/mkfs/xfs_mkfs.c
> +++ b/mkfs/xfs_mkfs.c
> @@ -101,7 +101,7 @@ unsigned int		sectorsize;
>   *     to zero. But if one value is different: minval=0 and maxval=1,
>   *     then it is OK.)
>   *
> - *   defaultval MANDATORY
> + *   flagval MANDATORY
>   *     The value used if user specifies the subopt, but no value.
>   *     If the subopt accepts some values (-d file=[1|0]), then this
>   *     sets what is used with simple specifying the subopt (-d file).
> @@ -126,7 +126,7 @@ struct opt_params {
>  		int		conflicts[MAX_CONFLICTS];
>  		long long	minval;
>  		long long	maxval;
> -		long long	defaultval;
> +		long long	flagval;
>  		char		*raw_input;
>  	}		subopt_params[MAX_SUBOPTS];
>  };
> @@ -146,7 +146,7 @@ struct opt_params bopts = {
>  				 LAST_CONFLICT },
>  		  .minval = XFS_MIN_BLOCKSIZE_LOG,
>  		  .maxval = XFS_MAX_BLOCKSIZE_LOG,
> -		  .defaultval = SUBOPT_NEEDS_VAL,
> +		  .flagval = SUBOPT_NEEDS_VAL,
>  		},
>  		{ .index = B_SIZE,
>  		  .convert = true,
> @@ -155,7 +155,7 @@ struct opt_params bopts = {
>  				 LAST_CONFLICT },
>  		  .minval = XFS_MIN_BLOCKSIZE,
>  		  .maxval = XFS_MAX_BLOCKSIZE,
> -		  .defaultval = SUBOPT_NEEDS_VAL,
> +		  .flagval = SUBOPT_NEEDS_VAL,
>  		},
>  	},
>  };
> @@ -201,24 +201,24 @@ struct opt_params dopts = {
>  				 LAST_CONFLICT },
>  		  .minval = 1,
>  		  .maxval = XFS_MAX_AGNUMBER,
> -		  .defaultval = SUBOPT_NEEDS_VAL,
> +		  .flagval = SUBOPT_NEEDS_VAL,
>  		},
>  		{ .index = D_FILE,
>  		  .conflicts = { LAST_CONFLICT },
>  		  .minval = 0,
>  		  .maxval = 1,
> -		  .defaultval = 1,
> +		  .flagval = 1,
>  		},
>  		{ .index = D_NAME,
>  		  .conflicts = { LAST_CONFLICT },
> -		  .defaultval = SUBOPT_NEEDS_VAL,
> +		  .flagval = SUBOPT_NEEDS_VAL,
>  		},
>  		{ .index = D_SIZE,
>  		  .conflicts = { LAST_CONFLICT },
>  		  .convert = true,
>  		  .minval = XFS_AG_MIN_BYTES,
>  		  .maxval = LLONG_MAX,
> -		  .defaultval = SUBOPT_NEEDS_VAL,
> +		  .flagval = SUBOPT_NEEDS_VAL,
>  		},
>  		{ .index = D_SUNIT,
>  		  .conflicts = { D_NOALIGN,
> @@ -227,7 +227,7 @@ struct opt_params dopts = {
>  				 LAST_CONFLICT },
>  		  .minval = 0,
>  		  .maxval = UINT_MAX,
> -		  .defaultval = SUBOPT_NEEDS_VAL,
> +		  .flagval = SUBOPT_NEEDS_VAL,
>  		},
>  		{ .index = D_SWIDTH,
>  		  .conflicts = { D_NOALIGN,
> @@ -236,7 +236,7 @@ struct opt_params dopts = {
>  				 LAST_CONFLICT },
>  		  .minval = 0,
>  		  .maxval = UINT_MAX,
> -		  .defaultval = SUBOPT_NEEDS_VAL,
> +		  .flagval = SUBOPT_NEEDS_VAL,
>  		},
>  		{ .index = D_AGSIZE,
>  		  .conflicts = { D_AGCOUNT,
> @@ -244,7 +244,7 @@ struct opt_params dopts = {
>  		  .convert = true,
>  		  .minval = XFS_AG_MIN_BYTES,
>  		  .maxval = XFS_AG_MAX_BYTES,
> -		  .defaultval = SUBOPT_NEEDS_VAL,
> +		  .flagval = SUBOPT_NEEDS_VAL,
>  		},
>  		{ .index = D_SU,
>  		  .conflicts = { D_NOALIGN,
> @@ -254,7 +254,7 @@ struct opt_params dopts = {
>  		  .convert = true,
>  		  .minval = 0,
>  		  .maxval = UINT_MAX,
> -		  .defaultval = SUBOPT_NEEDS_VAL,
> +		  .flagval = SUBOPT_NEEDS_VAL,
>  		},
>  		{ .index = D_SW,
>  		  .conflicts = { D_NOALIGN,
> @@ -263,14 +263,14 @@ struct opt_params dopts = {
>  				 LAST_CONFLICT },
>  		  .minval = 0,
>  		  .maxval = UINT_MAX,
> -		  .defaultval = SUBOPT_NEEDS_VAL,
> +		  .flagval = SUBOPT_NEEDS_VAL,
>  		},
>  		{ .index = D_SECTLOG,
>  		  .conflicts = { D_SECTSIZE,
>  				 LAST_CONFLICT },
>  		  .minval = XFS_MIN_SECTORSIZE_LOG,
>  		  .maxval = XFS_MAX_SECTORSIZE_LOG,
> -		  .defaultval = SUBOPT_NEEDS_VAL,
> +		  .flagval = SUBOPT_NEEDS_VAL,
>  		},
>  		{ .index = D_SECTSIZE,
>  		  .conflicts = { D_SECTLOG,
> @@ -279,7 +279,7 @@ struct opt_params dopts = {
>  		  .is_power_2 = true,
>  		  .minval = XFS_MIN_SECTORSIZE,
>  		  .maxval = XFS_MAX_SECTORSIZE,
> -		  .defaultval = SUBOPT_NEEDS_VAL,
> +		  .flagval = SUBOPT_NEEDS_VAL,
>  		},
>  		{ .index = D_NOALIGN,
>  		  .conflicts = { D_SU,
> @@ -289,25 +289,25 @@ struct opt_params dopts = {
>  				 LAST_CONFLICT },
>  		  .minval = 0,
>  		  .maxval = 1,
> -		  .defaultval = 1,
> +		  .flagval = 1,
>  		},
>  		{ .index = D_RTINHERIT,
>  		  .conflicts = { LAST_CONFLICT },
>  		  .minval = 1,
>  		  .maxval = 1,
> -		  .defaultval = 1,
> +		  .flagval = 1,
>  		},
>  		{ .index = D_PROJINHERIT,
>  		  .conflicts = { LAST_CONFLICT },
>  		  .minval = 0,
>  		  .maxval = UINT_MAX,
> -		  .defaultval = SUBOPT_NEEDS_VAL,
> +		  .flagval = SUBOPT_NEEDS_VAL,
>  		},
>  		{ .index = D_EXTSZINHERIT,
>  		  .conflicts = { LAST_CONFLICT },
>  		  .minval = 0,
>  		  .maxval = UINT_MAX,
> -		  .defaultval = SUBOPT_NEEDS_VAL,
> +		  .flagval = SUBOPT_NEEDS_VAL,
>  		},
>  	},
>  };
> @@ -339,7 +339,7 @@ struct opt_params iopts = {
>  		  .conflicts = { LAST_CONFLICT },
>  		  .minval = 0,
>  		  .maxval = 1,
> -		  .defaultval = 1,
> +		  .flagval = 1,
>  		},
>  		{ .index = I_LOG,
>  		  .conflicts = { I_PERBLOCK,
> @@ -347,13 +347,13 @@ struct opt_params iopts = {
>  				 LAST_CONFLICT },
>  		  .minval = XFS_DINODE_MIN_LOG,
>  		  .maxval = XFS_DINODE_MAX_LOG,
> -		  .defaultval = SUBOPT_NEEDS_VAL,
> +		  .flagval = SUBOPT_NEEDS_VAL,
>  		},
>  		{ .index = I_MAXPCT,
>  		  .conflicts = { LAST_CONFLICT },
>  		  .minval = 0,
>  		  .maxval = 100,
> -		  .defaultval = SUBOPT_NEEDS_VAL,
> +		  .flagval = SUBOPT_NEEDS_VAL,
>  		},
>  		{ .index = I_PERBLOCK,
>  		  .conflicts = { I_LOG,
> @@ -362,7 +362,7 @@ struct opt_params iopts = {
>  		  .is_power_2 = true,
>  		  .minval = XFS_MIN_INODE_PERBLOCK,
>  		  .maxval = XFS_MAX_BLOCKSIZE / XFS_DINODE_MIN_SIZE,
> -		  .defaultval = SUBOPT_NEEDS_VAL,
> +		  .flagval = SUBOPT_NEEDS_VAL,
>  		},
>  		{ .index = I_SIZE,
>  		  .conflicts = { I_PERBLOCK,
> @@ -371,25 +371,25 @@ struct opt_params iopts = {
>  		  .is_power_2 = true,
>  		  .minval = XFS_DINODE_MIN_SIZE,
>  		  .maxval = XFS_DINODE_MAX_SIZE,
> -		  .defaultval = SUBOPT_NEEDS_VAL,
> +		  .flagval = SUBOPT_NEEDS_VAL,
>  		},
>  		{ .index = I_ATTR,
>  		  .conflicts = { LAST_CONFLICT },
>  		  .minval = 0,
>  		  .maxval = 2,
> -		  .defaultval = SUBOPT_NEEDS_VAL,
> +		  .flagval = SUBOPT_NEEDS_VAL,
>  		},
>  		{ .index = I_PROJID32BIT,
>  		  .conflicts = { LAST_CONFLICT },
>  		  .minval = 0,
>  		  .maxval = 1,
> -		  .defaultval = 1,
> +		  .flagval = 1,
>  		},
>  		{ .index = I_SPINODES,
>  		  .conflicts = { LAST_CONFLICT },
>  		  .minval = 0,
>  		  .maxval = 1,
> -		  .defaultval = 1,
> +		  .flagval = 1,
>  		},
>  	},
>  };
> @@ -429,7 +429,7 @@ struct opt_params lopts = {
>  				 LAST_CONFLICT },
>  		  .minval = 0,
>  		  .maxval = UINT_MAX,
> -		  .defaultval = SUBOPT_NEEDS_VAL,
> +		  .flagval = SUBOPT_NEEDS_VAL,
>  		},
>  		{ .index = L_INTERNAL,
>  		  .conflicts = { L_FILE,
> @@ -437,27 +437,27 @@ struct opt_params lopts = {
>  				 LAST_CONFLICT },
>  		  .minval = 0,
>  		  .maxval = 1,
> -		  .defaultval = 1,
> +		  .flagval = 1,
>  		},
>  		{ .index = L_SIZE,
>  		  .conflicts = { LAST_CONFLICT },
>  		  .convert = true,
>  		  .minval = 2 * 1024 * 1024LL,	/* XXX: XFS_MIN_LOG_BYTES */
>  		  .maxval = XFS_MAX_LOG_BYTES,
> -		  .defaultval = SUBOPT_NEEDS_VAL,
> +		  .flagval = SUBOPT_NEEDS_VAL,
>  		},
>  		{ .index = L_VERSION,
>  		  .conflicts = { LAST_CONFLICT },
>  		  .minval = 1,
>  		  .maxval = 2,
> -		  .defaultval = SUBOPT_NEEDS_VAL,
> +		  .flagval = SUBOPT_NEEDS_VAL,
>  		},
>  		{ .index = L_SUNIT,
>  		  .conflicts = { L_SU,
>  				 LAST_CONFLICT },
>  		  .minval = 1,
>  		  .maxval = BTOBB(XLOG_MAX_RECORD_BSIZE),
> -		  .defaultval = SUBOPT_NEEDS_VAL,
> +		  .flagval = SUBOPT_NEEDS_VAL,
>  		},
>  		{ .index = L_SU,
>  		  .conflicts = { L_SUNIT,
> @@ -465,20 +465,20 @@ struct opt_params lopts = {
>  		  .convert = true,
>  		  .minval = BBTOB(1),
>  		  .maxval = XLOG_MAX_RECORD_BSIZE,
> -		  .defaultval = SUBOPT_NEEDS_VAL,
> +		  .flagval = SUBOPT_NEEDS_VAL,
>  		},
>  		{ .index = L_DEV,
>  		  .conflicts = { L_AGNUM,
>  				 L_INTERNAL,
>  				 LAST_CONFLICT },
> -		  .defaultval = SUBOPT_NEEDS_VAL,
> +		  .flagval = SUBOPT_NEEDS_VAL,
>  		},
>  		{ .index = L_SECTLOG,
>  		  .conflicts = { L_SECTSIZE,
>  				 LAST_CONFLICT },
>  		  .minval = XFS_MIN_SECTORSIZE_LOG,
>  		  .maxval = XFS_MAX_SECTORSIZE_LOG,
> -		  .defaultval = SUBOPT_NEEDS_VAL,
> +		  .flagval = SUBOPT_NEEDS_VAL,
>  		},
>  		{ .index = L_SECTSIZE,
>  		  .conflicts = { L_SECTLOG,
> @@ -487,26 +487,26 @@ struct opt_params lopts = {
>  		  .is_power_2 = true,
>  		  .minval = XFS_MIN_SECTORSIZE,
>  		  .maxval = XFS_MAX_SECTORSIZE,
> -		  .defaultval = SUBOPT_NEEDS_VAL,
> +		  .flagval = SUBOPT_NEEDS_VAL,
>  		},
>  		{ .index = L_FILE,
>  		  .conflicts = { L_INTERNAL,
>  				 LAST_CONFLICT },
>  		  .minval = 0,
>  		  .maxval = 1,
> -		  .defaultval = 1,
> +		  .flagval = 1,
>  		},
>  		{ .index = L_NAME,
>  		  .conflicts = { L_AGNUM,
>  				 L_INTERNAL,
>  				 LAST_CONFLICT },
> -		  .defaultval = SUBOPT_NEEDS_VAL,
> +		  .flagval = SUBOPT_NEEDS_VAL,
>  		},
>  		{ .index = L_LAZYSBCNTR,
>  		  .conflicts = { LAST_CONFLICT },
>  		  .minval = 0,
>  		  .maxval = 1,
> -		  .defaultval = 1,
> +		  .flagval = 1,
>  		},
>  	},
>  };
> @@ -530,7 +530,7 @@ struct opt_params nopts = {
>  				 LAST_CONFLICT },
>  		  .minval = XFS_MIN_REC_DIRSIZE,
>  		  .maxval = XFS_MAX_BLOCKSIZE_LOG,
> -		  .defaultval = SUBOPT_NEEDS_VAL,
> +		  .flagval = SUBOPT_NEEDS_VAL,
>  		},
>  		{ .index = N_SIZE,
>  		  .conflicts = { N_LOG,
> @@ -539,19 +539,19 @@ struct opt_params nopts = {
>  		  .is_power_2 = true,
>  		  .minval = 1 << XFS_MIN_REC_DIRSIZE,
>  		  .maxval = XFS_MAX_BLOCKSIZE,
> -		  .defaultval = SUBOPT_NEEDS_VAL,
> +		  .flagval = SUBOPT_NEEDS_VAL,
>  		},
>  		{ .index = N_VERSION,
>  		  .conflicts = { LAST_CONFLICT },
>  		  .minval = 2,
>  		  .maxval = 2,
> -		  .defaultval = SUBOPT_NEEDS_VAL,
> +		  .flagval = SUBOPT_NEEDS_VAL,
>  		},
>  		{ .index = N_FTYPE,
>  		  .conflicts = { LAST_CONFLICT },
>  		  .minval = 0,
>  		  .maxval = 1,
> -		  .defaultval = 1,
> +		  .flagval = 1,
>  		},
>  	},
>  };
> @@ -579,33 +579,33 @@ struct opt_params ropts = {
>  		  .convert = true,
>  		  .minval = XFS_MIN_RTEXTSIZE,
>  		  .maxval = XFS_MAX_RTEXTSIZE,
> -		  .defaultval = SUBOPT_NEEDS_VAL,
> +		  .flagval = SUBOPT_NEEDS_VAL,
>  		},
>  		{ .index = R_SIZE,
>  		  .conflicts = { LAST_CONFLICT },
>  		  .convert = true,
>  		  .minval = 0,
>  		  .maxval = LLONG_MAX,
> -		  .defaultval = SUBOPT_NEEDS_VAL,
> +		  .flagval = SUBOPT_NEEDS_VAL,
>  		},
>  		{ .index = R_DEV,
>  		  .conflicts = { LAST_CONFLICT },
> -		  .defaultval = SUBOPT_NEEDS_VAL,
> +		  .flagval = SUBOPT_NEEDS_VAL,
>  		},
>  		{ .index = R_FILE,
>  		  .minval = 0,
>  		  .maxval = 1,
> -		  .defaultval = 1,
> +		  .flagval = 1,
>  		  .conflicts = { LAST_CONFLICT },
>  		},
>  		{ .index = R_NAME,
>  		  .conflicts = { LAST_CONFLICT },
> -		  .defaultval = SUBOPT_NEEDS_VAL,
> +		  .flagval = SUBOPT_NEEDS_VAL,
>  		},
>  		{ .index = R_NOALIGN,
>  		  .minval = 0,
>  		  .maxval = 1,
> -		  .defaultval = 1,
> +		  .flagval = 1,
>  		  .conflicts = { LAST_CONFLICT },
>  		},
>  	},
> @@ -631,7 +631,7 @@ struct opt_params sopts = {
>  				 LAST_CONFLICT },
>  		  .minval = XFS_MIN_SECTORSIZE_LOG,
>  		  .maxval = XFS_MAX_SECTORSIZE_LOG,
> -		  .defaultval = SUBOPT_NEEDS_VAL,
> +		  .flagval = SUBOPT_NEEDS_VAL,
>  		},
>  		{ .index = S_SECTLOG,
>  		  .conflicts = { S_SIZE,
> @@ -639,7 +639,7 @@ struct opt_params sopts = {
>  				 LAST_CONFLICT },
>  		  .minval = XFS_MIN_SECTORSIZE_LOG,
>  		  .maxval = XFS_MAX_SECTORSIZE_LOG,
> -		  .defaultval = SUBOPT_NEEDS_VAL,
> +		  .flagval = SUBOPT_NEEDS_VAL,
>  		},
>  		{ .index = S_SIZE,
>  		  .conflicts = { S_LOG,
> @@ -649,7 +649,7 @@ struct opt_params sopts = {
>  		  .is_power_2 = true,
>  		  .minval = XFS_MIN_SECTORSIZE,
>  		  .maxval = XFS_MAX_SECTORSIZE,
> -		  .defaultval = SUBOPT_NEEDS_VAL,
> +		  .flagval = SUBOPT_NEEDS_VAL,
>  		},
>  		{ .index = S_SECTSIZE,
>  		  .conflicts = { S_LOG,
> @@ -659,7 +659,7 @@ struct opt_params sopts = {
>  		  .is_power_2 = true,
>  		  .minval = XFS_MIN_SECTORSIZE,
>  		  .maxval = XFS_MAX_SECTORSIZE,
> -		  .defaultval = SUBOPT_NEEDS_VAL,
> +		  .flagval = SUBOPT_NEEDS_VAL,
>  		},
>  	},
>  };
> @@ -684,29 +684,29 @@ struct opt_params mopts = {
>  		  .conflicts = { LAST_CONFLICT },
>  		  .minval = 0,
>  		  .maxval = 1,
> -		  .defaultval = 1,
> +		  .flagval = 1,
>  		},
>  		{ .index = M_FINOBT,
>  		  .conflicts = { LAST_CONFLICT },
>  		  .minval = 0,
>  		  .maxval = 1,
> -		  .defaultval = 1,
> +		  .flagval = 1,
>  		},
>  		{ .index = M_UUID,
>  		  .conflicts = { LAST_CONFLICT },
> -		  .defaultval = SUBOPT_NEEDS_VAL,
> +		  .flagval = SUBOPT_NEEDS_VAL,
>  		},
>  		{ .index = M_RMAPBT,
>  		  .conflicts = { LAST_CONFLICT },
>  		  .minval = 0,
>  		  .maxval = 1,
> -		  .defaultval = 1,
> +		  .flagval = 1,
>  		},
>  		{ .index = M_REFLINK,
>  		  .conflicts = { LAST_CONFLICT },
>  		  .minval = 0,
>  		  .maxval = 1,
> -		  .defaultval = 1,
> +		  .flagval = 1,
>  		},
>  	},
>  };
> @@ -1398,9 +1398,9 @@ getnum(
>  	check_opt(opts, index, false);
>  	/* empty strings might just return a default value */
>  	if (!str || *str == '\0') {
> -		if (sp->defaultval == SUBOPT_NEEDS_VAL)
> +		if (sp->flagval == SUBOPT_NEEDS_VAL)
>  			reqval(opts->name, (char **)opts->subopts, index);
> -		return sp->defaultval;
> +		return sp->flagval;
>  	}
>  
>  	if (sp->minval == 0 && sp->maxval == 0) {
> -- 
> 2.13.3
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 3/6] mkfs: remove intermediate getstr followed by getnum
  2017-08-11 12:30 ` [PATCH 3/6] mkfs: remove intermediate getstr followed by getnum Jan Tulak
@ 2017-08-14 22:58   ` Darrick J. Wong
  0 siblings, 0 replies; 37+ messages in thread
From: Darrick J. Wong @ 2017-08-14 22:58 UTC (permalink / raw)
  To: Jan Tulak; +Cc: linux-xfs

On Fri, Aug 11, 2017 at 02:30:34PM +0200, Jan Tulak wrote:
> Some options loaded a number as a string with getstr and converted it to
> number with getnum later in the code, without any reason for this
> approach.  (They were probably forgotten in some past cleaning.)
> 
> This patch changes them to skip the string and use getnum directly in
> the main option-parsing loop, as do all the other numerical options.
> And as we now have two variables of the same type for the same value,
> merge them together. (e.g. former string dsize and number dbytes).
> 
> Signed-off-by: Jan Tulak <jtulak@redhat.com>

Looks ok, I think...
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>

> 
> ---
> 
> This patch has to be applied after "mkfs: Save raw user input ...",
> because otherwise we would temporary lose the access to strings
> with user-given values and thus wouldn't be able to report them in
> case of an issue. (In reply to Eric's comment.)
> 
> UPDATE:
>  * fix dbytes, rtbytes, rtextbytes and logbytes - these variables should
>    be uint64, as the local old ones they are replacing, but were
>    unintentionally created as int
> ---
>  mkfs/xfs_mkfs.c | 90 ++++++++++++++++++++++++++-------------------------------
>  1 file changed, 41 insertions(+), 49 deletions(-)
> 
> diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
> index 9431f010..78e27498 100644
> --- a/mkfs/xfs_mkfs.c
> +++ b/mkfs/xfs_mkfs.c
> @@ -1396,6 +1396,7 @@ getnum(
>  	long long		c;
>  
>  	check_opt(opts, index, false);
> +	set_conf_raw(opts, index, str);
>  	/* empty strings might just return a default value */
>  	if (!str || *str == '\0') {
>  		if (sp->flagval == SUBOPT_NEEDS_VAL)
> @@ -1483,13 +1484,13 @@ main(
>  	char			*dfile;
>  	int			dirblocklog;
>  	int			dirblocksize;
> -	char			*dsize;
> +	uint64_t		dbytes;
>  	int			dsu;
>  	int			dsw;
>  	int			dsunit;
>  	int			dswidth;
>  	int			dsflag;
> -	int			force_overwrite;
> +	bool			force_overwrite;
>  	struct fsxattr		fsx;
>  	int			ilflag;
>  	int			imaxpct;
> @@ -1508,7 +1509,7 @@ main(
>  	xfs_rfsblock_t		logblocks;
>  	char			*logfile;
>  	int			loginternal;
> -	char			*logsize;
> +	uint64_t		logbytes;
>  	xfs_fsblock_t		logstart;
>  	int			lvflag;
>  	int			lsflag;
> @@ -1537,11 +1538,11 @@ main(
>  	char			*protostring;
>  	int			qflag;
>  	xfs_rfsblock_t		rtblocks;
> +	uint64_t		rtbytes;
>  	xfs_extlen_t		rtextblocks;
>  	xfs_rtblock_t		rtextents;
> -	char			*rtextsize;
> +	uint64_t		rtextbytes;
>  	char			*rtfile;
> -	char			*rtsize;
>  	xfs_sb_t		*sbp;
>  	int			sectorlog;
>  	uint64_t		sector_mask;
> @@ -1589,7 +1590,8 @@ main(
>  	qflag = 0;
>  	imaxpct = inodelog = inopblock = isize = 0;
>  	dfile = logfile = rtfile = NULL;
> -	dsize = logsize = rtsize = rtextsize = protofile = NULL;
> +	protofile = NULL;
> +	rtbytes = rtextbytes = logbytes = dbytes = 0;
>  	dsu = dsw = dsunit = dswidth = lalign = lsu = lsunit = 0;
>  	dsflag = nodsflag = norsflag = 0;
>  	force_overwrite = 0;
> @@ -1653,7 +1655,7 @@ main(
>  					xi.dname = getstr(value, &dopts, D_NAME);
>  					break;
>  				case D_SIZE:
> -					dsize = getstr(value, &dopts, D_SIZE);
> +					dbytes = getnum(value, &dopts, D_SIZE);
>  					break;
>  				case D_SUNIT:
>  					dsunit = getnum(value, &dopts, D_SUNIT);
> @@ -1802,7 +1804,7 @@ main(
>  					lvflag = 1;
>  					break;
>  				case L_SIZE:
> -					logsize = getstr(value, &lopts, L_SIZE);
> +					logbytes = getnum(value, &lopts, L_SIZE);
>  					break;
>  				case L_SECTLOG:
>  					lsectorlog = getnum(value, &lopts,
> @@ -1931,8 +1933,7 @@ main(
>  
>  				switch (getsubopt(&p, subopts, &value)) {
>  				case R_EXTSIZE:
> -					rtextsize = getstr(value, &ropts,
> -							   R_EXTSIZE);
> +					rtextbytes = getnum(value, &ropts, R_EXTSIZE);
>  					break;
>  				case R_FILE:
>  					xi.risfile = getnum(value, &ropts,
> @@ -1944,7 +1945,7 @@ main(
>  							   R_NAME);
>  					break;
>  				case R_SIZE:
> -					rtsize = getstr(value, &ropts, R_SIZE);
> +					rtbytes = getnum(value, &ropts, R_SIZE);
>  					break;
>  				case R_NOALIGN:
>  					norsflag = getnum(value, &ropts,
> @@ -2047,14 +2048,14 @@ _("Minimum block size for CRC enabled filesystems is %d bytes.\n"),
>  	 * sector size mismatches between the new filesystem and the underlying
>  	 * host filesystem.
>  	 */
> -	check_device_type(dfile, &xi.disfile, !dsize, !dfile,
> +	check_device_type(dfile, &xi.disfile, !dbytes, !dfile,
>  			  Nflag ? NULL : &xi.dcreat, force_overwrite, "d");
>  	if (!loginternal)
> -		check_device_type(xi.logname, &xi.lisfile, !logsize, !xi.logname,
> -				  Nflag ? NULL : &xi.lcreat,
> +		check_device_type(xi.logname, &xi.lisfile, !logbytes,
> +				  !xi.logname, Nflag ? NULL : &xi.lcreat,
>  				  force_overwrite, "l");
>  	if (xi.rtname)
> -		check_device_type(xi.rtname, &xi.risfile, !rtsize, !xi.rtname,
> +		check_device_type(xi.rtname, &xi.risfile, !rtbytes, !xi.rtname,
>  				  Nflag ? NULL : &xi.rcreat,
>  				  force_overwrite, "r");
>  	if (xi.disfile || xi.lisfile || xi.risfile)
> @@ -2235,10 +2236,7 @@ _("rmapbt not supported with realtime devices\n"));
>  	}
>  
>  
> -	if (dsize) {
> -		uint64_t dbytes;
> -
> -		dbytes = getnum(dsize, &dopts, D_SIZE);
> +	if (dbytes) {
>  		if (dbytes % XFS_MIN_BLOCKSIZE) {
>  			fprintf(stderr,
>  			_("illegal data length %lld, not a multiple of %d\n"),
> @@ -2267,10 +2265,7 @@ _("rmapbt not supported with realtime devices\n"));
>  		usage();
>  	}
>  
> -	if (logsize) {
> -		uint64_t logbytes;
> -
> -		logbytes = getnum(logsize, &lopts, L_SIZE);
> +	if (logbytes) {
>  		if (logbytes % XFS_MIN_BLOCKSIZE) {
>  			fprintf(stderr,
>  			_("illegal log length %lld, not a multiple of %d\n"),
> @@ -2284,10 +2279,7 @@ _("rmapbt not supported with realtime devices\n"));
>  				(long long)logbytes, blocksize,
>  				(long long)(logblocks << blocklog));
>  	}
> -	if (rtsize) {
> -		uint64_t rtbytes;
> -
> -		rtbytes = getnum(rtsize, &ropts, R_SIZE);
> +	if (rtbytes) {
>  		if (rtbytes % XFS_MIN_BLOCKSIZE) {
>  			fprintf(stderr,
>  			_("illegal rt length %lld, not a multiple of %d\n"),
> @@ -2304,10 +2296,7 @@ _("rmapbt not supported with realtime devices\n"));
>  	/*
>  	 * If specified, check rt extent size against its constraints.
>  	 */
> -	if (rtextsize) {
> -		uint64_t rtextbytes;
> -
> -		rtextbytes = getnum(rtextsize, &ropts, R_EXTSIZE);
> +	if (rtextbytes) {
>  		if (rtextbytes % blocksize) {
>  			fprintf(stderr,
>  		_("illegal rt extent size %lld, not a multiple of %d\n"),
> @@ -2324,7 +2313,7 @@ _("rmapbt not supported with realtime devices\n"));
>  		uint64_t	rswidth;
>  		uint64_t	rtextbytes;
>  
> -		if (!norsflag && !xi.risfile && !(!rtsize && xi.disfile))
> +		if (!norsflag && !xi.risfile && !(!rtbytes && xi.disfile))
>  			rswidth = ft.rtswidth;
>  		else
>  			rswidth = 0;
> @@ -2439,15 +2428,16 @@ _("rmapbt not supported with realtime devices\n"));
>  		rtfile = _("volume rt");
>  	else if (!xi.rtdev)
>  		rtfile = _("none");
> -	if (dsize && xi.dsize > 0 && dblocks > DTOBT(xi.dsize)) {
> +	if (dbytes && xi.dsize > 0 && dblocks > DTOBT(xi.dsize)) {
>  		fprintf(stderr,
>  			_("size %s specified for data subvolume is too large, "
>  			"maximum is %lld blocks\n"),
> -			dsize, (long long)DTOBT(xi.dsize));
> +			get_conf_raw_safe(&dopts, D_SIZE),
> +			(long long)DTOBT(xi.dsize));
>  		usage();
> -	} else if (!dsize && xi.dsize > 0)
> +	} else if (!dbytes && xi.dsize > 0)
>  		dblocks = DTOBT(xi.dsize);
> -	else if (!dsize) {
> +	else if (!dbytes) {
>  		fprintf(stderr, _("can't get size of data subvolume\n"));
>  		usage();
>  	}
> @@ -2480,22 +2470,23 @@ reported by the device (%u).\n"),
>  reported by the device (%u).\n"),
>  			lsectorsize, xi.lbsize);
>  	}
> -	if (rtsize && xi.rtsize > 0 && xi.rtbsize > sectorsize) {
> +	if (rtbytes && xi.rtsize > 0 && xi.rtbsize > sectorsize) {
>  		fprintf(stderr, _(
>  "Warning: the realtime subvolume sector size %u is less than the sector size\n\
>  reported by the device (%u).\n"),
>  			sectorsize, xi.rtbsize);
>  	}
>  
> -	if (rtsize && xi.rtsize > 0 && rtblocks > DTOBT(xi.rtsize)) {
> +	if (rtbytes && xi.rtsize > 0 && rtblocks > DTOBT(xi.rtsize)) {
>  		fprintf(stderr,
>  			_("size %s specified for rt subvolume is too large, "
>  			"maximum is %lld blocks\n"),
> -			rtsize, (long long)DTOBT(xi.rtsize));
> +			get_conf_raw_safe(&ropts, R_SIZE),
> +			(long long)DTOBT(xi.rtsize));
>  		usage();
> -	} else if (!rtsize && xi.rtsize > 0)
> +	} else if (!rtbytes && xi.rtsize > 0)
>  		rtblocks = DTOBT(xi.rtsize);
> -	else if (rtsize && !xi.rtdev) {
> +	else if (rtbytes && !xi.rtdev) {
>  		fprintf(stderr,
>  			_("size specified for non-existent rt subvolume\n"));
>  		usage();
> @@ -2701,26 +2692,27 @@ an AG size that is one stripe unit smaller, for example %llu.\n"),
>  				   sb_feat.inode_align);
>  	ASSERT(min_logblocks);
>  	min_logblocks = MAX(XFS_MIN_LOG_BLOCKS, min_logblocks);
> -	if (!logsize && dblocks >= (1024*1024*1024) >> blocklog)
> +	if (!logbytes && dblocks >= (1024*1024*1024) >> blocklog)
>  		min_logblocks = MAX(min_logblocks, XFS_MIN_LOG_BYTES>>blocklog);
> -	if (logsize && xi.logBBsize > 0 && logblocks > DTOBT(xi.logBBsize)) {
> +	if (logbytes && xi.logBBsize > 0 && logblocks > DTOBT(xi.logBBsize)) {
>  		fprintf(stderr,
>  _("size %s specified for log subvolume is too large, maximum is %lld blocks\n"),
> -			logsize, (long long)DTOBT(xi.logBBsize));
> +			get_conf_raw_safe(&lopts, L_SIZE),
> +			(long long)DTOBT(xi.logBBsize));
>  		usage();
> -	} else if (!logsize && xi.logBBsize > 0) {
> +	} else if (!logbytes && xi.logBBsize > 0) {
>  		logblocks = DTOBT(xi.logBBsize);
> -	} else if (logsize && !xi.logdev && !loginternal) {
> +	} else if (logbytes && !xi.logdev && !loginternal) {
>  		fprintf(stderr,
>  			_("size specified for non-existent log subvolume\n"));
>  		usage();
> -	} else if (loginternal && logsize && logblocks >= dblocks) {
> +	} else if (loginternal && logbytes && logblocks >= dblocks) {
>  		fprintf(stderr, _("size %lld too large for internal log\n"),
>  			(long long)logblocks);
>  		usage();
>  	} else if (!loginternal && !xi.logdev) {
>  		logblocks = 0;
> -	} else if (loginternal && !logsize) {
> +	} else if (loginternal && !logbytes) {
>  
>  		if (dblocks < GIGABYTES(1, blocklog)) {
>  			/* tiny filesystems get minimum sized logs. */
> @@ -2784,7 +2776,7 @@ _("size %s specified for log subvolume is too large, maximum is %lld blocks\n"),
>  		 * Readjust the log size to fit within an AG if it was sized
>  		 * automatically.
>  		 */
> -		if (!logsize) {
> +		if (!logbytes) {
>  			logblocks = MIN(logblocks,
>  					libxfs_alloc_ag_max_usable(mp));
>  
> -- 
> 2.13.3
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 4/6] mkfs: merge tables for opts parsing into one table
  2017-08-11 12:30 ` [PATCH 4/6] mkfs: merge tables for opts parsing into one table Jan Tulak
@ 2017-08-14 23:06   ` Darrick J. Wong
  2017-08-15 10:05     ` Jan Tulak
  0 siblings, 1 reply; 37+ messages in thread
From: Darrick J. Wong @ 2017-08-14 23:06 UTC (permalink / raw)
  To: Jan Tulak; +Cc: linux-xfs

On Fri, Aug 11, 2017 at 02:30:35PM +0200, Jan Tulak wrote:
> Merge separate instances of opt_params into one indexable table. Git
> makes this patch looks a bit more complicated, but it does not change
> values or structure of anything else. It only moves all the "struct
> opt_params dopts = {...}", changes indentation for these substructures
> and replaces their usage (dopts -> opts[OPT_D]).
> 
> The reason for this is to be able to address all options from any single
> one, even across OPT_X. Right now, we can do automated conflict checks
> only within one OPT_X, but after this, it is possible to extend the
> conflict declaration to other options as well.
> 
> Signed-off-by: Jan Tulak <jtulak@redhat.com>
> ---
> Change:
>  * expand bounds check to newly added opt parameter in get/set functions
>  * updated description
> ---
>  mkfs/xfs_mkfs.c | 1341 +++++++++++++++++++++++++++++--------------------------
>  1 file changed, 696 insertions(+), 645 deletions(-)
> 
> diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
> index 78e27498..e3f7d345 100644
> --- a/mkfs/xfs_mkfs.c
> +++ b/mkfs/xfs_mkfs.c
> @@ -39,6 +39,7 @@ static int  ispow2(unsigned int i);
>  unsigned int		blocksize;
>  unsigned int		sectorsize;
>  
> +#define MAX_OPTS	16
>  #define MAX_SUBOPTS	16
>  #define SUBOPT_NEEDS_VAL	(-1LL)
>  #define MAX_CONFLICTS	8
> @@ -49,6 +50,10 @@ unsigned int		sectorsize;
>   *
>   * Description of the structure members follows:
>   *
> + * index MANDATORY
> + *   An integer denoting the position of the specific option in opts array,
> + *   counting from 0 up to MAX_OPTS.
> + *
>   * name MANDATORY
>   *   Name is a single char, e.g., for '-d file', name is 'd'.
>   *
> @@ -114,6 +119,7 @@ unsigned int		sectorsize;
>   *
>   */
>  struct opt_params {
> +	int		index;
>  	const char	name;
>  	const char	*subopts[MAX_SUBOPTS];
>  
> @@ -129,584 +135,592 @@ struct opt_params {
>  		long long	flagval;
>  		char		*raw_input;
>  	}		subopt_params[MAX_SUBOPTS];
> -};
> -
> -struct opt_params bopts = {
> -	.name = 'b',
> -	.subopts = {
> +} opts[MAX_OPTS] = {
> +#define OPT_B	0
> +	{
> +		.index = OPT_B,
> +		.name = 'b',
> +		.subopts = {
>  #define	B_LOG		0
> -		"log",
> +			"log",
>  #define	B_SIZE		1
> -		"size",
> -		NULL
> -	},
> -	.subopt_params = {
> -		{ .index = B_LOG,

I /really/ wish there was a way calculate these automatically, but I
don't think I know of any such way, at least not without using horrid
macros.

> -		  .conflicts = { B_SIZE,
> -				 LAST_CONFLICT },
> -		  .minval = XFS_MIN_BLOCKSIZE_LOG,
> -		  .maxval = XFS_MAX_BLOCKSIZE_LOG,
> -		  .flagval = SUBOPT_NEEDS_VAL,
> +			"size",
> +			NULL
>  		},
> -		{ .index = B_SIZE,
> -		  .convert = true,
> -		  .is_power_2 = true,
> -		  .conflicts = { B_LOG,
> -				 LAST_CONFLICT },
> -		  .minval = XFS_MIN_BLOCKSIZE,
> -		  .maxval = XFS_MAX_BLOCKSIZE,
> -		  .flagval = SUBOPT_NEEDS_VAL,
> +		.subopt_params = {
> +			{ .index = B_LOG,
> +			  .conflicts = { B_SIZE,
> +					 LAST_CONFLICT },
> +			  .minval = XFS_MIN_BLOCKSIZE_LOG,
> +			  .maxval = XFS_MAX_BLOCKSIZE_LOG,
> +			  .flagval = SUBOPT_NEEDS_VAL,
> +			},
> +			{ .index = B_SIZE,
> +			  .convert = true,
> +			  .is_power_2 = true,
> +			  .conflicts = { B_LOG,
> +					 LAST_CONFLICT },
> +			  .minval = XFS_MIN_BLOCKSIZE,
> +			  .maxval = XFS_MAX_BLOCKSIZE,
> +			  .flagval = SUBOPT_NEEDS_VAL,
> +			},
>  		},
>  	},
> -};
> -
> -struct opt_params dopts = {
> -	.name = 'd',
> -	.subopts = {
> -#define	D_AGCOUNT	0
> -		"agcount",
> -#define	D_FILE		1
> -		"file",
> -#define	D_NAME		2
> -		"name",
> -#define	D_SIZE		3
> -		"size",
> -#define D_SUNIT		4
> -		"sunit",
> -#define D_SWIDTH	5
> -		"swidth",
> -#define D_AGSIZE	6
> -		"agsize",
> -#define D_SU		7
> -		"su",
> -#define D_SW		8
> -		"sw",
> -#define D_SECTLOG	9
> -		"sectlog",
> -#define D_SECTSIZE	10
> -		"sectsize",
> -#define D_NOALIGN	11
> -		"noalign",
> -#define D_RTINHERIT	12
> -		"rtinherit",
> -#define D_PROJINHERIT	13
> -		"projinherit",
> -#define D_EXTSZINHERIT	14
> -		"extszinherit",
> -		NULL
> -	},
> -	.subopt_params = {
> -		{ .index = D_AGCOUNT,
> -		  .conflicts = { D_AGSIZE,
> -				 LAST_CONFLICT },
> -		  .minval = 1,
> -		  .maxval = XFS_MAX_AGNUMBER,
> -		  .flagval = SUBOPT_NEEDS_VAL,
> -		},
> -		{ .index = D_FILE,
> -		  .conflicts = { LAST_CONFLICT },
> -		  .minval = 0,
> -		  .maxval = 1,
> -		  .flagval = 1,
> -		},
> -		{ .index = D_NAME,
> -		  .conflicts = { LAST_CONFLICT },
> -		  .flagval = SUBOPT_NEEDS_VAL,
> -		},
> -		{ .index = D_SIZE,
> -		  .conflicts = { LAST_CONFLICT },
> -		  .convert = true,
> -		  .minval = XFS_AG_MIN_BYTES,
> -		  .maxval = LLONG_MAX,
> -		  .flagval = SUBOPT_NEEDS_VAL,
> -		},
> -		{ .index = D_SUNIT,
> -		  .conflicts = { D_NOALIGN,
> -				 D_SU,
> -				 D_SW,
> -				 LAST_CONFLICT },
> -		  .minval = 0,
> -		  .maxval = UINT_MAX,
> -		  .flagval = SUBOPT_NEEDS_VAL,
> -		},
> -		{ .index = D_SWIDTH,
> -		  .conflicts = { D_NOALIGN,
> -				 D_SU,
> -				 D_SW,
> -				 LAST_CONFLICT },
> -		  .minval = 0,
> -		  .maxval = UINT_MAX,
> -		  .flagval = SUBOPT_NEEDS_VAL,
> -		},
> -		{ .index = D_AGSIZE,
> -		  .conflicts = { D_AGCOUNT,
> -				 LAST_CONFLICT },
> -		  .convert = true,
> -		  .minval = XFS_AG_MIN_BYTES,
> -		  .maxval = XFS_AG_MAX_BYTES,
> -		  .flagval = SUBOPT_NEEDS_VAL,
> -		},
> -		{ .index = D_SU,
> -		  .conflicts = { D_NOALIGN,
> -				 D_SUNIT,
> -				 D_SWIDTH,
> -				 LAST_CONFLICT },
> -		  .convert = true,
> -		  .minval = 0,
> -		  .maxval = UINT_MAX,
> -		  .flagval = SUBOPT_NEEDS_VAL,
> -		},
> -		{ .index = D_SW,
> -		  .conflicts = { D_NOALIGN,
> -				 D_SUNIT,
> -				 D_SWIDTH,
> -				 LAST_CONFLICT },
> -		  .minval = 0,
> -		  .maxval = UINT_MAX,
> -		  .flagval = SUBOPT_NEEDS_VAL,
> -		},
> -		{ .index = D_SECTLOG,
> -		  .conflicts = { D_SECTSIZE,
> -				 LAST_CONFLICT },
> -		  .minval = XFS_MIN_SECTORSIZE_LOG,
> -		  .maxval = XFS_MAX_SECTORSIZE_LOG,
> -		  .flagval = SUBOPT_NEEDS_VAL,
> -		},
> -		{ .index = D_SECTSIZE,
> -		  .conflicts = { D_SECTLOG,
> -				 LAST_CONFLICT },
> -		  .convert = true,
> -		  .is_power_2 = true,
> -		  .minval = XFS_MIN_SECTORSIZE,
> -		  .maxval = XFS_MAX_SECTORSIZE,
> -		  .flagval = SUBOPT_NEEDS_VAL,
> +#define OPT_D	1
> +	{
> +		.index = OPT_D,
> +		.name = 'd',
> +		.subopts = {
> +	#define	D_AGCOUNT	0
> +			"agcount",
> +	#define	D_FILE		1
> +			"file",
> +	#define	D_NAME		2
> +			"name",
> +	#define	D_SIZE		3
> +			"size",
> +	#define D_SUNIT		4
> +			"sunit",
> +	#define D_SWIDTH	5
> +			"swidth",
> +	#define D_AGSIZE	6
> +			"agsize",
> +	#define D_SU		7
> +			"su",
> +	#define D_SW		8
> +			"sw",
> +	#define D_SECTLOG	9
> +			"sectlog",
> +	#define D_SECTSIZE	10
> +			"sectsize",
> +	#define D_NOALIGN	11
> +			"noalign",
> +	#define D_RTINHERIT	12
> +			"rtinherit",
> +	#define D_PROJINHERIT	13
> +			"projinherit",
> +	#define D_EXTSZINHERIT	14
> +			"extszinherit",
> +			NULL
>  		},
> -		{ .index = D_NOALIGN,
> -		  .conflicts = { D_SU,
> -				 D_SW,
> -				 D_SUNIT,
> -				 D_SWIDTH,
> -				 LAST_CONFLICT },
> -		  .minval = 0,
> -		  .maxval = 1,
> -		  .flagval = 1,
> -		},
> -		{ .index = D_RTINHERIT,
> -		  .conflicts = { LAST_CONFLICT },
> -		  .minval = 1,
> -		  .maxval = 1,
> -		  .flagval = 1,
> -		},
> -		{ .index = D_PROJINHERIT,
> -		  .conflicts = { LAST_CONFLICT },
> -		  .minval = 0,
> -		  .maxval = UINT_MAX,
> -		  .flagval = SUBOPT_NEEDS_VAL,
> -		},
> -		{ .index = D_EXTSZINHERIT,
> -		  .conflicts = { LAST_CONFLICT },
> -		  .minval = 0,
> -		  .maxval = UINT_MAX,
> -		  .flagval = SUBOPT_NEEDS_VAL,
> +		.subopt_params = {
> +			{ .index = D_AGCOUNT,
> +			  .conflicts = { D_AGSIZE,
> +					 LAST_CONFLICT },
> +			  .minval = 1,
> +			  .maxval = XFS_MAX_AGNUMBER,
> +			  .flagval = SUBOPT_NEEDS_VAL,
> +			},
> +			{ .index = D_FILE,
> +			  .conflicts = { LAST_CONFLICT },
> +			  .minval = 0,
> +			  .maxval = 1,
> +			  .flagval = 1,
> +			},
> +			{ .index = D_NAME,
> +			  .conflicts = { LAST_CONFLICT },
> +			  .flagval = SUBOPT_NEEDS_VAL,
> +			},
> +			{ .index = D_SIZE,
> +			  .conflicts = { LAST_CONFLICT },
> +			  .convert = true,
> +			  .minval = XFS_AG_MIN_BYTES,
> +			  .maxval = LLONG_MAX,
> +			  .flagval = SUBOPT_NEEDS_VAL,
> +			},
> +			{ .index = D_SUNIT,
> +			  .conflicts = { D_NOALIGN,
> +					 D_SU,
> +					 D_SW,
> +					 LAST_CONFLICT },
> +			  .minval = 0,
> +			  .maxval = UINT_MAX,
> +			  .flagval = SUBOPT_NEEDS_VAL,
> +			},
> +			{ .index = D_SWIDTH,
> +			  .conflicts = { D_NOALIGN,
> +					 D_SU,
> +					 D_SW,
> +					 LAST_CONFLICT },
> +			  .minval = 0,
> +			  .maxval = UINT_MAX,
> +			  .flagval = SUBOPT_NEEDS_VAL,
> +			},
> +			{ .index = D_AGSIZE,
> +			  .conflicts = { D_AGCOUNT,
> +					 LAST_CONFLICT },
> +			  .convert = true,
> +			  .minval = XFS_AG_MIN_BYTES,
> +			  .maxval = XFS_AG_MAX_BYTES,
> +			  .flagval = SUBOPT_NEEDS_VAL,
> +			},
> +			{ .index = D_SU,
> +			  .conflicts = { D_NOALIGN,
> +					 D_SUNIT,
> +					 D_SWIDTH,
> +					 LAST_CONFLICT },
> +			  .convert = true,
> +			  .minval = 0,
> +			  .maxval = UINT_MAX,
> +			  .flagval = SUBOPT_NEEDS_VAL,
> +			},
> +			{ .index = D_SW,
> +			  .conflicts = { D_NOALIGN,
> +					 D_SUNIT,
> +					 D_SWIDTH,
> +					 LAST_CONFLICT },
> +			  .minval = 0,
> +			  .maxval = UINT_MAX,
> +			  .flagval = SUBOPT_NEEDS_VAL,
> +			},
> +			{ .index = D_SECTLOG,
> +			  .conflicts = { D_SECTSIZE,
> +					 LAST_CONFLICT },
> +			  .minval = XFS_MIN_SECTORSIZE_LOG,
> +			  .maxval = XFS_MAX_SECTORSIZE_LOG,
> +			  .flagval = SUBOPT_NEEDS_VAL,
> +			},
> +			{ .index = D_SECTSIZE,
> +			  .conflicts = { D_SECTLOG,
> +					 LAST_CONFLICT },
> +			  .convert = true,
> +			  .is_power_2 = true,
> +			  .minval = XFS_MIN_SECTORSIZE,
> +			  .maxval = XFS_MAX_SECTORSIZE,
> +			  .flagval = SUBOPT_NEEDS_VAL,
> +			},
> +			{ .index = D_NOALIGN,
> +			  .conflicts = { D_SU,
> +					 D_SW,
> +					 D_SUNIT,
> +					 D_SWIDTH,
> +					 LAST_CONFLICT },
> +			  .minval = 0,
> +			  .maxval = 1,
> +			  .flagval = 1,
> +			},
> +			{ .index = D_RTINHERIT,
> +			  .conflicts = { LAST_CONFLICT },
> +			  .minval = 0,
> +			  .maxval = 1,
> +			  .flagval = 1,
> +			},
> +			{ .index = D_PROJINHERIT,
> +			  .conflicts = { LAST_CONFLICT },
> +			  .minval = 0,
> +			  .maxval = UINT_MAX,
> +			  .flagval = SUBOPT_NEEDS_VAL,
> +			},
> +			{ .index = D_EXTSZINHERIT,
> +			  .conflicts = { LAST_CONFLICT },
> +			  .minval = 0,
> +			  .maxval = UINT_MAX,
> +			  .flagval = SUBOPT_NEEDS_VAL,
> +			},
>  		},
>  	},
> -};
> -
> -
> -struct opt_params iopts = {
> -	.name = 'i',
> -	.subopts = {
> +#define OPT_I	2
> +	{
> +		.index = OPT_I,
> +		.name = 'i',
> +		.subopts = {
>  #define	I_ALIGN		0
> -		"align",
> +			"align",
>  #define	I_LOG		1
> -		"log",
> +			"log",
>  #define	I_MAXPCT	2
> -		"maxpct",
> +			"maxpct",
>  #define	I_PERBLOCK	3
> -		"perblock",
> +			"perblock",
>  #define	I_SIZE		4
> -		"size",
> +			"size",
>  #define	I_ATTR		5
> -		"attr",
> +			"attr",
>  #define	I_PROJID32BIT	6
> -		"projid32bit",
> +			"projid32bit",
>  #define I_SPINODES	7
> -		"sparse",
> -		NULL
> -	},
> -	.subopt_params = {
> -		{ .index = I_ALIGN,
> -		  .conflicts = { LAST_CONFLICT },
> -		  .minval = 0,
> -		  .maxval = 1,
> -		  .flagval = 1,
> -		},
> -		{ .index = I_LOG,
> -		  .conflicts = { I_PERBLOCK,
> -				 I_SIZE,
> -				 LAST_CONFLICT },
> -		  .minval = XFS_DINODE_MIN_LOG,
> -		  .maxval = XFS_DINODE_MAX_LOG,
> -		  .flagval = SUBOPT_NEEDS_VAL,
> -		},
> -		{ .index = I_MAXPCT,
> -		  .conflicts = { LAST_CONFLICT },
> -		  .minval = 0,
> -		  .maxval = 100,
> -		  .flagval = SUBOPT_NEEDS_VAL,
> +			"sparse",
> +			NULL
>  		},
> -		{ .index = I_PERBLOCK,
> -		  .conflicts = { I_LOG,
> -				 I_SIZE,
> -				 LAST_CONFLICT },
> -		  .is_power_2 = true,
> -		  .minval = XFS_MIN_INODE_PERBLOCK,
> -		  .maxval = XFS_MAX_BLOCKSIZE / XFS_DINODE_MIN_SIZE,
> -		  .flagval = SUBOPT_NEEDS_VAL,
> -		},
> -		{ .index = I_SIZE,
> -		  .conflicts = { I_PERBLOCK,
> -				 I_LOG,
> -				 LAST_CONFLICT },
> -		  .is_power_2 = true,
> -		  .minval = XFS_DINODE_MIN_SIZE,
> -		  .maxval = XFS_DINODE_MAX_SIZE,
> -		  .flagval = SUBOPT_NEEDS_VAL,
> -		},
> -		{ .index = I_ATTR,
> -		  .conflicts = { LAST_CONFLICT },
> -		  .minval = 0,
> -		  .maxval = 2,
> -		  .flagval = SUBOPT_NEEDS_VAL,
> -		},
> -		{ .index = I_PROJID32BIT,
> -		  .conflicts = { LAST_CONFLICT },
> -		  .minval = 0,
> -		  .maxval = 1,
> -		  .flagval = 1,
> -		},
> -		{ .index = I_SPINODES,
> -		  .conflicts = { LAST_CONFLICT },
> -		  .minval = 0,
> -		  .maxval = 1,
> -		  .flagval = 1,
> +		.subopt_params = {
> +			{ .index = I_ALIGN,
> +			  .conflicts = { LAST_CONFLICT },
> +			  .minval = 0,
> +			  .maxval = 1,
> +			  .flagval = 1,
> +			},
> +			{ .index = I_LOG,
> +			  .conflicts = { I_PERBLOCK,
> +					 I_SIZE,
> +					 LAST_CONFLICT },
> +			  .minval = XFS_DINODE_MIN_LOG,
> +			  .maxval = XFS_DINODE_MAX_LOG,
> +			  .flagval = SUBOPT_NEEDS_VAL,
> +			},
> +			{ .index = I_MAXPCT,
> +			  .conflicts = { LAST_CONFLICT },
> +			  .minval = 0,
> +			  .maxval = 100,
> +			  .flagval = SUBOPT_NEEDS_VAL,
> +			},
> +			{ .index = I_PERBLOCK,
> +			  .conflicts = { I_LOG,
> +					 I_SIZE,
> +					 LAST_CONFLICT },
> +			  .is_power_2 = true,
> +			  .minval = XFS_MIN_INODE_PERBLOCK,
> +			  .maxval = XFS_MAX_BLOCKSIZE / XFS_DINODE_MIN_SIZE,
> +			  .flagval = SUBOPT_NEEDS_VAL,
> +			},
> +			{ .index = I_SIZE,
> +			  .conflicts = { I_PERBLOCK,
> +					 I_LOG,
> +					 LAST_CONFLICT },
> +			  .is_power_2 = true,
> +			  .minval = XFS_DINODE_MIN_SIZE,
> +			  .maxval = XFS_DINODE_MAX_SIZE,
> +			  .flagval = SUBOPT_NEEDS_VAL,
> +			},
> +			{ .index = I_ATTR,
> +			  .conflicts = { LAST_CONFLICT },
> +			  .minval = 0,
> +			  .maxval = 2,
> +			  .flagval = SUBOPT_NEEDS_VAL,
> +			},
> +			{ .index = I_PROJID32BIT,
> +			  .conflicts = { LAST_CONFLICT },
> +			  .minval = 0,
> +			  .maxval = 1,
> +			  .flagval = 1,
> +			},
> +			{ .index = I_SPINODES,
> +			  .conflicts = { LAST_CONFLICT },
> +			  .minval = 0,
> +			  .maxval = 1,
> +			  .flagval = 1,
> +			},
>  		},
>  	},
> -};
> -
> -struct opt_params lopts = {
> -	.name = 'l',
> -	.subopts = {
> -#define	L_AGNUM		0
> -		"agnum",
> -#define	L_INTERNAL	1
> -		"internal",
> -#define	L_SIZE		2
> -		"size",
> -#define L_VERSION	3
> -		"version",
> -#define L_SUNIT		4
> -		"sunit",
> -#define L_SU		5
> -		"su",
> -#define L_DEV		6
> -		"logdev",
> -#define	L_SECTLOG	7
> -		"sectlog",
> -#define	L_SECTSIZE	8
> -		"sectsize",
> -#define	L_FILE		9
> -		"file",
> -#define	L_NAME		10
> -		"name",
> -#define	L_LAZYSBCNTR	11
> -		"lazy-count",
> -		NULL
> -	},
> -	.subopt_params = {
> -		{ .index = L_AGNUM,
> -		  .conflicts = { L_DEV,
> -				 LAST_CONFLICT },
> -		  .minval = 0,
> -		  .maxval = UINT_MAX,
> -		  .flagval = SUBOPT_NEEDS_VAL,
> -		},
> -		{ .index = L_INTERNAL,
> -		  .conflicts = { L_FILE,
> -				 L_DEV,
> -				 LAST_CONFLICT },
> -		  .minval = 0,
> -		  .maxval = 1,
> -		  .flagval = 1,
> +#define OPT_L	3
> +	{
> +		.index = OPT_L,
> +		.name = 'l',
> +		.subopts = {
> +	#define	L_AGNUM		0
> +			"agnum",
> +	#define	L_INTERNAL	1
> +			"internal",
> +	#define	L_SIZE		2
> +			"size",
> +	#define L_VERSION	3
> +			"version",
> +	#define L_SUNIT		4
> +			"sunit",
> +	#define L_SU		5
> +			"su",
> +	#define L_DEV		6
> +			"logdev",
> +	#define	L_SECTLOG	7
> +			"sectlog",
> +	#define	L_SECTSIZE	8
> +			"sectsize",
> +	#define	L_FILE		9
> +			"file",
> +	#define	L_NAME		10
> +			"name",
> +	#define	L_LAZYSBCNTR	11
> +			"lazy-count",
> +			NULL
>  		},
> -		{ .index = L_SIZE,
> -		  .conflicts = { LAST_CONFLICT },
> -		  .convert = true,
> -		  .minval = 2 * 1024 * 1024LL,	/* XXX: XFS_MIN_LOG_BYTES */
> -		  .maxval = XFS_MAX_LOG_BYTES,
> -		  .flagval = SUBOPT_NEEDS_VAL,
> -		},
> -		{ .index = L_VERSION,
> -		  .conflicts = { LAST_CONFLICT },
> -		  .minval = 1,
> -		  .maxval = 2,
> -		  .flagval = SUBOPT_NEEDS_VAL,
> -		},
> -		{ .index = L_SUNIT,
> -		  .conflicts = { L_SU,
> -				 LAST_CONFLICT },
> -		  .minval = 1,
> -		  .maxval = BTOBB(XLOG_MAX_RECORD_BSIZE),
> -		  .flagval = SUBOPT_NEEDS_VAL,
> -		},
> -		{ .index = L_SU,
> -		  .conflicts = { L_SUNIT,
> -				 LAST_CONFLICT },
> -		  .convert = true,
> -		  .minval = BBTOB(1),
> -		  .maxval = XLOG_MAX_RECORD_BSIZE,
> -		  .flagval = SUBOPT_NEEDS_VAL,
> -		},
> -		{ .index = L_DEV,
> -		  .conflicts = { L_AGNUM,
> -				 L_INTERNAL,
> -				 LAST_CONFLICT },
> -		  .flagval = SUBOPT_NEEDS_VAL,
> -		},
> -		{ .index = L_SECTLOG,
> -		  .conflicts = { L_SECTSIZE,
> -				 LAST_CONFLICT },
> -		  .minval = XFS_MIN_SECTORSIZE_LOG,
> -		  .maxval = XFS_MAX_SECTORSIZE_LOG,
> -		  .flagval = SUBOPT_NEEDS_VAL,
> -		},
> -		{ .index = L_SECTSIZE,
> -		  .conflicts = { L_SECTLOG,
> -				 LAST_CONFLICT },
> -		  .convert = true,
> -		  .is_power_2 = true,
> -		  .minval = XFS_MIN_SECTORSIZE,
> -		  .maxval = XFS_MAX_SECTORSIZE,
> -		  .flagval = SUBOPT_NEEDS_VAL,
> -		},
> -		{ .index = L_FILE,
> -		  .conflicts = { L_INTERNAL,
> -				 LAST_CONFLICT },
> -		  .minval = 0,
> -		  .maxval = 1,
> -		  .flagval = 1,
> -		},
> -		{ .index = L_NAME,
> -		  .conflicts = { L_AGNUM,
> -				 L_INTERNAL,
> -				 LAST_CONFLICT },
> -		  .flagval = SUBOPT_NEEDS_VAL,
> -		},
> -		{ .index = L_LAZYSBCNTR,
> -		  .conflicts = { LAST_CONFLICT },
> -		  .minval = 0,
> -		  .maxval = 1,
> -		  .flagval = 1,
> +		.subopt_params = {
> +			{ .index = L_AGNUM,
> +			  .conflicts = { L_DEV,
> +					 LAST_CONFLICT },
> +			  .minval = 0,
> +			  .maxval = UINT_MAX,
> +			  .flagval = SUBOPT_NEEDS_VAL,
> +			},
> +			{ .index = L_INTERNAL,
> +			  .conflicts = { L_FILE,
> +					 L_DEV,
> +					 LAST_CONFLICT },
> +			  .minval = 0,
> +			  .maxval = 1,
> +			  .flagval = 1,
> +			},
> +			{ .index = L_SIZE,
> +			  .conflicts = { LAST_CONFLICT },
> +			  .convert = true,
> +			  .minval = 2 * 1024 * 1024LL,	/* XXX: XFS_MIN_LOG_BYTES */

I recognize that this is a mechanical translation patch, but why does
this setter have an XXX comment for a #define that actually exists?  And
why does the value used differ??

If this needs fixing, please do it as a separate patch.

As far as this one goes,
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>

> +			  .maxval = XFS_MAX_LOG_BYTES,
> +			  .flagval = SUBOPT_NEEDS_VAL,
> +			},
> +			{ .index = L_VERSION,
> +			  .conflicts = { LAST_CONFLICT },
> +			  .minval = 1,
> +			  .maxval = 2,
> +			  .flagval = SUBOPT_NEEDS_VAL,
> +			},
> +			{ .index = L_SUNIT,
> +			  .conflicts = { L_SU,
> +					 LAST_CONFLICT },
> +			  .minval = 1,
> +			  .maxval = BTOBB(XLOG_MAX_RECORD_BSIZE),
> +			  .flagval = SUBOPT_NEEDS_VAL,
> +			},
> +			{ .index = L_SU,
> +			  .conflicts = { L_SUNIT,
> +					 LAST_CONFLICT },
> +			  .convert = true,
> +			  .minval = BBTOB(1),
> +			  .maxval = XLOG_MAX_RECORD_BSIZE,
> +			  .flagval = SUBOPT_NEEDS_VAL,
> +			},
> +			{ .index = L_DEV,
> +			  .conflicts = { L_AGNUM,
> +					 L_INTERNAL,
> +					 LAST_CONFLICT },
> +			  .flagval = SUBOPT_NEEDS_VAL,
> +			},
> +			{ .index = L_SECTLOG,
> +			  .conflicts = { L_SECTSIZE,
> +					 LAST_CONFLICT },
> +			  .minval = XFS_MIN_SECTORSIZE_LOG,
> +			  .maxval = XFS_MAX_SECTORSIZE_LOG,
> +			  .flagval = SUBOPT_NEEDS_VAL,
> +			},
> +			{ .index = L_SECTSIZE,
> +			  .conflicts = { L_SECTLOG,
> +					 LAST_CONFLICT },
> +			  .convert = true,
> +			  .is_power_2 = true,
> +			  .minval = XFS_MIN_SECTORSIZE,
> +			  .maxval = XFS_MAX_SECTORSIZE,
> +			  .flagval = SUBOPT_NEEDS_VAL,
> +			},
> +			{ .index = L_FILE,
> +			  .conflicts = { L_INTERNAL,
> +					 LAST_CONFLICT },
> +			  .minval = 0,
> +			  .maxval = 1,
> +			  .flagval = 1,
> +			},
> +			{ .index = L_NAME,
> +			  .conflicts = { L_AGNUM,
> +					 L_INTERNAL,
> +					 LAST_CONFLICT },
> +			  .flagval = SUBOPT_NEEDS_VAL,
> +			},
> +			{ .index = L_LAZYSBCNTR,
> +			  .conflicts = { LAST_CONFLICT },
> +			  .minval = 0,
> +			  .maxval = 1,
> +			  .flagval = 1,
> +			},
>  		},
>  	},
> -};
> -
> -struct opt_params nopts = {
> -	.name = 'n',
> -	.subopts = {
> -#define	N_LOG		0
> -		"log",
> -#define	N_SIZE		1
> -		"size",
> -#define	N_VERSION	2
> -		"version",
> -#define	N_FTYPE		3
> -		"ftype",
> -	NULL,
> -	},
> -	.subopt_params = {
> -		{ .index = N_LOG,
> -		  .conflicts = { N_SIZE,
> -				 LAST_CONFLICT },
> -		  .minval = XFS_MIN_REC_DIRSIZE,
> -		  .maxval = XFS_MAX_BLOCKSIZE_LOG,
> -		  .flagval = SUBOPT_NEEDS_VAL,
> -		},
> -		{ .index = N_SIZE,
> -		  .conflicts = { N_LOG,
> -				 LAST_CONFLICT },
> -		  .convert = true,
> -		  .is_power_2 = true,
> -		  .minval = 1 << XFS_MIN_REC_DIRSIZE,
> -		  .maxval = XFS_MAX_BLOCKSIZE,
> -		  .flagval = SUBOPT_NEEDS_VAL,
> +#define OPT_N	4
> +	{
> +		.index = OPT_N,
> +		.name = 'n',
> +		.subopts = {
> +	#define	N_LOG		0
> +			"log",
> +	#define	N_SIZE		1
> +			"size",
> +	#define	N_VERSION	2
> +			"version",
> +	#define	N_FTYPE		3
> +			"ftype",
> +		NULL,
>  		},
> -		{ .index = N_VERSION,
> -		  .conflicts = { LAST_CONFLICT },
> -		  .minval = 2,
> -		  .maxval = 2,
> -		  .flagval = SUBOPT_NEEDS_VAL,
> +		.subopt_params = {
> +			{ .index = N_LOG,
> +			  .conflicts = { N_SIZE,
> +					 LAST_CONFLICT },
> +			  .minval = XFS_MIN_REC_DIRSIZE,
> +			  .maxval = XFS_MAX_BLOCKSIZE_LOG,
> +			  .flagval = SUBOPT_NEEDS_VAL,
> +			},
> +			{ .index = N_SIZE,
> +			  .conflicts = { N_LOG,
> +					 LAST_CONFLICT },
> +			  .convert = true,
> +			  .is_power_2 = true,
> +			  .minval = 1 << XFS_MIN_REC_DIRSIZE,
> +			  .maxval = XFS_MAX_BLOCKSIZE,
> +			  .flagval = SUBOPT_NEEDS_VAL,
> +			},
> +			{ .index = N_VERSION,
> +			  .conflicts = { LAST_CONFLICT },
> +			  .minval = 2,
> +			  .maxval = 2,
> +			  .flagval = SUBOPT_NEEDS_VAL,
> +			},
> +			{ .index = N_FTYPE,
> +			  .conflicts = { LAST_CONFLICT },
> +			  .minval = 0,
> +			  .maxval = 1,
> +			  .flagval = 1,
> +			},
>  		},
> -		{ .index = N_FTYPE,
> -		  .conflicts = { LAST_CONFLICT },
> -		  .minval = 0,
> -		  .maxval = 1,
> -		  .flagval = 1,
> -		},
> -	},
> -};
> -
> -struct opt_params ropts = {
> -	.name = 'r',
> -	.subopts = {
> -#define	R_EXTSIZE	0
> -		"extsize",
> -#define	R_SIZE		1
> -		"size",
> -#define	R_DEV		2
> -		"rtdev",
> -#define	R_FILE		3
> -		"file",
> -#define	R_NAME		4
> -		"name",
> -#define R_NOALIGN	5
> -		"noalign",
> -		NULL
>  	},
> -	.subopt_params = {
> -		{ .index = R_EXTSIZE,
> -		  .conflicts = { LAST_CONFLICT },
> -		  .convert = true,
> -		  .minval = XFS_MIN_RTEXTSIZE,
> -		  .maxval = XFS_MAX_RTEXTSIZE,
> -		  .flagval = SUBOPT_NEEDS_VAL,
> +#define OPT_R	5
> +	{
> +		.index = OPT_R,
> +		.name = 'r',
> +		.subopts = {
> +	#define	R_EXTSIZE	0
> +			"extsize",
> +	#define	R_SIZE		1
> +			"size",
> +	#define	R_DEV		2
> +			"rtdev",
> +	#define	R_FILE		3
> +			"file",
> +	#define	R_NAME		4
> +			"name",
> +	#define R_NOALIGN	5
> +			"noalign",
> +			NULL
>  		},
> -		{ .index = R_SIZE,
> -		  .conflicts = { LAST_CONFLICT },
> -		  .convert = true,
> -		  .minval = 0,
> -		  .maxval = LLONG_MAX,
> -		  .flagval = SUBOPT_NEEDS_VAL,
> -		},
> -		{ .index = R_DEV,
> -		  .conflicts = { LAST_CONFLICT },
> -		  .flagval = SUBOPT_NEEDS_VAL,
> -		},
> -		{ .index = R_FILE,
> -		  .minval = 0,
> -		  .maxval = 1,
> -		  .flagval = 1,
> -		  .conflicts = { LAST_CONFLICT },
> -		},
> -		{ .index = R_NAME,
> -		  .conflicts = { LAST_CONFLICT },
> -		  .flagval = SUBOPT_NEEDS_VAL,
> -		},
> -		{ .index = R_NOALIGN,
> -		  .minval = 0,
> -		  .maxval = 1,
> -		  .flagval = 1,
> -		  .conflicts = { LAST_CONFLICT },
> +		.subopt_params = {
> +			{ .index = R_EXTSIZE,
> +			  .conflicts = { LAST_CONFLICT },
> +			  .convert = true,
> +			  .minval = XFS_MIN_RTEXTSIZE,
> +			  .maxval = XFS_MAX_RTEXTSIZE,
> +			  .flagval = SUBOPT_NEEDS_VAL,
> +			},
> +			{ .index = R_SIZE,
> +			  .conflicts = { LAST_CONFLICT },
> +			  .convert = true,
> +			  .minval = 0,
> +			  .maxval = LLONG_MAX,
> +			  .flagval = SUBOPT_NEEDS_VAL,
> +			},
> +			{ .index = R_DEV,
> +			  .conflicts = { LAST_CONFLICT },
> +			  .flagval = SUBOPT_NEEDS_VAL,
> +			},
> +			{ .index = R_FILE,
> +			  .minval = 0,
> +			  .maxval = 1,
> +			  .flagval = 1,
> +			  .conflicts = { LAST_CONFLICT },
> +			},
> +			{ .index = R_NAME,
> +			  .conflicts = { LAST_CONFLICT },
> +			  .flagval = SUBOPT_NEEDS_VAL,
> +			},
> +			{ .index = R_NOALIGN,
> +			  .minval = 0,
> +			  .maxval = 1,
> +			  .flagval = 1,
> +			  .conflicts = { LAST_CONFLICT },
> +			},
>  		},
>  	},
> -};
> -
> -struct opt_params sopts = {
> -	.name = 's',
> -	.subopts = {
> -#define	S_LOG		0
> -		"log",
> -#define	S_SECTLOG	1
> -		"sectlog",
> -#define	S_SIZE		2
> -		"size",
> -#define	S_SECTSIZE	3
> -		"sectsize",
> -		NULL
> -	},
> -	.subopt_params = {
> -		{ .index = S_LOG,
> -		  .conflicts = { S_SIZE,
> -				 S_SECTSIZE,
> -				 LAST_CONFLICT },
> -		  .minval = XFS_MIN_SECTORSIZE_LOG,
> -		  .maxval = XFS_MAX_SECTORSIZE_LOG,
> -		  .flagval = SUBOPT_NEEDS_VAL,
> -		},
> -		{ .index = S_SECTLOG,
> -		  .conflicts = { S_SIZE,
> -				 S_SECTSIZE,
> -				 LAST_CONFLICT },
> -		  .minval = XFS_MIN_SECTORSIZE_LOG,
> -		  .maxval = XFS_MAX_SECTORSIZE_LOG,
> -		  .flagval = SUBOPT_NEEDS_VAL,
> -		},
> -		{ .index = S_SIZE,
> -		  .conflicts = { S_LOG,
> -				 S_SECTLOG,
> -				 LAST_CONFLICT },
> -		  .convert = true,
> -		  .is_power_2 = true,
> -		  .minval = XFS_MIN_SECTORSIZE,
> -		  .maxval = XFS_MAX_SECTORSIZE,
> -		  .flagval = SUBOPT_NEEDS_VAL,
> +#define OPT_S	6
> +	{
> +		.index = OPT_S,
> +		.name = 's',
> +		.subopts = {
> +	#define	S_LOG		0
> +			"log",
> +	#define	S_SECTLOG	1
> +			"sectlog",
> +	#define	S_SIZE		2
> +			"size",
> +	#define	S_SECTSIZE	3
> +			"sectsize",
> +			NULL
>  		},
> -		{ .index = S_SECTSIZE,
> -		  .conflicts = { S_LOG,
> -				 S_SECTLOG,
> -				 LAST_CONFLICT },
> -		  .convert = true,
> -		  .is_power_2 = true,
> -		  .minval = XFS_MIN_SECTORSIZE,
> -		  .maxval = XFS_MAX_SECTORSIZE,
> -		  .flagval = SUBOPT_NEEDS_VAL,
> +		.subopt_params = {
> +			{ .index = S_LOG,
> +			  .conflicts = { S_SIZE,
> +					 S_SECTSIZE,
> +					 LAST_CONFLICT },
> +			  .minval = XFS_MIN_SECTORSIZE_LOG,
> +			  .maxval = XFS_MAX_SECTORSIZE_LOG,
> +			  .flagval = SUBOPT_NEEDS_VAL,
> +			},
> +			{ .index = S_SECTLOG,
> +			  .conflicts = { S_SIZE,
> +					 S_SECTSIZE,
> +					 LAST_CONFLICT },
> +			  .minval = XFS_MIN_SECTORSIZE_LOG,
> +			  .maxval = XFS_MAX_SECTORSIZE_LOG,
> +			  .flagval = SUBOPT_NEEDS_VAL,
> +			},
> +			{ .index = S_SIZE,
> +			  .conflicts = { S_LOG,
> +					 S_SECTLOG,
> +					 LAST_CONFLICT },
> +			  .convert = true,
> +			  .is_power_2 = true,
> +			  .minval = XFS_MIN_SECTORSIZE,
> +			  .maxval = XFS_MAX_SECTORSIZE,
> +			  .flagval = SUBOPT_NEEDS_VAL,
> +			},
> +			{ .index = S_SECTSIZE,
> +			  .conflicts = { S_LOG,
> +					 S_SECTLOG,
> +					 LAST_CONFLICT },
> +			  .convert = true,
> +			  .is_power_2 = true,
> +			  .minval = XFS_MIN_SECTORSIZE,
> +			  .maxval = XFS_MAX_SECTORSIZE,
> +			  .flagval = SUBOPT_NEEDS_VAL,
> +			},
>  		},
>  	},
> -};
> -
> -struct opt_params mopts = {
> -	.name = 'm',
> -	.subopts = {
> -#define	M_CRC		0
> -		"crc",
> -#define M_FINOBT	1
> -		"finobt",
> -#define M_UUID		2
> -		"uuid",
> -#define M_RMAPBT	3
> -		"rmapbt",
> -#define M_REFLINK	4
> -		"reflink",
> -		NULL
> -	},
> -	.subopt_params = {
> -		{ .index = M_CRC,
> -		  .conflicts = { LAST_CONFLICT },
> -		  .minval = 0,
> -		  .maxval = 1,
> -		  .flagval = 1,
> -		},
> -		{ .index = M_FINOBT,
> -		  .conflicts = { LAST_CONFLICT },
> -		  .minval = 0,
> -		  .maxval = 1,
> -		  .flagval = 1,
> +#define OPT_M	7
> +	{
> +		.index = OPT_M,
> +		.name = 'm',
> +		.subopts = {
> +	#define	M_CRC		0
> +			"crc",
> +	#define M_FINOBT	1
> +			"finobt",
> +	#define M_UUID		2
> +			"uuid",
> +	#define M_RMAPBT	3
> +			"rmapbt",
> +	#define M_REFLINK	4
> +			"reflink",
> +			NULL
>  		},
> -		{ .index = M_UUID,
> -		  .conflicts = { LAST_CONFLICT },
> -		  .flagval = SUBOPT_NEEDS_VAL,
> -		},
> -		{ .index = M_RMAPBT,
> -		  .conflicts = { LAST_CONFLICT },
> -		  .minval = 0,
> -		  .maxval = 1,
> -		  .flagval = 1,
> -		},
> -		{ .index = M_REFLINK,
> -		  .conflicts = { LAST_CONFLICT },
> -		  .minval = 0,
> -		  .maxval = 1,
> -		  .flagval = 1,
> +		.subopt_params = {
> +			{ .index = M_CRC,
> +			  .conflicts = { LAST_CONFLICT },
> +			  .minval = 0,
> +			  .maxval = 1,
> +			  .flagval = 1,
> +			},
> +			{ .index = M_FINOBT,
> +			  .conflicts = { LAST_CONFLICT },
> +			  .minval = 0,
> +			  .maxval = 1,
> +			  .flagval = 1,
> +			},
> +			{ .index = M_UUID,
> +			  .conflicts = { LAST_CONFLICT },
> +			  .flagval = SUBOPT_NEEDS_VAL,
> +			},
> +			{ .index = M_RMAPBT,
> +			.conflicts = { LAST_CONFLICT },
> +			.minval = 0,
> +			.maxval = 1,
> +			.flagval = 1,
> +			},
> +			{ .index = M_REFLINK,
> +			  .conflicts = { LAST_CONFLICT },
> +			  .minval = 0,
> +			  .maxval = 1,
> +			  .flagval = 1,
> +			},
>  		},
>  	},
>  };
> @@ -740,21 +754,22 @@ struct opt_params mopts = {
>   * the string to be saved.
>   */
>  static int
> -set_conf_raw(struct opt_params *opt, const int subopt, const char *value)
> +set_conf_raw(const int opt, const int subopt, const char *value)
>  {
> -	if (subopt < 0 || subopt >= MAX_SUBOPTS) {
> +	if (subopt < 0 || subopt >= MAX_SUBOPTS ||
> +	    opt < 0 || opt >= MAX_OPTS) {
>  		fprintf(stderr,
> -		"This is a bug: set_conf_raw called with invalid opt/subopt: %c/%d\n",
> -		opt->name, subopt);
> +		"This is a bug: set_conf_raw called with invalid opt/subopt: %d/%d\n",
> +		opt, subopt);
>  		return -EINVAL;
>  	}
>  	if (value == NULL) {
> -		if (opt->subopt_params[subopt].raw_input != NULL)
> -			free(opt->subopt_params[subopt].raw_input);
> -		opt->subopt_params[subopt].raw_input = NULL;
> +		if (opts[opt].subopt_params[subopt].raw_input != NULL)
> +			free(opts[opt].subopt_params[subopt].raw_input);
> +		opts[opt].subopt_params[subopt].raw_input = NULL;
>  	} else {
> -		opt->subopt_params[subopt].raw_input = strdup(value);
> -		if (opt->subopt_params[subopt].raw_input == NULL)
> +		opts[opt].subopt_params[subopt].raw_input = strdup(value);
> +		if (opts[opt].subopt_params[subopt].raw_input == NULL)
>  			return -ENOMEM;
>  	}
>  	return 0;
> @@ -765,19 +780,19 @@ set_conf_raw(struct opt_params *opt, const int subopt, const char *value)
>   * the string to be saved into the out pointer.
>   */
>  static int
> -get_conf_raw(const struct opt_params *opt, const int subopt, char **out)
> +get_conf_raw(const int opt, const int subopt, char **out)
>  {
> -	if (subopt < 0 || subopt >= MAX_SUBOPTS) {
> +	if (subopt < 0 || subopt >= MAX_SUBOPTS ||
> +	    opt < 0 || opt >= MAX_OPTS) {
>  		fprintf(stderr,
> -		"This is a bug: get_conf_raw called with invalid opt/subopt: %c/%d\n",
> -		opt->name, subopt);
> +		"This is a bug: get_conf_raw called with invalid opt/subopt: %d/%d\n",
> +		opt, subopt);
>  		return -EINVAL;
>  	}
> -	*out = strdup(opt->subopt_params[subopt].raw_input);
> +	*out = strdup(opts[opt].subopt_params[subopt].raw_input);
>  	if (*out == NULL)
>  		return -ENOMEM;
>  	return 0;
> -
>  }
>  
>  /*
> @@ -785,7 +800,7 @@ get_conf_raw(const struct opt_params *opt, const int subopt, char **out)
>   * If any error occurs, return NULL.
>   */
>  static char *
> -get_conf_raw_safe(const struct opt_params *opt, const int subopt)
> +get_conf_raw_safe(const int opt, const int subopt)
>  {
>  	char *str;
>  
> @@ -1396,7 +1411,7 @@ getnum(
>  	long long		c;
>  
>  	check_opt(opts, index, false);
> -	set_conf_raw(opts, index, str);
> +	set_conf_raw(opts->index, index, str);
>  	/* empty strings might just return a default value */
>  	if (!str || *str == '\0') {
>  		if (sp->flagval == SUBOPT_NEEDS_VAL)
> @@ -1611,17 +1626,19 @@ main(
>  		case 'b':
>  			p = optarg;
>  			while (*p != '\0') {
> -				char	**subopts = (char **)bopts.subopts;
> +				char	**subopts =
> +						(char **)opts[OPT_B].subopts;
>  				char	*value;
>  
>  				switch (getsubopt(&p, subopts, &value)) {
>  				case B_LOG:
> -					blocklog = getnum(value, &bopts, B_LOG);
> +					blocklog = getnum(value, &opts[OPT_B],
> +								B_LOG);

I was thinking that these should get moved to separate functions to
handle each option category (-b, -d, -m, etc.) to reduce the indenting
here, but that's a job for a subsequent patch (or maybe you do it later
already?)

--D

>  					blocksize = 1 << blocklog;
>  					blflag = 1;
>  					break;
>  				case B_SIZE:
> -					blocksize = getnum(value, &bopts,
> +					blocksize = getnum(value, &opts[OPT_B],
>  							   B_SIZE);
>  					blocklog = libxfs_highbit32(blocksize);
>  					bsflag = 1;
> @@ -1634,78 +1651,86 @@ main(
>  		case 'd':
>  			p = optarg;
>  			while (*p != '\0') {
> -				char	**subopts = (char **)dopts.subopts;
> +				char	**subopts =
> +						(char **)opts[OPT_D].subopts;
>  				char	*value;
>  
>  				switch (getsubopt(&p, subopts, &value)) {
>  				case D_AGCOUNT:
> -					agcount = getnum(value, &dopts,
> +					agcount = getnum(value, &opts[OPT_D],
>  							 D_AGCOUNT);
>  					daflag = 1;
>  					break;
>  				case D_AGSIZE:
> -					agsize = getnum(value, &dopts, D_AGSIZE);
> +					agsize = getnum(value, &opts[OPT_D],
> +								D_AGSIZE);
>  					dasize = 1;
>  					break;
>  				case D_FILE:
> -					xi.disfile = getnum(value, &dopts,
> -							    D_FILE);
> +					xi.disfile = getnum(value,
> +						&opts[OPT_D], D_FILE);
>  					break;
>  				case D_NAME:
> -					xi.dname = getstr(value, &dopts, D_NAME);
> +					xi.dname = getstr(value, &opts[OPT_D],
> +								D_NAME);
>  					break;
>  				case D_SIZE:
> -					dbytes = getnum(value, &dopts, D_SIZE);
> +					dbytes = getnum(value, &opts[OPT_D],
> +								D_SIZE);
>  					break;
>  				case D_SUNIT:
> -					dsunit = getnum(value, &dopts, D_SUNIT);
> +					dsunit = getnum(value, &opts[OPT_D],
> +								D_SUNIT);
>  					dsflag = 1;
>  					break;
>  				case D_SWIDTH:
> -					dswidth = getnum(value, &dopts,
> +					dswidth = getnum(value, &opts[OPT_D],
>  							 D_SWIDTH);
>  					dsflag = 1;
>  					break;
>  				case D_SU:
> -					dsu = getnum(value, &dopts, D_SU);
> +					dsu = getnum(value, &opts[OPT_D],
> +								D_SU);
>  					dsflag = 1;
>  					break;
>  				case D_SW:
> -					dsw = getnum(value, &dopts, D_SW);
> +					dsw = getnum(value, &opts[OPT_D],
> +								D_SW);
>  					dsflag = 1;
>  					break;
>  				case D_NOALIGN:
> -					nodsflag = getnum(value, &dopts,
> +					nodsflag = getnum(value, &opts[OPT_D],
>  								D_NOALIGN);
>  					break;
>  				case D_SECTLOG:
> -					sectorlog = getnum(value, &dopts,
> +					sectorlog = getnum(value, &opts[OPT_D],
>  							   D_SECTLOG);
>  					sectorsize = 1 << sectorlog;
>  					slflag = 1;
>  					break;
>  				case D_SECTSIZE:
> -					sectorsize = getnum(value, &dopts,
> -							    D_SECTSIZE);
> +					sectorsize = getnum(value,
> +						&opts[OPT_D], D_SECTSIZE);
>  					sectorlog =
>  						libxfs_highbit32(sectorsize);
>  					ssflag = 1;
>  					break;
>  				case D_RTINHERIT:
> -					c = getnum(value, &dopts, D_RTINHERIT);
> +					c = getnum(value, &opts[OPT_D],
> +								D_RTINHERIT);
>  					if (c)
>  						fsx.fsx_xflags |=
>  							XFS_DIFLAG_RTINHERIT;
>  					break;
>  				case D_PROJINHERIT:
> -					fsx.fsx_projid = getnum(value, &dopts,
> -								D_PROJINHERIT);
> +					fsx.fsx_projid = getnum(value,
> +						&opts[OPT_D], D_PROJINHERIT);
>  					fsx.fsx_xflags |=
>  						XFS_DIFLAG_PROJINHERIT;
>  					break;
>  				case D_EXTSZINHERIT:
> -					fsx.fsx_extsize = getnum(value, &dopts,
> -								 D_EXTSZINHERIT);
> +					fsx.fsx_extsize = getnum(value,
> +						&opts[OPT_D], D_EXTSZINHERIT);
>  					fsx.fsx_xflags |=
>  						XFS_DIFLAG_EXTSZINHERIT;
>  					break;
> @@ -1717,46 +1742,51 @@ main(
>  		case 'i':
>  			p = optarg;
>  			while (*p != '\0') {
> -				char	**subopts = (char **)iopts.subopts;
> +				char	**subopts =
> +						(char **)opts[OPT_I].subopts;
>  				char	*value;
>  
>  				switch (getsubopt(&p, subopts, &value)) {
>  				case I_ALIGN:
>  					sb_feat.inode_align = getnum(value,
> -								&iopts, I_ALIGN);
> +						&opts[OPT_I], I_ALIGN);
>  					break;
>  				case I_LOG:
> -					inodelog = getnum(value, &iopts, I_LOG);
> +					inodelog = getnum(value, &opts[OPT_I],
> +								I_LOG);
>  					isize = 1 << inodelog;
>  					ilflag = 1;
>  					break;
>  				case I_MAXPCT:
> -					imaxpct = getnum(value, &iopts,
> +					imaxpct = getnum(value, &opts[OPT_I],
>  							 I_MAXPCT);
>  					imflag = 1;
>  					break;
>  				case I_PERBLOCK:
> -					inopblock = getnum(value, &iopts,
> +					inopblock = getnum(value, &opts[OPT_I],
>  							   I_PERBLOCK);
>  					ipflag = 1;
>  					break;
>  				case I_SIZE:
> -					isize = getnum(value, &iopts, I_SIZE);
> +					isize = getnum(value, &opts[OPT_I],
> +								I_SIZE);
>  					inodelog = libxfs_highbit32(isize);
>  					isflag = 1;
>  					break;
>  				case I_ATTR:
>  					sb_feat.attr_version =
> -						getnum(value, &iopts, I_ATTR);
> +						getnum(value, &opts[OPT_I],
> +								I_ATTR);
>  					break;
>  				case I_PROJID32BIT:
>  					sb_feat.projid16bit =
> -						!getnum(value, &iopts,
> +						!getnum(value, &opts[OPT_I],
>  							I_PROJID32BIT);
>  					break;
>  				case I_SPINODES:
>  					sb_feat.spinodes = getnum(value,
> -							&iopts, I_SPINODES);
> +								&opts[OPT_I],
> +								I_SPINODES);
>  					break;
>  				default:
>  					unknown('i', value);
> @@ -1766,63 +1796,70 @@ main(
>  		case 'l':
>  			p = optarg;
>  			while (*p != '\0') {
> -				char	**subopts = (char **)lopts.subopts;
> +				char	**subopts =
> +						(char **)opts[OPT_L].subopts;
>  				char	*value;
>  
>  				switch (getsubopt(&p, subopts, &value)) {
>  				case L_AGNUM:
> -					logagno = getnum(value, &lopts, L_AGNUM);
> +					logagno = getnum(value, &opts[OPT_L],
> +								L_AGNUM);
>  					laflag = 1;
>  					break;
>  				case L_FILE:
> -					xi.lisfile = getnum(value, &lopts,
> -							    L_FILE);
> +					xi.lisfile = getnum(value,
> +						&opts[OPT_L], L_FILE);
>  					break;
>  				case L_INTERNAL:
> -					loginternal = getnum(value, &lopts,
> -							     L_INTERNAL);
> +					loginternal = getnum(value,
> +						&opts[OPT_L], L_INTERNAL);
>  					liflag = 1;
>  					break;
>  				case L_SU:
> -					lsu = getnum(value, &lopts, L_SU);
> +					lsu = getnum(value, &opts[OPT_L],
> +								L_SU);
>  					lsuflag = 1;
>  					break;
>  				case L_SUNIT:
> -					lsunit = getnum(value, &lopts, L_SUNIT);
> +					lsunit = getnum(value, &opts[OPT_L],
> +								L_SUNIT);
>  					lsunitflag = 1;
>  					break;
>  				case L_NAME:
>  				case L_DEV:
> -					logfile = getstr(value, &lopts, L_NAME);
> +					logfile = getstr(value, &opts[OPT_L],
> +								L_NAME);
>  					xi.logname = logfile;
>  					ldflag = 1;
>  					loginternal = 0;
>  					break;
>  				case L_VERSION:
>  					sb_feat.log_version =
> -						getnum(value, &lopts, L_VERSION);
> +						getnum(value, &opts[OPT_L],
> +								L_VERSION);
>  					lvflag = 1;
>  					break;
>  				case L_SIZE:
> -					logbytes = getnum(value, &lopts, L_SIZE);
> +					logbytes = getnum(value,
> +						&opts[OPT_L], L_SIZE);
>  					break;
>  				case L_SECTLOG:
> -					lsectorlog = getnum(value, &lopts,
> -							    L_SECTLOG);
> +					lsectorlog = getnum(value,
> +						&opts[OPT_L], L_SECTLOG);
>  					lsectorsize = 1 << lsectorlog;
>  					lslflag = 1;
>  					break;
>  				case L_SECTSIZE:
> -					lsectorsize = getnum(value, &lopts,
> -							     L_SECTSIZE);
> +					lsectorsize = getnum(value,
> +						&opts[OPT_L], L_SECTSIZE);
>  					lsectorlog =
>  						libxfs_highbit32(lsectorsize);
>  					lssflag = 1;
>  					break;
>  				case L_LAZYSBCNTR:
>  					sb_feat.lazy_sb_counters =
> -							getnum(value, &lopts,
> -							       L_LAZYSBCNTR);
> +						getnum(value, &opts[OPT_L],
> +							L_LAZYSBCNTR);
>  					break;
>  				default:
>  					unknown('l', value);
> @@ -1837,19 +1874,21 @@ main(
>  		case 'm':
>  			p = optarg;
>  			while (*p != '\0') {
> -				char	**subopts = (char **)mopts.subopts;
> +				char	**subopts =
> +						(char **)opts[OPT_M].subopts;
>  				char	*value;
>  
>  				switch (getsubopt(&p, subopts, &value)) {
>  				case M_CRC:
>  					sb_feat.crcs_enabled =
> -						getnum(value, &mopts, M_CRC);
> +						getnum(value, &opts[OPT_M],
> +								M_CRC);
>  					if (sb_feat.crcs_enabled)
>  						sb_feat.dirftype = true;
>  					break;
>  				case M_FINOBT:
>  					sb_feat.finobt = getnum(
> -						value, &mopts, M_FINOBT);
> +						value, &opts[OPT_M], M_FINOBT);
>  					break;
>  				case M_UUID:
>  					if (!value || *value == '\0')
> @@ -1859,11 +1898,12 @@ main(
>  					break;
>  				case M_RMAPBT:
>  					sb_feat.rmapbt = getnum(
> -						value, &mopts, M_RMAPBT);
> +						value, &opts[OPT_M], M_RMAPBT);
>  					break;
>  				case M_REFLINK:
> -					sb_feat.reflink = getnum(
> -						value, &mopts, M_REFLINK);
> +					sb_feat.reflink =
> +						getnum(value, &opts[OPT_M],
> +							M_REFLINK);
>  					break;
>  				default:
>  					unknown('m', value);
> @@ -1873,38 +1913,41 @@ main(
>  		case 'n':
>  			p = optarg;
>  			while (*p != '\0') {
> -				char	**subopts = (char **)nopts.subopts;
> +				char	**subopts =
> +						(char **)opts[OPT_N].subopts;
>  				char	*value;
>  
>  				switch (getsubopt(&p, subopts, &value)) {
>  				case N_LOG:
> -					dirblocklog = getnum(value, &nopts,
> -							     N_LOG);
> +					dirblocklog = getnum(value,
> +						&opts[OPT_N], N_LOG);
>  					dirblocksize = 1 << dirblocklog;
>  					nlflag = 1;
>  					break;
>  				case N_SIZE:
> -					dirblocksize = getnum(value, &nopts,
> -							      N_SIZE);
> +					dirblocksize = getnum(value,
> +						&opts[OPT_N], N_SIZE);
>  					dirblocklog =
>  						libxfs_highbit32(dirblocksize);
>  					nsflag = 1;
>  					break;
>  				case N_VERSION:
> -					value = getstr(value, &nopts, N_VERSION);
> +					value = getstr(value, &opts[OPT_N],
> +								N_VERSION);
>  					if (!strcasecmp(value, "ci")) {
>  						/* ASCII CI mode */
>  						sb_feat.nci = true;
>  					} else {
>  						sb_feat.dir_version =
> -							getnum(value, &nopts,
> +							getnum(value,
> +							       &opts[OPT_N],
>  							       N_VERSION);
>  					}
>  					nvflag = 1;
>  					break;
>  				case N_FTYPE:
> -					sb_feat.dirftype = getnum(value, &nopts,
> -								  N_FTYPE);
> +					sb_feat.dirftype = getnum(value,
> +						&opts[OPT_N], N_FTYPE);
>  					break;
>  				default:
>  					unknown('n', value);
> @@ -1928,27 +1971,30 @@ main(
>  		case 'r':
>  			p = optarg;
>  			while (*p != '\0') {
> -				char	**subopts = (char **)ropts.subopts;
> +				char	**subopts =
> +						(char **)opts[OPT_R].subopts;
>  				char	*value;
>  
>  				switch (getsubopt(&p, subopts, &value)) {
>  				case R_EXTSIZE:
> -					rtextbytes = getnum(value, &ropts, R_EXTSIZE);
> +					rtextbytes = getnum(value,
> +						&opts[OPT_R], R_EXTSIZE);
>  					break;
>  				case R_FILE:
> -					xi.risfile = getnum(value, &ropts,
> -							    R_FILE);
> +					xi.risfile = getnum(value,
> +						&opts[OPT_R], R_FILE);
>  					break;
>  				case R_NAME:
>  				case R_DEV:
> -					xi.rtname = getstr(value, &ropts,
> +					xi.rtname = getstr(value, &opts[OPT_R],
>  							   R_NAME);
>  					break;
>  				case R_SIZE:
> -					rtbytes = getnum(value, &ropts, R_SIZE);
> +					rtbytes = getnum(value, &opts[OPT_R],
> +								R_SIZE);
>  					break;
>  				case R_NOALIGN:
> -					norsflag = getnum(value, &ropts,
> +					norsflag = getnum(value, &opts[OPT_R],
>  								R_NOALIGN);
>  					break;
>  				default:
> @@ -1959,7 +2005,8 @@ main(
>  		case 's':
>  			p = optarg;
>  			while (*p != '\0') {
> -				char	**subopts = (char **)sopts.subopts;
> +				char	**subopts =
> +						(char **)opts[OPT_S].subopts;
>  				char	*value;
>  
>  				switch (getsubopt(&p, subopts, &value)) {
> @@ -1967,8 +2014,9 @@ main(
>  				case S_SECTLOG:
>  					if (lssflag)
>  						conflict('s', subopts,
> -							 S_SECTSIZE, S_SECTLOG);
> -					sectorlog = getnum(value, &sopts,
> +							 S_SECTSIZE,
> +							 S_SECTLOG);
> +					sectorlog = getnum(value, &opts[OPT_S],
>  							   S_SECTLOG);
>  					lsectorlog = sectorlog;
>  					sectorsize = 1 << sectorlog;
> @@ -1978,10 +2026,11 @@ main(
>  				case S_SIZE:
>  				case S_SECTSIZE:
>  					if (lslflag)
> -						conflict('s', subopts, S_SECTLOG,
> +						conflict('s', subopts,
> +							 S_SECTLOG,
>  							 S_SECTSIZE);
> -					sectorsize = getnum(value, &sopts,
> -							    S_SECTSIZE);
> +					sectorsize = getnum(value,
> +						&opts[OPT_S], S_SECTSIZE);
>  					lsectorsize = sectorsize;
>  					sectorlog =
>  						libxfs_highbit32(sectorsize);
> @@ -2004,7 +2053,8 @@ main(
>  		fprintf(stderr, _("extra arguments\n"));
>  		usage();
>  	} else if (argc - optind == 1) {
> -		dfile = xi.volname = getstr(argv[optind], &dopts, D_NAME);
> +		dfile = xi.volname = getstr(argv[optind],
> +					&opts[OPT_D], D_NAME);
>  	} else
>  		dfile = xi.dname;
>  
> @@ -2183,7 +2233,8 @@ _("32 bit Project IDs always enabled on CRC enabled filesytems\n"));
>  		 * then issue an error.
>  		 * The same is also for sparse inodes.
>  		 */
> -		if (sb_feat.finobt && mopts.subopt_params[M_FINOBT].seen) {
> +		if (sb_feat.finobt &&
> +		    opts[OPT_M].subopt_params[M_FINOBT].seen) {
>  			fprintf(stderr,
>  _("finobt not supported without CRC support\n"));
>  			usage();
> @@ -2432,7 +2483,7 @@ _("rmapbt not supported with realtime devices\n"));
>  		fprintf(stderr,
>  			_("size %s specified for data subvolume is too large, "
>  			"maximum is %lld blocks\n"),
> -			get_conf_raw_safe(&dopts, D_SIZE),
> +			get_conf_raw_safe(OPT_D, D_SIZE),
>  			(long long)DTOBT(xi.dsize));
>  		usage();
>  	} else if (!dbytes && xi.dsize > 0)
> @@ -2481,7 +2532,7 @@ reported by the device (%u).\n"),
>  		fprintf(stderr,
>  			_("size %s specified for rt subvolume is too large, "
>  			"maximum is %lld blocks\n"),
> -			get_conf_raw_safe(&ropts, R_SIZE),
> +			get_conf_raw_safe(OPT_R, R_SIZE),
>  			(long long)DTOBT(xi.rtsize));
>  		usage();
>  	} else if (!rtbytes && xi.rtsize > 0)
> @@ -2697,7 +2748,7 @@ an AG size that is one stripe unit smaller, for example %llu.\n"),
>  	if (logbytes && xi.logBBsize > 0 && logblocks > DTOBT(xi.logBBsize)) {
>  		fprintf(stderr,
>  _("size %s specified for log subvolume is too large, maximum is %lld blocks\n"),
> -			get_conf_raw_safe(&lopts, L_SIZE),
> +			get_conf_raw_safe(OPT_L, L_SIZE),
>  			(long long)DTOBT(xi.logBBsize));
>  		usage();
>  	} else if (!logbytes && xi.logBBsize > 0) {
> -- 
> 2.13.3
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 5/6] mkfs: move getnum within the file
  2017-08-11 12:30 ` [PATCH 5/6] mkfs: move getnum within the file Jan Tulak
@ 2017-08-14 23:07   ` Darrick J. Wong
  2017-08-15 10:14     ` Jan Tulak
  0 siblings, 1 reply; 37+ messages in thread
From: Darrick J. Wong @ 2017-08-14 23:07 UTC (permalink / raw)
  To: Jan Tulak; +Cc: linux-xfs

On Fri, Aug 11, 2017 at 02:30:36PM +0200, Jan Tulak wrote:
> Move getnum, check_opt and illegal_option within the file. We have to do
> this to avoid dependency issues with the following patch. There is no
> other change in this patch, just cut&paste of these functions.
> 
> Signed-off-by: Jan Tulak <jtulak@redhat.com>
> ---
>  mkfs/xfs_mkfs.c | 236 ++++++++++++++++++++++++++++----------------------------
>  1 file changed, 118 insertions(+), 118 deletions(-)
> 
> diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
> index e3f7d345..3e7ba5f0 100644
> --- a/mkfs/xfs_mkfs.c
> +++ b/mkfs/xfs_mkfs.c
> @@ -813,6 +813,124 @@ get_conf_raw_safe(const int opt, const int subopt)
>  	return str;
>  }
>  
> +static __attribute__((noreturn)) void
> +illegal_option(

How about declaring the functions at the top and leaving the definitions
where they are?

--D

> +	const char		*value,
> +	struct opt_params	*opts,
> +	int			index,
> +	const char		*reason)
> +{
> +	fprintf(stderr,
> +		_("Illegal value %s for -%c %s option. %s\n"),
> +		value, opts->name, opts->subopts[index],
> +		reason ? reason : "");
> +	usage();
> +}
> +
> +/*
> + * Check for conflicts and option respecification.
> + */
> +static void
> +check_opt(
> +	struct opt_params	*opts,
> +	int			index,
> +	bool			str_seen)
> +{
> +	struct subopt_param	*sp = &opts->subopt_params[index];
> +	int			i;
> +
> +	if (sp->index != index) {
> +		fprintf(stderr,
> +	("Developer screwed up option parsing (%d/%d)! Please report!\n"),
> +			sp->index, index);
> +		reqval(opts->name, (char **)opts->subopts, index);
> +	}
> +
> +	/*
> +	 * Check for respecification of the option. This is more complex than it
> +	 * seems because some options are parsed twice - once as a string during
> +	 * input parsing, then later the string is passed to getnum for
> +	 * conversion into a number and bounds checking. Hence the two variables
> +	 * used to track the different uses based on the @str parameter passed
> +	 * to us.
> +	 */
> +	if (!str_seen) {
> +		if (sp->seen)
> +			respec(opts->name, (char **)opts->subopts, index);
> +		sp->seen = true;
> +	} else {
> +		if (sp->str_seen)
> +			respec(opts->name, (char **)opts->subopts, index);
> +		sp->str_seen = true;
> +	}
> +
> +	/* check for conflicts with the option */
> +	for (i = 0; i < MAX_CONFLICTS; i++) {
> +		int conflict_opt = sp->conflicts[i];
> +
> +		if (conflict_opt == LAST_CONFLICT)
> +			break;
> +		if (opts->subopt_params[conflict_opt].seen ||
> +		    opts->subopt_params[conflict_opt].str_seen)
> +			conflict(opts->name, (char **)opts->subopts,
> +				 conflict_opt, index);
> +	}
> +}
> +
> +static long long
> +getnum(
> +	const char		*str,
> +	struct opt_params	*opts,
> +	int			index)
> +{
> +	struct subopt_param	*sp = &opts->subopt_params[index];
> +	long long		c;
> +
> +	check_opt(opts, index, false);
> +	set_conf_raw(opts->index, index, str);
> +	/* empty strings might just return a default value */
> +	if (!str || *str == '\0') {
> +		if (sp->flagval == SUBOPT_NEEDS_VAL)
> +			reqval(opts->name, (char **)opts->subopts, index);
> +		return sp->flagval;
> +	}
> +
> +	if (sp->minval == 0 && sp->maxval == 0) {
> +		fprintf(stderr,
> +			_("Option -%c %s has undefined minval/maxval."
> +			  "Can't verify value range. This is a bug.\n"),
> +			opts->name, opts->subopts[index]);
> +		exit(1);
> +	}
> +
> +	/*
> +	 * Some values are pure numbers, others can have suffixes that define
> +	 * the units of the number. Those get passed to cvtnum(), otherwise we
> +	 * convert it ourselves to guarantee there is no trailing garbage in the
> +	 * number.
> +	 */
> +	if (sp->convert)
> +		c = cvtnum(blocksize, sectorsize, str);
> +	else {
> +		char		*str_end;
> +
> +		c = strtoll(str, &str_end, 0);
> +		if (c == 0 && str_end == str)
> +			illegal_option(str, opts, index, NULL);
> +		if (*str_end != '\0')
> +			illegal_option(str, opts, index, NULL);
> +	}
> +
> +	/* Validity check the result. */
> +	if (c < sp->minval)
> +		illegal_option(str, opts, index, _("value is too small"));
> +	else if (c > sp->maxval)
> +		illegal_option(str, opts, index, _("value is too large"));
> +	if (sp->is_power_2 && !ispow2(c))
> +		illegal_option(str, opts, index, _("value must be a power of 2"));
> +	return c;
> +}
> +
>  /*
>   * Convert lsu to lsunit for 512 bytes blocks and check validity of the values.
>   */
> @@ -1337,124 +1455,6 @@ sb_set_features(
>  
>  }
>  
> -static __attribute__((noreturn)) void
> -illegal_option(
> -	const char		*value,
> -	struct opt_params	*opts,
> -	int			index,
> -	const char		*reason)
> -{
> -	fprintf(stderr,
> -		_("Illegal value %s for -%c %s option. %s\n"),
> -		value, opts->name, opts->subopts[index],
> -		reason ? reason : "");
> -	usage();
> -}
> -
> -/*
> - * Check for conflicts and option respecification.
> - */
> -static void
> -check_opt(
> -	struct opt_params	*opts,
> -	int			index,
> -	bool			str_seen)
> -{
> -	struct subopt_param	*sp = &opts->subopt_params[index];
> -	int			i;
> -
> -	if (sp->index != index) {
> -		fprintf(stderr,
> -	("Developer screwed up option parsing (%d/%d)! Please report!\n"),
> -			sp->index, index);
> -		reqval(opts->name, (char **)opts->subopts, index);
> -	}
> -
> -	/*
> -	 * Check for respecification of the option. This is more complex than it
> -	 * seems because some options are parsed twice - once as a string during
> -	 * input parsing, then later the string is passed to getnum for
> -	 * conversion into a number and bounds checking. Hence the two variables
> -	 * used to track the different uses based on the @str parameter passed
> -	 * to us.
> -	 */
> -	if (!str_seen) {
> -		if (sp->seen)
> -			respec(opts->name, (char **)opts->subopts, index);
> -		sp->seen = true;
> -	} else {
> -		if (sp->str_seen)
> -			respec(opts->name, (char **)opts->subopts, index);
> -		sp->str_seen = true;
> -	}
> -
> -	/* check for conflicts with the option */
> -	for (i = 0; i < MAX_CONFLICTS; i++) {
> -		int conflict_opt = sp->conflicts[i];
> -
> -		if (conflict_opt == LAST_CONFLICT)
> -			break;
> -		if (opts->subopt_params[conflict_opt].seen ||
> -		    opts->subopt_params[conflict_opt].str_seen)
> -			conflict(opts->name, (char **)opts->subopts,
> -				 conflict_opt, index);
> -	}
> -}
> -
> -static long long
> -getnum(
> -	const char		*str,
> -	struct opt_params	*opts,
> -	int			index)
> -{
> -	struct subopt_param	*sp = &opts->subopt_params[index];
> -	long long		c;
> -
> -	check_opt(opts, index, false);
> -	set_conf_raw(opts->index, index, str);
> -	/* empty strings might just return a default value */
> -	if (!str || *str == '\0') {
> -		if (sp->flagval == SUBOPT_NEEDS_VAL)
> -			reqval(opts->name, (char **)opts->subopts, index);
> -		return sp->flagval;
> -	}
> -
> -	if (sp->minval == 0 && sp->maxval == 0) {
> -		fprintf(stderr,
> -			_("Option -%c %s has undefined minval/maxval."
> -			  "Can't verify value range. This is a bug.\n"),
> -			opts->name, opts->subopts[index]);
> -		exit(1);
> -	}
> -
> -	/*
> -	 * Some values are pure numbers, others can have suffixes that define
> -	 * the units of the number. Those get passed to cvtnum(), otherwise we
> -	 * convert it ourselves to guarantee there is no trailing garbage in the
> -	 * number.
> -	 */
> -	if (sp->convert)
> -		c = cvtnum(blocksize, sectorsize, str);
> -	else {
> -		char		*str_end;
> -
> -		c = strtoll(str, &str_end, 0);
> -		if (c == 0 && str_end == str)
> -			illegal_option(str, opts, index, NULL);
> -		if (*str_end != '\0')
> -			illegal_option(str, opts, index, NULL);
> -	}
> -
> -	/* Validity check the result. */
> -	if (c < sp->minval)
> -		illegal_option(str, opts, index, _("value is too small"));
> -	else if (c > sp->maxval)
> -		illegal_option(str, opts, index, _("value is too large"));
> -	if (sp->is_power_2 && !ispow2(c))
> -		illegal_option(str, opts, index, _("value must be a power of 2"));
> -	return c;
> -}
> -
>  /*
>   * Option is a string - do all the option table work, and check there
>   * is actually an option string. Otherwise we don't do anything with the string
> -- 
> 2.13.3
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 6/6] mkfs: extend opt_params with a value field
  2017-08-11 12:30 ` [PATCH 6/6] mkfs: extend opt_params with a value field Jan Tulak
@ 2017-08-14 23:15   ` Darrick J. Wong
  2017-08-15 10:42     ` Jan Tulak
  0 siblings, 1 reply; 37+ messages in thread
From: Darrick J. Wong @ 2017-08-14 23:15 UTC (permalink / raw)
  To: Jan Tulak; +Cc: linux-xfs

On Fri, Aug 11, 2017 at 02:30:37PM +0200, Jan Tulak wrote:
> This patch adds infrastructure that will be used in subsequent patches.
> 
> The Value field is the actual value used in computations for creating
> the filesystem.  This is initialized with sensible default values. If
> initialized to 0, the value is considered disabled. User input will
> override default values.  If the field is a string and not a number, the
> value is set to a positive non-zero number when user input has been
> supplied.
> 
> Add functions that can be used to get/set values to opts table.
> 
> Signed-off-by: Jan Tulak <jtulak@redhat.com>
> 
> ---
> Change:
> * make the value type to be long long instead of uint64 for now
> * add collateral updates
> * add bounds to get/set functions
> * update the description of commit/in code
> * merge with another patch, which adds the get/set functions.
> ---
>  mkfs/xfs_mkfs.c | 194 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 194 insertions(+)
> 
> diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
> index 3e7ba5f0..61ef09e8 100644
> --- a/mkfs/xfs_mkfs.c
> +++ b/mkfs/xfs_mkfs.c
> @@ -117,6 +117,13 @@ unsigned int		sectorsize;
>   *     Filled raw string from the user, so we never lose that information e.g.
>   *     to print it back in case of an issue.
>   *
> + *   value OPTIONAL
> + *     The actual value used in computations for creating the filesystem.
> + *     This is initialized with sensible default values. If initialized to 0,
> + *     the value is considered disabled. User input will override default
> + *     values. If the field is a string and not a number, the value is set to
> + *     a positive non-zero number when user input has been supplied.
> + *
>   */
>  struct opt_params {
>  	int		index;
> @@ -134,6 +141,7 @@ struct opt_params {
>  		long long	maxval;
>  		long long	flagval;
>  		char		*raw_input;
> +		long long	value;

I think this is less sensitive for mkfs options, but for structures
please keep variables of the same type together to reduce memory usage.
That (char *) between the (long long) creates a 4-byte padding hole on
32-bit machines.  I recommend pahole for things like this.

>  	}		subopt_params[MAX_SUBOPTS];
>  } opts[MAX_OPTS] = {
>  #define OPT_B	0
> @@ -750,6 +758,180 @@ struct opt_params {
>  #define WHACK_SIZE (128 * 1024)
>  
>  /*
> + * Get and set values to the opts table.
> + */
> +static int
> +get_conf_val_unsafe(int opt, int subopt, uint64_t *output)
> +{
> +	if (subopt < 0 || subopt >= MAX_SUBOPTS ||
> +	    opt < 0 || opt >= MAX_OPTS) {
> +		fprintf(stderr,
> +		"This is a bug: get_conf_val called with invalid opt/subopt: %d/%d\n",

Oh yeah, I forgot to mention this a few patches back -- if these remain
fprintfs, then shouldn't the string be enclosed in _() so that strings
can be localized?

> +		opt, subopt);
> +		return -EINVAL;
> +	}
> +	*output = opts[opt].subopt_params[subopt].value;
> +	return 0;
> +}
> +
> +static long long
> +get_conf_val(int opt, int subopt)
> +{
> +	uint64_t res;
> +	if (get_conf_val_unsafe(opt, subopt, &res) != 0)
> +	    exit(1);

Tab then space indentation problem here.

> +	return res;
> +}
> +
> +static int
> +set_conf_val_unsafe(int opt, int subopt, uint64_t val)
> +{
> +	if (subopt < 0 || subopt >= MAX_SUBOPTS ||
> +	    opt < 0 || opt >= MAX_OPTS) {
> +		fprintf(stderr,
> +		"This is a bug: set_conf_val called with invalid opt/subopt: %d/%d\n",
> +		opt, subopt);
> +		return -EINVAL;
> +	}
> +	struct subopt_param *sp = &opts[opt].subopt_params[subopt];
> +	sp->value = val;
> +
> +	return 0;
> +}
> +
> +static void
> +set_conf_val(int opt, int subopt, uint64_t val)
> +{
> +	if (set_conf_val_unsafe(opt, subopt, val) != 0)
> +		exit(1);
> +}
> +
> +/*
> + * A wrapper around set_conf_val which updates also connected/collateral values.
> + * E.g. when changing S_LOG, update S_SIZE too.
> + */
> +static void
> +set_conf_val_collateral(int opt, int subopt, uint64_t val)

"collateral"... I hope we're not trying to secure a loan here. :)

I suggest using "connected" (or "correlated") here instead.

> +{
> +	set_conf_val(opt, subopt, val);
> +
> +	switch (opt) {
> +	case OPT_B:
> +		switch (subopt) {
> +		case B_LOG:
> +			set_conf_val(OPT_B, B_SIZE, 1 << val);
> +			break;
> +		case B_SIZE:
> +			set_conf_val(OPT_B, B_LOG,
> +				libxfs_highbit32(val));
> +			break;
> +		}
> +		break;
> +	case OPT_D:
> +		switch (subopt) {
> +		case D_SECTLOG:
> +			set_conf_val(OPT_S, S_LOG, val);
> +			set_conf_val(OPT_S, S_SECTLOG, val);
> +			set_conf_val(OPT_D, D_SECTSIZE,
> +					1 << val);
> +			set_conf_val(OPT_S, S_SECTSIZE,
> +					1 << val);
> +			set_conf_val(OPT_S, S_SIZE,
> +					1 << val);
> +			break;
> +		case D_SECTSIZE:
> +			set_conf_val(OPT_S, S_SIZE, val);
> +			set_conf_val(OPT_S, S_SECTSIZE, val);
> +			set_conf_val(OPT_D, D_SECTLOG,
> +				libxfs_highbit32(val));
> +			set_conf_val(OPT_S, S_LOG,
> +				libxfs_highbit32(val));
> +			set_conf_val(OPT_S, S_SECTLOG,
> +				libxfs_highbit32(val));
> +			break;
> +		}
> +		break;
> +	case OPT_I:
> +		switch (subopt) {
> +		case I_LOG:
> +			set_conf_val(OPT_I, I_SIZE, 1 << val);
> +			break;
> +		case I_SIZE:
> +			set_conf_val(OPT_I, I_LOG,
> +				libxfs_highbit32(val));
> +			break;
> +		}
> +		break;
> +	case OPT_L:
> +		switch (subopt) {
> +		case L_SECTLOG:
> +			set_conf_val(OPT_L, L_SECTSIZE,
> +					1 << val);
> +			break;
> +		case L_SECTSIZE:
> +			set_conf_val(OPT_L, L_SECTLOG,
> +			     libxfs_highbit32(val));

Tab/space indentation problem here too.

(Wondering if the calls here are short enough for a single line?)

> +			break;
> +		}
> +		break;
> +	case OPT_M:
> +		switch (subopt) {
> +		}
> +		break;
> +	case OPT_N:
> +		switch (subopt) {
> +		case N_LOG:
> +			set_conf_val(OPT_N, N_SIZE, 1 << val);
> +			break;
> +		case N_SIZE:
> +			set_conf_val(OPT_N, N_LOG,
> +				libxfs_highbit32(val));
> +			break;
> +		}
> +		break;
> +	case OPT_R:
> +		switch (subopt) {
> +		}
> +		break;
> +	case OPT_S:
> +		switch (subopt) {
> +		case S_LOG:
> +		case S_SECTLOG:
> +			set_conf_val(OPT_S, S_LOG, val);
> +			set_conf_val(OPT_D, D_SECTLOG, val);
> +			set_conf_val(OPT_L, L_SECTLOG, val);
> +			set_conf_val(OPT_D, D_SECTSIZE,
> +					1 << val);
> +			set_conf_val(OPT_S, S_SIZE, 1 << val);
> +			set_conf_val(OPT_S, S_SECTSIZE,
> +					1 << val);
> +			set_conf_val(OPT_L, L_SECTLOG, val);
> +			set_conf_val(OPT_L,
> +					L_SECTSIZE, 1 << val);
> +
> +			set_conf_val(OPT_L, L_SECTSIZE, val);
> +			break;
> +		case S_SIZE:
> +		case S_SECTSIZE:
> +			set_conf_val(OPT_S, S_SIZE, val);
> +			set_conf_val(OPT_D, D_SECTSIZE, val);
> +			set_conf_val(OPT_D, D_SECTLOG,
> +				libxfs_highbit32(val));
> +			set_conf_val(OPT_S, S_LOG,
> +				libxfs_highbit32(val));
> +			set_conf_val(OPT_S, S_SECTLOG,
> +				libxfs_highbit32(val));
> +			set_conf_val(OPT_L,
> +					L_SECTSIZE, val);
> +			set_conf_val(OPT_L, L_SECTLOG,
> +					libxfs_highbit32(val));
> +			break;
> +		}
> +		break;
> +	}
> +}
> +
> +/*
>   * Return 0 on success, -ENOMEM if it could not allocate enough memory for
>   * the string to be saved.
>   */
> @@ -932,6 +1114,18 @@ getnum(
>  }
>  
>  /*
> + * A wrapper for getnum and set_conf_val.
> + */
> +static inline long long
> +parse_conf_val(int opt, int subopt, char *value)
> +{
> +	long long num = getnum(value, &opts[opt], subopt);
> +
> +	set_conf_val_collateral(opt, subopt, num);
> +	return num;
> +}
> +
> +/*
>   * Convert lsu to lsunit for 512 bytes blocks and check validity of the values.
>   */
>  static void
> -- 
> 2.13.3
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 1/6] mkfs: Save raw user input field to the opts struct
  2017-08-14 22:56   ` Darrick J. Wong
@ 2017-08-15  9:47     ` Jan Tulak
  0 siblings, 0 replies; 37+ messages in thread
From: Jan Tulak @ 2017-08-15  9:47 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On Tue, Aug 15, 2017 at 12:56 AM, Darrick J. Wong
<darrick.wong@oracle.com> wrote:
> On Fri, Aug 11, 2017 at 02:30:32PM +0200, Jan Tulak wrote:
>> Save exactly what the user gave us for every option.  This way, we will
>> never lose the information if we need it to print back an issue.
>> (Just add the infrastructure now, used in the next patches.)
>>
>> Signed-off-by: Jan Tulak <jtulak@redhat.com>
>>
>> ---
>> CHANGE:
>> * added strdup
>> * added boundary checks to set/get functions
>> ---
>>  mkfs/xfs_mkfs.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>  1 file changed, 69 insertions(+)
>>
>> diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
>> index 7bb6408f..fa0b475c 100644
>> --- a/mkfs/xfs_mkfs.c
>> +++ b/mkfs/xfs_mkfs.c
>> @@ -107,6 +107,11 @@ unsigned int             sectorsize;
>>   *     sets what is used with simple specifying the subopt (-d file).
>>   *     A special SUBOPT_NEEDS_VAL can be used to require a user-given
>>   *     value in any case.
>> + *
>> + *   raw_input INTERNAL
>> + *     Filled raw string from the user, so we never lose that information e.g.
>> + *     to print it back in case of an issue.
>> + *
>>   */
>>  struct opt_params {
>>       const char      name;
>> @@ -122,6 +127,7 @@ struct opt_params {
>>               long long       minval;
>>               long long       maxval;
>>               long long       defaultval;
>> +             char            *raw_input;
>>       }               subopt_params[MAX_SUBOPTS];
>>  };
>>
>> @@ -730,6 +736,69 @@ struct opt_params mopts = {
>>  #define WHACK_SIZE (128 * 1024)
>>
>>  /*
>> + * Return 0 on success, -ENOMEM if it could not allocate enough memory for
>> + * the string to be saved.
>> + */
>> +static int
>> +set_conf_raw(struct opt_params *opt, const int subopt, const char *value)
>> +{
>> +     if (subopt < 0 || subopt >= MAX_SUBOPTS) {
>> +             fprintf(stderr,
>> +             "This is a bug: set_conf_raw called with invalid opt/subopt: %c/%d\n",
>> +             opt->name, subopt);
>
> ASSERT?  Or, if I'm just foolishly restarting an old bikeshed and the
> fprintf/-EINVAL should stay, then the indentation of the arguments needs
> fixing.

It stays, so I'm fixing the indentation for the fprintf.

>
>> +             return -EINVAL;
>> +     }
>> +     if (value == NULL) {
>> +             if (opt->subopt_params[subopt].raw_input != NULL)
>> +                     free(opt->subopt_params[subopt].raw_input);
>> +             opt->subopt_params[subopt].raw_input = NULL;
>> +     } else {
>> +             opt->subopt_params[subopt].raw_input = strdup(value);
>> +             if (opt->subopt_params[subopt].raw_input == NULL)
>> +                     return -ENOMEM;
>> +     }
>> +     return 0;
>> +}
>> +
>> +/*
>> + * Return 0 on success, -ENOMEM if it could not allocate enough memory for
>> + * the string to be saved into the out pointer.
>> + */
>> +static int
>> +get_conf_raw(const struct opt_params *opt, const int subopt, char **out)
>> +{
>> +     if (subopt < 0 || subopt >= MAX_SUBOPTS) {
>> +             fprintf(stderr,
>> +             "This is a bug: get_conf_raw called with invalid opt/subopt: %c/%d\n",
>> +             opt->name, subopt);
>> +             return -EINVAL;
>
> (Same here)
>
>> +     }
>> +     *out = strdup(opt->subopt_params[subopt].raw_input);
>
> Given that raw_input can be set to NULL and strdup(NULL) segfaults on
> glibc 2.23, do we need a null check of raw_input here?  Is it the case
> that get_conf_raw is only called if we (somehow) know that there's a
> value to get later?

We need it here, when I added the check to set_conf_raw somehow didn't
realise that it could fail on the other side as well.

Thanks,
Jan

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

* Re: [PATCH 4/6] mkfs: merge tables for opts parsing into one table
  2017-08-14 23:06   ` Darrick J. Wong
@ 2017-08-15 10:05     ` Jan Tulak
  0 siblings, 0 replies; 37+ messages in thread
From: Jan Tulak @ 2017-08-15 10:05 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On Tue, Aug 15, 2017 at 1:06 AM, Darrick J. Wong
<darrick.wong@oracle.com> wrote:
> On Fri, Aug 11, 2017 at 02:30:35PM +0200, Jan Tulak wrote:
>> Merge separate instances of opt_params into one indexable table. Git
>> makes this patch looks a bit more complicated, but it does not change
>> values or structure of anything else. It only moves all the "struct
>> opt_params dopts = {...}", changes indentation for these substructures
>> and replaces their usage (dopts -> opts[OPT_D]).
>>
>> The reason for this is to be able to address all options from any single
>> one, even across OPT_X. Right now, we can do automated conflict checks
>> only within one OPT_X, but after this, it is possible to extend the
>> conflict declaration to other options as well.
>>
>> Signed-off-by: Jan Tulak <jtulak@redhat.com>
>> ---
>> Change:
>>  * expand bounds check to newly added opt parameter in get/set functions
>>  * updated description
>> ---
>>  mkfs/xfs_mkfs.c | 1341 +++++++++++++++++++++++++++++--------------------------
>>  1 file changed, 696 insertions(+), 645 deletions(-)
>>
>> diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
>> index 78e27498..e3f7d345 100644
>> --- a/mkfs/xfs_mkfs.c
>> +++ b/mkfs/xfs_mkfs.c
>> @@ -39,6 +39,7 @@ static int  ispow2(unsigned int i);
>>  unsigned int         blocksize;
>>  unsigned int         sectorsize;
>>
>> +#define MAX_OPTS     16
>>  #define MAX_SUBOPTS  16
>>  #define SUBOPT_NEEDS_VAL     (-1LL)
>>  #define MAX_CONFLICTS        8
>> @@ -49,6 +50,10 @@ unsigned int               sectorsize;
>>   *
>>   * Description of the structure members follows:
>>   *
>> + * index MANDATORY
>> + *   An integer denoting the position of the specific option in opts array,
>> + *   counting from 0 up to MAX_OPTS.
>> + *
>>   * name MANDATORY
>>   *   Name is a single char, e.g., for '-d file', name is 'd'.
>>   *
>> @@ -114,6 +119,7 @@ unsigned int              sectorsize;
>>   *
>>   */
>>  struct opt_params {
>> +     int             index;
>>       const char      name;
>>       const char      *subopts[MAX_SUBOPTS];
>>
>> @@ -129,584 +135,592 @@ struct opt_params {
>>               long long       flagval;
>>               char            *raw_input;
>>       }               subopt_params[MAX_SUBOPTS];
>> -};
>> -
>> -struct opt_params bopts = {
>> -     .name = 'b',
>> -     .subopts = {
>> +} opts[MAX_OPTS] = {
>> +#define OPT_B        0
>> +     {
>> +             .index = OPT_B,
>> +             .name = 'b',
>> +             .subopts = {
>>  #define      B_LOG           0
>> -             "log",
>> +                     "log",
>>  #define      B_SIZE          1
>> -             "size",
>> -             NULL
>> -     },
>> -     .subopt_params = {
>> -             { .index = B_LOG,
>
> I /really/ wish there was a way calculate these automatically, but I
> don't think I know of any such way, at least not without using horrid
> macros.

Yes. :( Some enum magic could help a little bit with type checking,
but it still can't assign correct numbers everywhere on its own.

>
>> -               .conflicts = { B_SIZE,
>> -                              LAST_CONFLICT },
>> -               .minval = XFS_MIN_BLOCKSIZE_LOG,
>> -               .maxval = XFS_MAX_BLOCKSIZE_LOG,
>> -               .flagval = SUBOPT_NEEDS_VAL,
>> +                     "size",
>> +                     NULL
>>               },
>> -             { .index = B_SIZE,
>> -               .convert = true,
>> -               .is_power_2 = true,
>> -               .conflicts = { B_LOG,
>> -                              LAST_CONFLICT },
>> -               .minval = XFS_MIN_BLOCKSIZE,
>> -               .maxval = XFS_MAX_BLOCKSIZE,
>> -               .flagval = SUBOPT_NEEDS_VAL,
>> +             .subopt_params = {
>> +                     { .index = B_LOG,
>> +                       .conflicts = { B_SIZE,
>> +                                      LAST_CONFLICT },
>> +                       .minval = XFS_MIN_BLOCKSIZE_LOG,
>> +                       .maxval = XFS_MAX_BLOCKSIZE_LOG,
>> +                       .flagval = SUBOPT_NEEDS_VAL,
>> +                     },
>> +                     { .index = B_SIZE,
>> +                       .convert = true,
>> +                       .is_power_2 = true,
>> +                       .conflicts = { B_LOG,
>> +                                      LAST_CONFLICT },
>> +                       .minval = XFS_MIN_BLOCKSIZE,
>> +                       .maxval = XFS_MAX_BLOCKSIZE,
>> +                       .flagval = SUBOPT_NEEDS_VAL,
>> +                     },
>>               },
>>       },
>> -};
>> -
>> -struct opt_params dopts = {
>> -     .name = 'd',
>> -     .subopts = {
>> -#define      D_AGCOUNT       0
>> -             "agcount",
>> -#define      D_FILE          1
>> -             "file",
>> -#define      D_NAME          2
>> -             "name",
>> -#define      D_SIZE          3
>> -             "size",
>> -#define D_SUNIT              4
>> -             "sunit",
>> -#define D_SWIDTH     5
>> -             "swidth",
>> -#define D_AGSIZE     6
>> -             "agsize",
>> -#define D_SU         7
>> -             "su",
>> -#define D_SW         8
>> -             "sw",
>> -#define D_SECTLOG    9
>> -             "sectlog",
>> -#define D_SECTSIZE   10
>> -             "sectsize",
>> -#define D_NOALIGN    11
>> -             "noalign",
>> -#define D_RTINHERIT  12
>> -             "rtinherit",
>> -#define D_PROJINHERIT        13
>> -             "projinherit",
>> -#define D_EXTSZINHERIT       14
>> -             "extszinherit",
>> -             NULL
>> -     },
>> -     .subopt_params = {
>> -             { .index = D_AGCOUNT,
>> -               .conflicts = { D_AGSIZE,
>> -                              LAST_CONFLICT },
>> -               .minval = 1,
>> -               .maxval = XFS_MAX_AGNUMBER,
>> -               .flagval = SUBOPT_NEEDS_VAL,
>> -             },
>> -             { .index = D_FILE,
>> -               .conflicts = { LAST_CONFLICT },
>> -               .minval = 0,
>> -               .maxval = 1,
>> -               .flagval = 1,
>> -             },
>> -             { .index = D_NAME,
>> -               .conflicts = { LAST_CONFLICT },
>> -               .flagval = SUBOPT_NEEDS_VAL,
>> -             },
>> -             { .index = D_SIZE,
>> -               .conflicts = { LAST_CONFLICT },
>> -               .convert = true,
>> -               .minval = XFS_AG_MIN_BYTES,
>> -               .maxval = LLONG_MAX,
>> -               .flagval = SUBOPT_NEEDS_VAL,
>> -             },
>> -             { .index = D_SUNIT,
>> -               .conflicts = { D_NOALIGN,
>> -                              D_SU,
>> -                              D_SW,
>> -                              LAST_CONFLICT },
>> -               .minval = 0,
>> -               .maxval = UINT_MAX,
>> -               .flagval = SUBOPT_NEEDS_VAL,
>> -             },
>> -             { .index = D_SWIDTH,
>> -               .conflicts = { D_NOALIGN,
>> -                              D_SU,
>> -                              D_SW,
>> -                              LAST_CONFLICT },
>> -               .minval = 0,
>> -               .maxval = UINT_MAX,
>> -               .flagval = SUBOPT_NEEDS_VAL,
>> -             },
>> -             { .index = D_AGSIZE,
>> -               .conflicts = { D_AGCOUNT,
>> -                              LAST_CONFLICT },
>> -               .convert = true,
>> -               .minval = XFS_AG_MIN_BYTES,
>> -               .maxval = XFS_AG_MAX_BYTES,
>> -               .flagval = SUBOPT_NEEDS_VAL,
>> -             },
>> -             { .index = D_SU,
>> -               .conflicts = { D_NOALIGN,
>> -                              D_SUNIT,
>> -                              D_SWIDTH,
>> -                              LAST_CONFLICT },
>> -               .convert = true,
>> -               .minval = 0,
>> -               .maxval = UINT_MAX,
>> -               .flagval = SUBOPT_NEEDS_VAL,
>> -             },
>> -             { .index = D_SW,
>> -               .conflicts = { D_NOALIGN,
>> -                              D_SUNIT,
>> -                              D_SWIDTH,
>> -                              LAST_CONFLICT },
>> -               .minval = 0,
>> -               .maxval = UINT_MAX,
>> -               .flagval = SUBOPT_NEEDS_VAL,
>> -             },
>> -             { .index = D_SECTLOG,
>> -               .conflicts = { D_SECTSIZE,
>> -                              LAST_CONFLICT },
>> -               .minval = XFS_MIN_SECTORSIZE_LOG,
>> -               .maxval = XFS_MAX_SECTORSIZE_LOG,
>> -               .flagval = SUBOPT_NEEDS_VAL,
>> -             },
>> -             { .index = D_SECTSIZE,
>> -               .conflicts = { D_SECTLOG,
>> -                              LAST_CONFLICT },
>> -               .convert = true,
>> -               .is_power_2 = true,
>> -               .minval = XFS_MIN_SECTORSIZE,
>> -               .maxval = XFS_MAX_SECTORSIZE,
>> -               .flagval = SUBOPT_NEEDS_VAL,
>> +#define OPT_D        1
>> +     {
>> +             .index = OPT_D,
>> +             .name = 'd',
>> +             .subopts = {
>> +     #define D_AGCOUNT       0
>> +                     "agcount",
>> +     #define D_FILE          1
>> +                     "file",
>> +     #define D_NAME          2
>> +                     "name",
>> +     #define D_SIZE          3
>> +                     "size",
>> +     #define D_SUNIT         4
>> +                     "sunit",
>> +     #define D_SWIDTH        5
>> +                     "swidth",
>> +     #define D_AGSIZE        6
>> +                     "agsize",
>> +     #define D_SU            7
>> +                     "su",
>> +     #define D_SW            8
>> +                     "sw",
>> +     #define D_SECTLOG       9
>> +                     "sectlog",
>> +     #define D_SECTSIZE      10
>> +                     "sectsize",
>> +     #define D_NOALIGN       11
>> +                     "noalign",
>> +     #define D_RTINHERIT     12
>> +                     "rtinherit",
>> +     #define D_PROJINHERIT   13
>> +                     "projinherit",
>> +     #define D_EXTSZINHERIT  14
>> +                     "extszinherit",
>> +                     NULL
>>               },
>> -             { .index = D_NOALIGN,
>> -               .conflicts = { D_SU,
>> -                              D_SW,
>> -                              D_SUNIT,
>> -                              D_SWIDTH,
>> -                              LAST_CONFLICT },
>> -               .minval = 0,
>> -               .maxval = 1,
>> -               .flagval = 1,
>> -             },
>> -             { .index = D_RTINHERIT,
>> -               .conflicts = { LAST_CONFLICT },
>> -               .minval = 1,
>> -               .maxval = 1,
>> -               .flagval = 1,
>> -             },
>> -             { .index = D_PROJINHERIT,
>> -               .conflicts = { LAST_CONFLICT },
>> -               .minval = 0,
>> -               .maxval = UINT_MAX,
>> -               .flagval = SUBOPT_NEEDS_VAL,
>> -             },
>> -             { .index = D_EXTSZINHERIT,
>> -               .conflicts = { LAST_CONFLICT },
>> -               .minval = 0,
>> -               .maxval = UINT_MAX,
>> -               .flagval = SUBOPT_NEEDS_VAL,
>> +             .subopt_params = {
>> +                     { .index = D_AGCOUNT,
>> +                       .conflicts = { D_AGSIZE,
>> +                                      LAST_CONFLICT },
>> +                       .minval = 1,
>> +                       .maxval = XFS_MAX_AGNUMBER,
>> +                       .flagval = SUBOPT_NEEDS_VAL,
>> +                     },
>> +                     { .index = D_FILE,
>> +                       .conflicts = { LAST_CONFLICT },
>> +                       .minval = 0,
>> +                       .maxval = 1,
>> +                       .flagval = 1,
>> +                     },
>> +                     { .index = D_NAME,
>> +                       .conflicts = { LAST_CONFLICT },
>> +                       .flagval = SUBOPT_NEEDS_VAL,
>> +                     },
>> +                     { .index = D_SIZE,
>> +                       .conflicts = { LAST_CONFLICT },
>> +                       .convert = true,
>> +                       .minval = XFS_AG_MIN_BYTES,
>> +                       .maxval = LLONG_MAX,
>> +                       .flagval = SUBOPT_NEEDS_VAL,
>> +                     },
>> +                     { .index = D_SUNIT,
>> +                       .conflicts = { D_NOALIGN,
>> +                                      D_SU,
>> +                                      D_SW,
>> +                                      LAST_CONFLICT },
>> +                       .minval = 0,
>> +                       .maxval = UINT_MAX,
>> +                       .flagval = SUBOPT_NEEDS_VAL,
>> +                     },
>> +                     { .index = D_SWIDTH,
>> +                       .conflicts = { D_NOALIGN,
>> +                                      D_SU,
>> +                                      D_SW,
>> +                                      LAST_CONFLICT },
>> +                       .minval = 0,
>> +                       .maxval = UINT_MAX,
>> +                       .flagval = SUBOPT_NEEDS_VAL,
>> +                     },
>> +                     { .index = D_AGSIZE,
>> +                       .conflicts = { D_AGCOUNT,
>> +                                      LAST_CONFLICT },
>> +                       .convert = true,
>> +                       .minval = XFS_AG_MIN_BYTES,
>> +                       .maxval = XFS_AG_MAX_BYTES,
>> +                       .flagval = SUBOPT_NEEDS_VAL,
>> +                     },
>> +                     { .index = D_SU,
>> +                       .conflicts = { D_NOALIGN,
>> +                                      D_SUNIT,
>> +                                      D_SWIDTH,
>> +                                      LAST_CONFLICT },
>> +                       .convert = true,
>> +                       .minval = 0,
>> +                       .maxval = UINT_MAX,
>> +                       .flagval = SUBOPT_NEEDS_VAL,
>> +                     },
>> +                     { .index = D_SW,
>> +                       .conflicts = { D_NOALIGN,
>> +                                      D_SUNIT,
>> +                                      D_SWIDTH,
>> +                                      LAST_CONFLICT },
>> +                       .minval = 0,
>> +                       .maxval = UINT_MAX,
>> +                       .flagval = SUBOPT_NEEDS_VAL,
>> +                     },
>> +                     { .index = D_SECTLOG,
>> +                       .conflicts = { D_SECTSIZE,
>> +                                      LAST_CONFLICT },
>> +                       .minval = XFS_MIN_SECTORSIZE_LOG,
>> +                       .maxval = XFS_MAX_SECTORSIZE_LOG,
>> +                       .flagval = SUBOPT_NEEDS_VAL,
>> +                     },
>> +                     { .index = D_SECTSIZE,
>> +                       .conflicts = { D_SECTLOG,
>> +                                      LAST_CONFLICT },
>> +                       .convert = true,
>> +                       .is_power_2 = true,
>> +                       .minval = XFS_MIN_SECTORSIZE,
>> +                       .maxval = XFS_MAX_SECTORSIZE,
>> +                       .flagval = SUBOPT_NEEDS_VAL,
>> +                     },
>> +                     { .index = D_NOALIGN,
>> +                       .conflicts = { D_SU,
>> +                                      D_SW,
>> +                                      D_SUNIT,
>> +                                      D_SWIDTH,
>> +                                      LAST_CONFLICT },
>> +                       .minval = 0,
>> +                       .maxval = 1,
>> +                       .flagval = 1,
>> +                     },
>> +                     { .index = D_RTINHERIT,
>> +                       .conflicts = { LAST_CONFLICT },
>> +                       .minval = 0,
>> +                       .maxval = 1,
>> +                       .flagval = 1,
>> +                     },
>> +                     { .index = D_PROJINHERIT,
>> +                       .conflicts = { LAST_CONFLICT },
>> +                       .minval = 0,
>> +                       .maxval = UINT_MAX,
>> +                       .flagval = SUBOPT_NEEDS_VAL,
>> +                     },
>> +                     { .index = D_EXTSZINHERIT,
>> +                       .conflicts = { LAST_CONFLICT },
>> +                       .minval = 0,
>> +                       .maxval = UINT_MAX,
>> +                       .flagval = SUBOPT_NEEDS_VAL,
>> +                     },
>>               },
>>       },
>> -};
>> -
>> -
>> -struct opt_params iopts = {
>> -     .name = 'i',
>> -     .subopts = {
>> +#define OPT_I        2
>> +     {
>> +             .index = OPT_I,
>> +             .name = 'i',
>> +             .subopts = {
>>  #define      I_ALIGN         0
>> -             "align",
>> +                     "align",
>>  #define      I_LOG           1
>> -             "log",
>> +                     "log",
>>  #define      I_MAXPCT        2
>> -             "maxpct",
>> +                     "maxpct",
>>  #define      I_PERBLOCK      3
>> -             "perblock",
>> +                     "perblock",
>>  #define      I_SIZE          4
>> -             "size",
>> +                     "size",
>>  #define      I_ATTR          5
>> -             "attr",
>> +                     "attr",
>>  #define      I_PROJID32BIT   6
>> -             "projid32bit",
>> +                     "projid32bit",
>>  #define I_SPINODES   7
>> -             "sparse",
>> -             NULL
>> -     },
>> -     .subopt_params = {
>> -             { .index = I_ALIGN,
>> -               .conflicts = { LAST_CONFLICT },
>> -               .minval = 0,
>> -               .maxval = 1,
>> -               .flagval = 1,
>> -             },
>> -             { .index = I_LOG,
>> -               .conflicts = { I_PERBLOCK,
>> -                              I_SIZE,
>> -                              LAST_CONFLICT },
>> -               .minval = XFS_DINODE_MIN_LOG,
>> -               .maxval = XFS_DINODE_MAX_LOG,
>> -               .flagval = SUBOPT_NEEDS_VAL,
>> -             },
>> -             { .index = I_MAXPCT,
>> -               .conflicts = { LAST_CONFLICT },
>> -               .minval = 0,
>> -               .maxval = 100,
>> -               .flagval = SUBOPT_NEEDS_VAL,
>> +                     "sparse",
>> +                     NULL
>>               },
>> -             { .index = I_PERBLOCK,
>> -               .conflicts = { I_LOG,
>> -                              I_SIZE,
>> -                              LAST_CONFLICT },
>> -               .is_power_2 = true,
>> -               .minval = XFS_MIN_INODE_PERBLOCK,
>> -               .maxval = XFS_MAX_BLOCKSIZE / XFS_DINODE_MIN_SIZE,
>> -               .flagval = SUBOPT_NEEDS_VAL,
>> -             },
>> -             { .index = I_SIZE,
>> -               .conflicts = { I_PERBLOCK,
>> -                              I_LOG,
>> -                              LAST_CONFLICT },
>> -               .is_power_2 = true,
>> -               .minval = XFS_DINODE_MIN_SIZE,
>> -               .maxval = XFS_DINODE_MAX_SIZE,
>> -               .flagval = SUBOPT_NEEDS_VAL,
>> -             },
>> -             { .index = I_ATTR,
>> -               .conflicts = { LAST_CONFLICT },
>> -               .minval = 0,
>> -               .maxval = 2,
>> -               .flagval = SUBOPT_NEEDS_VAL,
>> -             },
>> -             { .index = I_PROJID32BIT,
>> -               .conflicts = { LAST_CONFLICT },
>> -               .minval = 0,
>> -               .maxval = 1,
>> -               .flagval = 1,
>> -             },
>> -             { .index = I_SPINODES,
>> -               .conflicts = { LAST_CONFLICT },
>> -               .minval = 0,
>> -               .maxval = 1,
>> -               .flagval = 1,
>> +             .subopt_params = {
>> +                     { .index = I_ALIGN,
>> +                       .conflicts = { LAST_CONFLICT },
>> +                       .minval = 0,
>> +                       .maxval = 1,
>> +                       .flagval = 1,
>> +                     },
>> +                     { .index = I_LOG,
>> +                       .conflicts = { I_PERBLOCK,
>> +                                      I_SIZE,
>> +                                      LAST_CONFLICT },
>> +                       .minval = XFS_DINODE_MIN_LOG,
>> +                       .maxval = XFS_DINODE_MAX_LOG,
>> +                       .flagval = SUBOPT_NEEDS_VAL,
>> +                     },
>> +                     { .index = I_MAXPCT,
>> +                       .conflicts = { LAST_CONFLICT },
>> +                       .minval = 0,
>> +                       .maxval = 100,
>> +                       .flagval = SUBOPT_NEEDS_VAL,
>> +                     },
>> +                     { .index = I_PERBLOCK,
>> +                       .conflicts = { I_LOG,
>> +                                      I_SIZE,
>> +                                      LAST_CONFLICT },
>> +                       .is_power_2 = true,
>> +                       .minval = XFS_MIN_INODE_PERBLOCK,
>> +                       .maxval = XFS_MAX_BLOCKSIZE / XFS_DINODE_MIN_SIZE,
>> +                       .flagval = SUBOPT_NEEDS_VAL,
>> +                     },
>> +                     { .index = I_SIZE,
>> +                       .conflicts = { I_PERBLOCK,
>> +                                      I_LOG,
>> +                                      LAST_CONFLICT },
>> +                       .is_power_2 = true,
>> +                       .minval = XFS_DINODE_MIN_SIZE,
>> +                       .maxval = XFS_DINODE_MAX_SIZE,
>> +                       .flagval = SUBOPT_NEEDS_VAL,
>> +                     },
>> +                     { .index = I_ATTR,
>> +                       .conflicts = { LAST_CONFLICT },
>> +                       .minval = 0,
>> +                       .maxval = 2,
>> +                       .flagval = SUBOPT_NEEDS_VAL,
>> +                     },
>> +                     { .index = I_PROJID32BIT,
>> +                       .conflicts = { LAST_CONFLICT },
>> +                       .minval = 0,
>> +                       .maxval = 1,
>> +                       .flagval = 1,
>> +                     },
>> +                     { .index = I_SPINODES,
>> +                       .conflicts = { LAST_CONFLICT },
>> +                       .minval = 0,
>> +                       .maxval = 1,
>> +                       .flagval = 1,
>> +                     },
>>               },
>>       },
>> -};
>> -
>> -struct opt_params lopts = {
>> -     .name = 'l',
>> -     .subopts = {
>> -#define      L_AGNUM         0
>> -             "agnum",
>> -#define      L_INTERNAL      1
>> -             "internal",
>> -#define      L_SIZE          2
>> -             "size",
>> -#define L_VERSION    3
>> -             "version",
>> -#define L_SUNIT              4
>> -             "sunit",
>> -#define L_SU         5
>> -             "su",
>> -#define L_DEV                6
>> -             "logdev",
>> -#define      L_SECTLOG       7
>> -             "sectlog",
>> -#define      L_SECTSIZE      8
>> -             "sectsize",
>> -#define      L_FILE          9
>> -             "file",
>> -#define      L_NAME          10
>> -             "name",
>> -#define      L_LAZYSBCNTR    11
>> -             "lazy-count",
>> -             NULL
>> -     },
>> -     .subopt_params = {
>> -             { .index = L_AGNUM,
>> -               .conflicts = { L_DEV,
>> -                              LAST_CONFLICT },
>> -               .minval = 0,
>> -               .maxval = UINT_MAX,
>> -               .flagval = SUBOPT_NEEDS_VAL,
>> -             },
>> -             { .index = L_INTERNAL,
>> -               .conflicts = { L_FILE,
>> -                              L_DEV,
>> -                              LAST_CONFLICT },
>> -               .minval = 0,
>> -               .maxval = 1,
>> -               .flagval = 1,
>> +#define OPT_L        3
>> +     {
>> +             .index = OPT_L,
>> +             .name = 'l',
>> +             .subopts = {
>> +     #define L_AGNUM         0
>> +                     "agnum",
>> +     #define L_INTERNAL      1
>> +                     "internal",
>> +     #define L_SIZE          2
>> +                     "size",
>> +     #define L_VERSION       3
>> +                     "version",
>> +     #define L_SUNIT         4
>> +                     "sunit",
>> +     #define L_SU            5
>> +                     "su",
>> +     #define L_DEV           6
>> +                     "logdev",
>> +     #define L_SECTLOG       7
>> +                     "sectlog",
>> +     #define L_SECTSIZE      8
>> +                     "sectsize",
>> +     #define L_FILE          9
>> +                     "file",
>> +     #define L_NAME          10
>> +                     "name",
>> +     #define L_LAZYSBCNTR    11
>> +                     "lazy-count",
>> +                     NULL
>>               },
>> -             { .index = L_SIZE,
>> -               .conflicts = { LAST_CONFLICT },
>> -               .convert = true,
>> -               .minval = 2 * 1024 * 1024LL,  /* XXX: XFS_MIN_LOG_BYTES */
>> -               .maxval = XFS_MAX_LOG_BYTES,
>> -               .flagval = SUBOPT_NEEDS_VAL,
>> -             },
>> -             { .index = L_VERSION,
>> -               .conflicts = { LAST_CONFLICT },
>> -               .minval = 1,
>> -               .maxval = 2,
>> -               .flagval = SUBOPT_NEEDS_VAL,
>> -             },
>> -             { .index = L_SUNIT,
>> -               .conflicts = { L_SU,
>> -                              LAST_CONFLICT },
>> -               .minval = 1,
>> -               .maxval = BTOBB(XLOG_MAX_RECORD_BSIZE),
>> -               .flagval = SUBOPT_NEEDS_VAL,
>> -             },
>> -             { .index = L_SU,
>> -               .conflicts = { L_SUNIT,
>> -                              LAST_CONFLICT },
>> -               .convert = true,
>> -               .minval = BBTOB(1),
>> -               .maxval = XLOG_MAX_RECORD_BSIZE,
>> -               .flagval = SUBOPT_NEEDS_VAL,
>> -             },
>> -             { .index = L_DEV,
>> -               .conflicts = { L_AGNUM,
>> -                              L_INTERNAL,
>> -                              LAST_CONFLICT },
>> -               .flagval = SUBOPT_NEEDS_VAL,
>> -             },
>> -             { .index = L_SECTLOG,
>> -               .conflicts = { L_SECTSIZE,
>> -                              LAST_CONFLICT },
>> -               .minval = XFS_MIN_SECTORSIZE_LOG,
>> -               .maxval = XFS_MAX_SECTORSIZE_LOG,
>> -               .flagval = SUBOPT_NEEDS_VAL,
>> -             },
>> -             { .index = L_SECTSIZE,
>> -               .conflicts = { L_SECTLOG,
>> -                              LAST_CONFLICT },
>> -               .convert = true,
>> -               .is_power_2 = true,
>> -               .minval = XFS_MIN_SECTORSIZE,
>> -               .maxval = XFS_MAX_SECTORSIZE,
>> -               .flagval = SUBOPT_NEEDS_VAL,
>> -             },
>> -             { .index = L_FILE,
>> -               .conflicts = { L_INTERNAL,
>> -                              LAST_CONFLICT },
>> -               .minval = 0,
>> -               .maxval = 1,
>> -               .flagval = 1,
>> -             },
>> -             { .index = L_NAME,
>> -               .conflicts = { L_AGNUM,
>> -                              L_INTERNAL,
>> -                              LAST_CONFLICT },
>> -               .flagval = SUBOPT_NEEDS_VAL,
>> -             },
>> -             { .index = L_LAZYSBCNTR,
>> -               .conflicts = { LAST_CONFLICT },
>> -               .minval = 0,
>> -               .maxval = 1,
>> -               .flagval = 1,
>> +             .subopt_params = {
>> +                     { .index = L_AGNUM,
>> +                       .conflicts = { L_DEV,
>> +                                      LAST_CONFLICT },
>> +                       .minval = 0,
>> +                       .maxval = UINT_MAX,
>> +                       .flagval = SUBOPT_NEEDS_VAL,
>> +                     },
>> +                     { .index = L_INTERNAL,
>> +                       .conflicts = { L_FILE,
>> +                                      L_DEV,
>> +                                      LAST_CONFLICT },
>> +                       .minval = 0,
>> +                       .maxval = 1,
>> +                       .flagval = 1,
>> +                     },
>> +                     { .index = L_SIZE,
>> +                       .conflicts = { LAST_CONFLICT },
>> +                       .convert = true,
>> +                       .minval = 2 * 1024 * 1024LL,  /* XXX: XFS_MIN_LOG_BYTES */
>
> I recognize that this is a mechanical translation patch, but why does
> this setter have an XXX comment for a #define that actually exists?  And
> why does the value used differ??
>
> If this needs fixing, please do it as a separate patch.

Mmm, I will check this.

>
> As far as this one goes,
> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
>
>> +                       .maxval = XFS_MAX_LOG_BYTES,
>> +                       .flagval = SUBOPT_NEEDS_VAL,
>> +                     },
>> +                     { .index = L_VERSION,
>> +                       .conflicts = { LAST_CONFLICT },
>> +                       .minval = 1,
>> +                       .maxval = 2,
>> +                       .flagval = SUBOPT_NEEDS_VAL,
>> +                     },
>> +                     { .index = L_SUNIT,
>> +                       .conflicts = { L_SU,
>> +                                      LAST_CONFLICT },
>> +                       .minval = 1,
>> +                       .maxval = BTOBB(XLOG_MAX_RECORD_BSIZE),
>> +                       .flagval = SUBOPT_NEEDS_VAL,
>> +                     },
>> +                     { .index = L_SU,
>> +                       .conflicts = { L_SUNIT,
>> +                                      LAST_CONFLICT },
>> +                       .convert = true,
>> +                       .minval = BBTOB(1),
>> +                       .maxval = XLOG_MAX_RECORD_BSIZE,
>> +                       .flagval = SUBOPT_NEEDS_VAL,
>> +                     },
>> +                     { .index = L_DEV,
>> +                       .conflicts = { L_AGNUM,
>> +                                      L_INTERNAL,
>> +                                      LAST_CONFLICT },
>> +                       .flagval = SUBOPT_NEEDS_VAL,
>> +                     },
>> +                     { .index = L_SECTLOG,
>> +                       .conflicts = { L_SECTSIZE,
>> +                                      LAST_CONFLICT },
>> +                       .minval = XFS_MIN_SECTORSIZE_LOG,
>> +                       .maxval = XFS_MAX_SECTORSIZE_LOG,
>> +                       .flagval = SUBOPT_NEEDS_VAL,
>> +                     },
>> +                     { .index = L_SECTSIZE,
>> +                       .conflicts = { L_SECTLOG,
>> +                                      LAST_CONFLICT },
>> +                       .convert = true,
>> +                       .is_power_2 = true,
>> +                       .minval = XFS_MIN_SECTORSIZE,
>> +                       .maxval = XFS_MAX_SECTORSIZE,
>> +                       .flagval = SUBOPT_NEEDS_VAL,
>> +                     },
>> +                     { .index = L_FILE,
>> +                       .conflicts = { L_INTERNAL,
>> +                                      LAST_CONFLICT },
>> +                       .minval = 0,
>> +                       .maxval = 1,
>> +                       .flagval = 1,
>> +                     },
>> +                     { .index = L_NAME,
>> +                       .conflicts = { L_AGNUM,
>> +                                      L_INTERNAL,
>> +                                      LAST_CONFLICT },
>> +                       .flagval = SUBOPT_NEEDS_VAL,
>> +                     },
>> +                     { .index = L_LAZYSBCNTR,
>> +                       .conflicts = { LAST_CONFLICT },
>> +                       .minval = 0,
>> +                       .maxval = 1,
>> +                       .flagval = 1,
>> +                     },
>>               },
>>       },
>> -};
>> -
>> -struct opt_params nopts = {
>> -     .name = 'n',
>> -     .subopts = {
>> -#define      N_LOG           0
>> -             "log",
>> -#define      N_SIZE          1
>> -             "size",
>> -#define      N_VERSION       2
>> -             "version",
>> -#define      N_FTYPE         3
>> -             "ftype",
>> -     NULL,
>> -     },
>> -     .subopt_params = {
>> -             { .index = N_LOG,
>> -               .conflicts = { N_SIZE,
>> -                              LAST_CONFLICT },
>> -               .minval = XFS_MIN_REC_DIRSIZE,
>> -               .maxval = XFS_MAX_BLOCKSIZE_LOG,
>> -               .flagval = SUBOPT_NEEDS_VAL,
>> -             },
>> -             { .index = N_SIZE,
>> -               .conflicts = { N_LOG,
>> -                              LAST_CONFLICT },
>> -               .convert = true,
>> -               .is_power_2 = true,
>> -               .minval = 1 << XFS_MIN_REC_DIRSIZE,
>> -               .maxval = XFS_MAX_BLOCKSIZE,
>> -               .flagval = SUBOPT_NEEDS_VAL,
>> +#define OPT_N        4
>> +     {
>> +             .index = OPT_N,
>> +             .name = 'n',
>> +             .subopts = {
>> +     #define N_LOG           0
>> +                     "log",
>> +     #define N_SIZE          1
>> +                     "size",
>> +     #define N_VERSION       2
>> +                     "version",
>> +     #define N_FTYPE         3
>> +                     "ftype",
>> +             NULL,
>>               },
>> -             { .index = N_VERSION,
>> -               .conflicts = { LAST_CONFLICT },
>> -               .minval = 2,
>> -               .maxval = 2,
>> -               .flagval = SUBOPT_NEEDS_VAL,
>> +             .subopt_params = {
>> +                     { .index = N_LOG,
>> +                       .conflicts = { N_SIZE,
>> +                                      LAST_CONFLICT },
>> +                       .minval = XFS_MIN_REC_DIRSIZE,
>> +                       .maxval = XFS_MAX_BLOCKSIZE_LOG,
>> +                       .flagval = SUBOPT_NEEDS_VAL,
>> +                     },
>> +                     { .index = N_SIZE,
>> +                       .conflicts = { N_LOG,
>> +                                      LAST_CONFLICT },
>> +                       .convert = true,
>> +                       .is_power_2 = true,
>> +                       .minval = 1 << XFS_MIN_REC_DIRSIZE,
>> +                       .maxval = XFS_MAX_BLOCKSIZE,
>> +                       .flagval = SUBOPT_NEEDS_VAL,
>> +                     },
>> +                     { .index = N_VERSION,
>> +                       .conflicts = { LAST_CONFLICT },
>> +                       .minval = 2,
>> +                       .maxval = 2,
>> +                       .flagval = SUBOPT_NEEDS_VAL,
>> +                     },
>> +                     { .index = N_FTYPE,
>> +                       .conflicts = { LAST_CONFLICT },
>> +                       .minval = 0,
>> +                       .maxval = 1,
>> +                       .flagval = 1,
>> +                     },
>>               },
>> -             { .index = N_FTYPE,
>> -               .conflicts = { LAST_CONFLICT },
>> -               .minval = 0,
>> -               .maxval = 1,
>> -               .flagval = 1,
>> -             },
>> -     },
>> -};
>> -
>> -struct opt_params ropts = {
>> -     .name = 'r',
>> -     .subopts = {
>> -#define      R_EXTSIZE       0
>> -             "extsize",
>> -#define      R_SIZE          1
>> -             "size",
>> -#define      R_DEV           2
>> -             "rtdev",
>> -#define      R_FILE          3
>> -             "file",
>> -#define      R_NAME          4
>> -             "name",
>> -#define R_NOALIGN    5
>> -             "noalign",
>> -             NULL
>>       },
>> -     .subopt_params = {
>> -             { .index = R_EXTSIZE,
>> -               .conflicts = { LAST_CONFLICT },
>> -               .convert = true,
>> -               .minval = XFS_MIN_RTEXTSIZE,
>> -               .maxval = XFS_MAX_RTEXTSIZE,
>> -               .flagval = SUBOPT_NEEDS_VAL,
>> +#define OPT_R        5
>> +     {
>> +             .index = OPT_R,
>> +             .name = 'r',
>> +             .subopts = {
>> +     #define R_EXTSIZE       0
>> +                     "extsize",
>> +     #define R_SIZE          1
>> +                     "size",
>> +     #define R_DEV           2
>> +                     "rtdev",
>> +     #define R_FILE          3
>> +                     "file",
>> +     #define R_NAME          4
>> +                     "name",
>> +     #define R_NOALIGN       5
>> +                     "noalign",
>> +                     NULL
>>               },
>> -             { .index = R_SIZE,
>> -               .conflicts = { LAST_CONFLICT },
>> -               .convert = true,
>> -               .minval = 0,
>> -               .maxval = LLONG_MAX,
>> -               .flagval = SUBOPT_NEEDS_VAL,
>> -             },
>> -             { .index = R_DEV,
>> -               .conflicts = { LAST_CONFLICT },
>> -               .flagval = SUBOPT_NEEDS_VAL,
>> -             },
>> -             { .index = R_FILE,
>> -               .minval = 0,
>> -               .maxval = 1,
>> -               .flagval = 1,
>> -               .conflicts = { LAST_CONFLICT },
>> -             },
>> -             { .index = R_NAME,
>> -               .conflicts = { LAST_CONFLICT },
>> -               .flagval = SUBOPT_NEEDS_VAL,
>> -             },
>> -             { .index = R_NOALIGN,
>> -               .minval = 0,
>> -               .maxval = 1,
>> -               .flagval = 1,
>> -               .conflicts = { LAST_CONFLICT },
>> +             .subopt_params = {
>> +                     { .index = R_EXTSIZE,
>> +                       .conflicts = { LAST_CONFLICT },
>> +                       .convert = true,
>> +                       .minval = XFS_MIN_RTEXTSIZE,
>> +                       .maxval = XFS_MAX_RTEXTSIZE,
>> +                       .flagval = SUBOPT_NEEDS_VAL,
>> +                     },
>> +                     { .index = R_SIZE,
>> +                       .conflicts = { LAST_CONFLICT },
>> +                       .convert = true,
>> +                       .minval = 0,
>> +                       .maxval = LLONG_MAX,
>> +                       .flagval = SUBOPT_NEEDS_VAL,
>> +                     },
>> +                     { .index = R_DEV,
>> +                       .conflicts = { LAST_CONFLICT },
>> +                       .flagval = SUBOPT_NEEDS_VAL,
>> +                     },
>> +                     { .index = R_FILE,
>> +                       .minval = 0,
>> +                       .maxval = 1,
>> +                       .flagval = 1,
>> +                       .conflicts = { LAST_CONFLICT },
>> +                     },
>> +                     { .index = R_NAME,
>> +                       .conflicts = { LAST_CONFLICT },
>> +                       .flagval = SUBOPT_NEEDS_VAL,
>> +                     },
>> +                     { .index = R_NOALIGN,
>> +                       .minval = 0,
>> +                       .maxval = 1,
>> +                       .flagval = 1,
>> +                       .conflicts = { LAST_CONFLICT },
>> +                     },
>>               },
>>       },
>> -};
>> -
>> -struct opt_params sopts = {
>> -     .name = 's',
>> -     .subopts = {
>> -#define      S_LOG           0
>> -             "log",
>> -#define      S_SECTLOG       1
>> -             "sectlog",
>> -#define      S_SIZE          2
>> -             "size",
>> -#define      S_SECTSIZE      3
>> -             "sectsize",
>> -             NULL
>> -     },
>> -     .subopt_params = {
>> -             { .index = S_LOG,
>> -               .conflicts = { S_SIZE,
>> -                              S_SECTSIZE,
>> -                              LAST_CONFLICT },
>> -               .minval = XFS_MIN_SECTORSIZE_LOG,
>> -               .maxval = XFS_MAX_SECTORSIZE_LOG,
>> -               .flagval = SUBOPT_NEEDS_VAL,
>> -             },
>> -             { .index = S_SECTLOG,
>> -               .conflicts = { S_SIZE,
>> -                              S_SECTSIZE,
>> -                              LAST_CONFLICT },
>> -               .minval = XFS_MIN_SECTORSIZE_LOG,
>> -               .maxval = XFS_MAX_SECTORSIZE_LOG,
>> -               .flagval = SUBOPT_NEEDS_VAL,
>> -             },
>> -             { .index = S_SIZE,
>> -               .conflicts = { S_LOG,
>> -                              S_SECTLOG,
>> -                              LAST_CONFLICT },
>> -               .convert = true,
>> -               .is_power_2 = true,
>> -               .minval = XFS_MIN_SECTORSIZE,
>> -               .maxval = XFS_MAX_SECTORSIZE,
>> -               .flagval = SUBOPT_NEEDS_VAL,
>> +#define OPT_S        6
>> +     {
>> +             .index = OPT_S,
>> +             .name = 's',
>> +             .subopts = {
>> +     #define S_LOG           0
>> +                     "log",
>> +     #define S_SECTLOG       1
>> +                     "sectlog",
>> +     #define S_SIZE          2
>> +                     "size",
>> +     #define S_SECTSIZE      3
>> +                     "sectsize",
>> +                     NULL
>>               },
>> -             { .index = S_SECTSIZE,
>> -               .conflicts = { S_LOG,
>> -                              S_SECTLOG,
>> -                              LAST_CONFLICT },
>> -               .convert = true,
>> -               .is_power_2 = true,
>> -               .minval = XFS_MIN_SECTORSIZE,
>> -               .maxval = XFS_MAX_SECTORSIZE,
>> -               .flagval = SUBOPT_NEEDS_VAL,
>> +             .subopt_params = {
>> +                     { .index = S_LOG,
>> +                       .conflicts = { S_SIZE,
>> +                                      S_SECTSIZE,
>> +                                      LAST_CONFLICT },
>> +                       .minval = XFS_MIN_SECTORSIZE_LOG,
>> +                       .maxval = XFS_MAX_SECTORSIZE_LOG,
>> +                       .flagval = SUBOPT_NEEDS_VAL,
>> +                     },
>> +                     { .index = S_SECTLOG,
>> +                       .conflicts = { S_SIZE,
>> +                                      S_SECTSIZE,
>> +                                      LAST_CONFLICT },
>> +                       .minval = XFS_MIN_SECTORSIZE_LOG,
>> +                       .maxval = XFS_MAX_SECTORSIZE_LOG,
>> +                       .flagval = SUBOPT_NEEDS_VAL,
>> +                     },
>> +                     { .index = S_SIZE,
>> +                       .conflicts = { S_LOG,
>> +                                      S_SECTLOG,
>> +                                      LAST_CONFLICT },
>> +                       .convert = true,
>> +                       .is_power_2 = true,
>> +                       .minval = XFS_MIN_SECTORSIZE,
>> +                       .maxval = XFS_MAX_SECTORSIZE,
>> +                       .flagval = SUBOPT_NEEDS_VAL,
>> +                     },
>> +                     { .index = S_SECTSIZE,
>> +                       .conflicts = { S_LOG,
>> +                                      S_SECTLOG,
>> +                                      LAST_CONFLICT },
>> +                       .convert = true,
>> +                       .is_power_2 = true,
>> +                       .minval = XFS_MIN_SECTORSIZE,
>> +                       .maxval = XFS_MAX_SECTORSIZE,
>> +                       .flagval = SUBOPT_NEEDS_VAL,
>> +                     },
>>               },
>>       },
>> -};
>> -
>> -struct opt_params mopts = {
>> -     .name = 'm',
>> -     .subopts = {
>> -#define      M_CRC           0
>> -             "crc",
>> -#define M_FINOBT     1
>> -             "finobt",
>> -#define M_UUID               2
>> -             "uuid",
>> -#define M_RMAPBT     3
>> -             "rmapbt",
>> -#define M_REFLINK    4
>> -             "reflink",
>> -             NULL
>> -     },
>> -     .subopt_params = {
>> -             { .index = M_CRC,
>> -               .conflicts = { LAST_CONFLICT },
>> -               .minval = 0,
>> -               .maxval = 1,
>> -               .flagval = 1,
>> -             },
>> -             { .index = M_FINOBT,
>> -               .conflicts = { LAST_CONFLICT },
>> -               .minval = 0,
>> -               .maxval = 1,
>> -               .flagval = 1,
>> +#define OPT_M        7
>> +     {
>> +             .index = OPT_M,
>> +             .name = 'm',
>> +             .subopts = {
>> +     #define M_CRC           0
>> +                     "crc",
>> +     #define M_FINOBT        1
>> +                     "finobt",
>> +     #define M_UUID          2
>> +                     "uuid",
>> +     #define M_RMAPBT        3
>> +                     "rmapbt",
>> +     #define M_REFLINK       4
>> +                     "reflink",
>> +                     NULL
>>               },
>> -             { .index = M_UUID,
>> -               .conflicts = { LAST_CONFLICT },
>> -               .flagval = SUBOPT_NEEDS_VAL,
>> -             },
>> -             { .index = M_RMAPBT,
>> -               .conflicts = { LAST_CONFLICT },
>> -               .minval = 0,
>> -               .maxval = 1,
>> -               .flagval = 1,
>> -             },
>> -             { .index = M_REFLINK,
>> -               .conflicts = { LAST_CONFLICT },
>> -               .minval = 0,
>> -               .maxval = 1,
>> -               .flagval = 1,
>> +             .subopt_params = {
>> +                     { .index = M_CRC,
>> +                       .conflicts = { LAST_CONFLICT },
>> +                       .minval = 0,
>> +                       .maxval = 1,
>> +                       .flagval = 1,
>> +                     },
>> +                     { .index = M_FINOBT,
>> +                       .conflicts = { LAST_CONFLICT },
>> +                       .minval = 0,
>> +                       .maxval = 1,
>> +                       .flagval = 1,
>> +                     },
>> +                     { .index = M_UUID,
>> +                       .conflicts = { LAST_CONFLICT },
>> +                       .flagval = SUBOPT_NEEDS_VAL,
>> +                     },
>> +                     { .index = M_RMAPBT,
>> +                     .conflicts = { LAST_CONFLICT },
>> +                     .minval = 0,
>> +                     .maxval = 1,
>> +                     .flagval = 1,
>> +                     },
>> +                     { .index = M_REFLINK,
>> +                       .conflicts = { LAST_CONFLICT },
>> +                       .minval = 0,
>> +                       .maxval = 1,
>> +                       .flagval = 1,
>> +                     },
>>               },
>>       },
>>  };
>> @@ -740,21 +754,22 @@ struct opt_params mopts = {
>>   * the string to be saved.
>>   */
>>  static int
>> -set_conf_raw(struct opt_params *opt, const int subopt, const char *value)
>> +set_conf_raw(const int opt, const int subopt, const char *value)
>>  {
>> -     if (subopt < 0 || subopt >= MAX_SUBOPTS) {
>> +     if (subopt < 0 || subopt >= MAX_SUBOPTS ||
>> +         opt < 0 || opt >= MAX_OPTS) {
>>               fprintf(stderr,
>> -             "This is a bug: set_conf_raw called with invalid opt/subopt: %c/%d\n",
>> -             opt->name, subopt);
>> +             "This is a bug: set_conf_raw called with invalid opt/subopt: %d/%d\n",
>> +             opt, subopt);
>>               return -EINVAL;
>>       }
>>       if (value == NULL) {
>> -             if (opt->subopt_params[subopt].raw_input != NULL)
>> -                     free(opt->subopt_params[subopt].raw_input);
>> -             opt->subopt_params[subopt].raw_input = NULL;
>> +             if (opts[opt].subopt_params[subopt].raw_input != NULL)
>> +                     free(opts[opt].subopt_params[subopt].raw_input);
>> +             opts[opt].subopt_params[subopt].raw_input = NULL;
>>       } else {
>> -             opt->subopt_params[subopt].raw_input = strdup(value);
>> -             if (opt->subopt_params[subopt].raw_input == NULL)
>> +             opts[opt].subopt_params[subopt].raw_input = strdup(value);
>> +             if (opts[opt].subopt_params[subopt].raw_input == NULL)
>>                       return -ENOMEM;
>>       }
>>       return 0;
>> @@ -765,19 +780,19 @@ set_conf_raw(struct opt_params *opt, const int subopt, const char *value)
>>   * the string to be saved into the out pointer.
>>   */
>>  static int
>> -get_conf_raw(const struct opt_params *opt, const int subopt, char **out)
>> +get_conf_raw(const int opt, const int subopt, char **out)
>>  {
>> -     if (subopt < 0 || subopt >= MAX_SUBOPTS) {
>> +     if (subopt < 0 || subopt >= MAX_SUBOPTS ||
>> +         opt < 0 || opt >= MAX_OPTS) {
>>               fprintf(stderr,
>> -             "This is a bug: get_conf_raw called with invalid opt/subopt: %c/%d\n",
>> -             opt->name, subopt);
>> +             "This is a bug: get_conf_raw called with invalid opt/subopt: %d/%d\n",
>> +             opt, subopt);
>>               return -EINVAL;
>>       }
>> -     *out = strdup(opt->subopt_params[subopt].raw_input);
>> +     *out = strdup(opts[opt].subopt_params[subopt].raw_input);
>>       if (*out == NULL)
>>               return -ENOMEM;
>>       return 0;
>> -
>>  }
>>
>>  /*
>> @@ -785,7 +800,7 @@ get_conf_raw(const struct opt_params *opt, const int subopt, char **out)
>>   * If any error occurs, return NULL.
>>   */
>>  static char *
>> -get_conf_raw_safe(const struct opt_params *opt, const int subopt)
>> +get_conf_raw_safe(const int opt, const int subopt)
>>  {
>>       char *str;
>>
>> @@ -1396,7 +1411,7 @@ getnum(
>>       long long               c;
>>
>>       check_opt(opts, index, false);
>> -     set_conf_raw(opts, index, str);
>> +     set_conf_raw(opts->index, index, str);
>>       /* empty strings might just return a default value */
>>       if (!str || *str == '\0') {
>>               if (sp->flagval == SUBOPT_NEEDS_VAL)
>> @@ -1611,17 +1626,19 @@ main(
>>               case 'b':
>>                       p = optarg;
>>                       while (*p != '\0') {
>> -                             char    **subopts = (char **)bopts.subopts;
>> +                             char    **subopts =
>> +                                             (char **)opts[OPT_B].subopts;
>>                               char    *value;
>>
>>                               switch (getsubopt(&p, subopts, &value)) {
>>                               case B_LOG:
>> -                                     blocklog = getnum(value, &bopts, B_LOG);
>> +                                     blocklog = getnum(value, &opts[OPT_B],
>> +                                                             B_LOG);
>
> I was thinking that these should get moved to separate functions to
> handle each option category (-b, -d, -m, etc.) to reduce the indenting
> here, but that's a job for a subsequent patch (or maybe you do it later
> already?)

I'm not doing it, but it is a good idea. I will see how it looks in as
a separate patch later on.

Jan

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

* Re: [PATCH 5/6] mkfs: move getnum within the file
  2017-08-14 23:07   ` Darrick J. Wong
@ 2017-08-15 10:14     ` Jan Tulak
  2017-08-15 21:09       ` Eric Sandeen
  0 siblings, 1 reply; 37+ messages in thread
From: Jan Tulak @ 2017-08-15 10:14 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On Tue, Aug 15, 2017 at 1:07 AM, Darrick J. Wong
<darrick.wong@oracle.com> wrote:
> On Fri, Aug 11, 2017 at 02:30:36PM +0200, Jan Tulak wrote:
>> Move getnum, check_opt and illegal_option within the file. We have to do
>> this to avoid dependency issues with the following patch. There is no
>> other change in this patch, just cut&paste of these functions.
>>
>> Signed-off-by: Jan Tulak <jtulak@redhat.com>
>> ---
>>  mkfs/xfs_mkfs.c | 236 ++++++++++++++++++++++++++++----------------------------
>>  1 file changed, 118 insertions(+), 118 deletions(-)
>>
>> diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
>> index e3f7d345..3e7ba5f0 100644
>> --- a/mkfs/xfs_mkfs.c
>> +++ b/mkfs/xfs_mkfs.c
>> @@ -813,6 +813,124 @@ get_conf_raw_safe(const int opt, const int subopt)
>>       return str;
>>  }
>>
>> +static __attribute__((noreturn)) void
>> +illegal_option(
>
> How about declaring the functions at the top and leaving the definitions
> where they are?

If I remember, Eric thought the opposite. :-)

Jan

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

* Re: [PATCH 6/6] mkfs: extend opt_params with a value field
  2017-08-14 23:15   ` Darrick J. Wong
@ 2017-08-15 10:42     ` Jan Tulak
  0 siblings, 0 replies; 37+ messages in thread
From: Jan Tulak @ 2017-08-15 10:42 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On Tue, Aug 15, 2017 at 1:15 AM, Darrick J. Wong
<darrick.wong@oracle.com> wrote:
> On Fri, Aug 11, 2017 at 02:30:37PM +0200, Jan Tulak wrote:
>> This patch adds infrastructure that will be used in subsequent patches.
>>
>> The Value field is the actual value used in computations for creating
>> the filesystem.  This is initialized with sensible default values. If
>> initialized to 0, the value is considered disabled. User input will
>> override default values.  If the field is a string and not a number, the
>> value is set to a positive non-zero number when user input has been
>> supplied.
>>
>> Add functions that can be used to get/set values to opts table.
>>
>> Signed-off-by: Jan Tulak <jtulak@redhat.com>
>>
>> ---
>> Change:
>> * make the value type to be long long instead of uint64 for now
>> * add collateral updates
>> * add bounds to get/set functions
>> * update the description of commit/in code
>> * merge with another patch, which adds the get/set functions.
>> ---
>>  mkfs/xfs_mkfs.c | 194 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>  1 file changed, 194 insertions(+)
>>
>> diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
>> index 3e7ba5f0..61ef09e8 100644
>> --- a/mkfs/xfs_mkfs.c
>> +++ b/mkfs/xfs_mkfs.c
>> @@ -117,6 +117,13 @@ unsigned int             sectorsize;
>>   *     Filled raw string from the user, so we never lose that information e.g.
>>   *     to print it back in case of an issue.
>>   *
>> + *   value OPTIONAL
>> + *     The actual value used in computations for creating the filesystem.
>> + *     This is initialized with sensible default values. If initialized to 0,
>> + *     the value is considered disabled. User input will override default
>> + *     values. If the field is a string and not a number, the value is set to
>> + *     a positive non-zero number when user input has been supplied.
>> + *
>>   */
>>  struct opt_params {
>>       int             index;
>> @@ -134,6 +141,7 @@ struct opt_params {
>>               long long       maxval;
>>               long long       flagval;
>>               char            *raw_input;
>> +             long long       value;
>
> I think this is less sensitive for mkfs options, but for structures
> please keep variables of the same type together to reduce memory usage.
> That (char *) between the (long long) creates a 4-byte padding hole on
> 32-bit machines.  I recommend pahole for things like this.

Fixing.. I'm theoretically aware of this issue, but I don't have it
under my skin yet. And thanks for the tool, I didn't knew about it.

>
>>       }               subopt_params[MAX_SUBOPTS];
>>  } opts[MAX_OPTS] = {
>>  #define OPT_B        0
>> @@ -750,6 +758,180 @@ struct opt_params {
>>  #define WHACK_SIZE (128 * 1024)
>>
>>  /*
>> + * Get and set values to the opts table.
>> + */
>> +static int
>> +get_conf_val_unsafe(int opt, int subopt, uint64_t *output)
>> +{
>> +     if (subopt < 0 || subopt >= MAX_SUBOPTS ||
>> +         opt < 0 || opt >= MAX_OPTS) {
>> +             fprintf(stderr,
>> +             "This is a bug: get_conf_val called with invalid opt/subopt: %d/%d\n",
>
> Oh yeah, I forgot to mention this a few patches back -- if these remain
> fprintfs, then shouldn't the string be enclosed in _() so that strings
> can be localized?

Sure, I realised that as well when fixing the indentation in the first patch.

>
>> +             opt, subopt);
>> +             return -EINVAL;
>> +     }
>> +     *output = opts[opt].subopt_params[subopt].value;
>> +     return 0;
>> +}
>> +
>> +static long long
>> +get_conf_val(int opt, int subopt)
>> +{
>> +     uint64_t res;
>> +     if (get_conf_val_unsafe(opt, subopt, &res) != 0)
>> +         exit(1);
>
> Tab then space indentation problem here.
>
>> +     return res;
>> +}
>> +
>> +static int
>> +set_conf_val_unsafe(int opt, int subopt, uint64_t val)
>> +{
>> +     if (subopt < 0 || subopt >= MAX_SUBOPTS ||
>> +         opt < 0 || opt >= MAX_OPTS) {
>> +             fprintf(stderr,
>> +             "This is a bug: set_conf_val called with invalid opt/subopt: %d/%d\n",
>> +             opt, subopt);
>> +             return -EINVAL;
>> +     }
>> +     struct subopt_param *sp = &opts[opt].subopt_params[subopt];
>> +     sp->value = val;
>> +
>> +     return 0;
>> +}
>> +
>> +static void
>> +set_conf_val(int opt, int subopt, uint64_t val)
>> +{
>> +     if (set_conf_val_unsafe(opt, subopt, val) != 0)
>> +             exit(1);
>> +}
>> +
>> +/*
>> + * A wrapper around set_conf_val which updates also connected/collateral values.
>> + * E.g. when changing S_LOG, update S_SIZE too.
>> + */
>> +static void
>> +set_conf_val_collateral(int opt, int subopt, uint64_t val)
>
> "collateral"... I hope we're not trying to secure a loan here. :)
>
> I suggest using "connected" (or "correlated") here instead.

OK, thanks. :-)

>
>> +{
>> +     set_conf_val(opt, subopt, val);
>> +
>> +     switch (opt) {
>> +     case OPT_B:
>> +             switch (subopt) {
>> +             case B_LOG:
>> +                     set_conf_val(OPT_B, B_SIZE, 1 << val);
>> +                     break;
>> +             case B_SIZE:
>> +                     set_conf_val(OPT_B, B_LOG,
>> +                             libxfs_highbit32(val));
>> +                     break;
>> +             }
>> +             break;
>> +     case OPT_D:
>> +             switch (subopt) {
>> +             case D_SECTLOG:
>> +                     set_conf_val(OPT_S, S_LOG, val);
>> +                     set_conf_val(OPT_S, S_SECTLOG, val);
>> +                     set_conf_val(OPT_D, D_SECTSIZE,
>> +                                     1 << val);
>> +                     set_conf_val(OPT_S, S_SECTSIZE,
>> +                                     1 << val);
>> +                     set_conf_val(OPT_S, S_SIZE,
>> +                                     1 << val);
>> +                     break;
>> +             case D_SECTSIZE:
>> +                     set_conf_val(OPT_S, S_SIZE, val);
>> +                     set_conf_val(OPT_S, S_SECTSIZE, val);
>> +                     set_conf_val(OPT_D, D_SECTLOG,
>> +                             libxfs_highbit32(val));
>> +                     set_conf_val(OPT_S, S_LOG,
>> +                             libxfs_highbit32(val));
>> +                     set_conf_val(OPT_S, S_SECTLOG,
>> +                             libxfs_highbit32(val));
>> +                     break;
>> +             }
>> +             break;
>> +     case OPT_I:
>> +             switch (subopt) {
>> +             case I_LOG:
>> +                     set_conf_val(OPT_I, I_SIZE, 1 << val);
>> +                     break;
>> +             case I_SIZE:
>> +                     set_conf_val(OPT_I, I_LOG,
>> +                             libxfs_highbit32(val));
>> +                     break;
>> +             }
>> +             break;
>> +     case OPT_L:
>> +             switch (subopt) {
>> +             case L_SECTLOG:
>> +                     set_conf_val(OPT_L, L_SECTSIZE,
>> +                                     1 << val);
>> +                     break;
>> +             case L_SECTSIZE:
>> +                     set_conf_val(OPT_L, L_SECTLOG,
>> +                          libxfs_highbit32(val));
>
> Tab/space indentation problem here too.
>
> (Wondering if the calls here are short enough for a single line?)

Some of them yes, I will fix that.

Jan

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

* [PATCH 1/6 v2] mkfs: Save raw user input field to the opts struct
  2017-08-11 12:30 [PATCH 0/6 v2] mkfs: save user input into opts table Jan Tulak
                   ` (5 preceding siblings ...)
  2017-08-11 12:30 ` [PATCH 6/6] mkfs: extend opt_params with a value field Jan Tulak
@ 2017-08-15 15:08 ` Jan Tulak
  2017-08-15 15:08   ` [PATCH 3/6 v2] mkfs: remove intermediate getstr followed by getnum Jan Tulak
                     ` (4 more replies)
  6 siblings, 5 replies; 37+ messages in thread
From: Jan Tulak @ 2017-08-15 15:08 UTC (permalink / raw)
  To: linux-xfs; +Cc: Jan Tulak

Save exactly what the user gave us for every option.  This way, we will
never lose the information if we need it to print back an issue.
(Just add the infrastructure now, used in the next patches.)

Signed-off-by: Jan Tulak <jtulak@redhat.com>

---
CHANGE:
* test for NULL before strdup in get_conf_raw
* Translation and indentation for fprints
* add set_conf_raw_safe
---
 mkfs/xfs_mkfs.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 88 insertions(+)

diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
index 7bb6408f..adfbd376 100644
--- a/mkfs/xfs_mkfs.c
+++ b/mkfs/xfs_mkfs.c
@@ -107,6 +107,11 @@ unsigned int		sectorsize;
  *     sets what is used with simple specifying the subopt (-d file).
  *     A special SUBOPT_NEEDS_VAL can be used to require a user-given
  *     value in any case.
+ *
+ *   raw_input INTERNAL
+ *     Filled raw string from the user, so we never lose that information e.g.
+ *     to print it back in case of an issue.
+ *
  */
 struct opt_params {
 	const char	name;
@@ -122,6 +127,7 @@ struct opt_params {
 		long long	minval;
 		long long	maxval;
 		long long	defaultval;
+		char		*raw_input;
 	}		subopt_params[MAX_SUBOPTS];
 };
 
@@ -730,6 +736,88 @@ struct opt_params mopts = {
 #define WHACK_SIZE (128 * 1024)
 
 /*
+ * Return 0 on success, -ENOMEM if it could not allocate enough memory for
+ * the string to be saved.
+ */
+static int
+set_conf_raw(struct opt_params *opt, const int subopt, const char *value)
+{
+	if (subopt < 0 || subopt >= MAX_SUBOPTS) {
+		fprintf(stderr,
+			_("This is a bug: set_conf_raw called with invalid "
+			  "opt/subopt: %c/%d\n"),
+			opt->name, subopt);
+		return -EINVAL;
+	}
+	if (value == NULL) {
+		if (opt->subopt_params[subopt].raw_input != NULL)
+			free(opt->subopt_params[subopt].raw_input);
+		opt->subopt_params[subopt].raw_input = NULL;
+	} else {
+		opt->subopt_params[subopt].raw_input = strdup(value);
+		if (opt->subopt_params[subopt].raw_input == NULL)
+			return -ENOMEM;
+	}
+	return 0;
+}
+
+/*
+ * Same as set_conf_raw(), except if any error occurs, return NULL.
+ */
+static void
+set_conf_raw_safe(struct opt_params *opt, const int subopt, const char *value)
+{
+	if (set_conf_raw(opt, subopt, value) != 0) {
+		exit(1);
+	}
+}
+
+/*
+ * Return 0 on success, -ENOMEM if it could not allocate enough memory for
+ * the string to be saved into the out pointer.
+ */
+static int
+get_conf_raw(const struct opt_params *opt, const int subopt, char **out)
+{
+	if (subopt < 0 || subopt >= MAX_SUBOPTS) {
+		fprintf(stderr,
+			_("This is a bug: get_conf_raw called with invalid "
+			  "opt/subopt: %c/%d\n"),
+			opt->name, subopt);
+		return -EINVAL;
+	}
+
+	if (opt->subopt_params[subopt].raw_input == NULL) {
+		*out = NULL;
+		return 0;
+	}
+
+	*out = strdup(opt->subopt_params[subopt].raw_input);
+	if (*out == NULL)
+		return -ENOMEM;
+	return 0;
+
+}
+
+/*
+ * Same as get_conf_raw(), except it returns the string through return.
+ * If any error occurs, return NULL.
+ */
+static char *
+get_conf_raw_safe(const struct opt_params *opt, const int subopt)
+{
+	char *str;
+
+	str = NULL;
+
+	if (get_conf_raw(opt, subopt, &str) == -ENOMEM) {
+		fprintf(stderr, "Out of memory!");
+		return NULL;
+	}
+	return str;
+}
+
+/*
  * Convert lsu to lsunit for 512 bytes blocks and check validity of the values.
  */
 static void
-- 
2.13.3


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

* [PATCH 3/6 v2] mkfs: remove intermediate getstr followed by getnum
  2017-08-15 15:08 ` [PATCH 1/6 v2] mkfs: Save raw user input field to the opts struct Jan Tulak
@ 2017-08-15 15:08   ` Jan Tulak
  2017-08-15 23:20     ` Eric Sandeen
  2017-08-17 11:36     ` Dave Chinner
  2017-08-15 15:08   ` [PATCH 4/6 v2] mkfs: merge tables for opts parsing into one table Jan Tulak
                     ` (3 subsequent siblings)
  4 siblings, 2 replies; 37+ messages in thread
From: Jan Tulak @ 2017-08-15 15:08 UTC (permalink / raw)
  To: linux-xfs; +Cc: Jan Tulak

Some options loaded a number as a string with getstr and converted it to
number with getnum later in the code, without any reason for this
approach.  (They were probably forgotten in some past cleaning.)

This patch changes them to skip the string and use getnum directly in
the main option-parsing loop, as do all the other numerical options.
And as we now have two variables of the same type for the same value,
merge them together. (e.g. former string dsize and number dbytes).

Signed-off-by: Jan Tulak <jtulak@redhat.com>

---
UPDATE:
* in getnum: set_conf_raw -> set_conf_raw_safe
---
 mkfs/xfs_mkfs.c | 90 ++++++++++++++++++++++++++-------------------------------
 1 file changed, 41 insertions(+), 49 deletions(-)

diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
index 6eb52e97..8e32bb34 100644
--- a/mkfs/xfs_mkfs.c
+++ b/mkfs/xfs_mkfs.c
@@ -1415,6 +1415,7 @@ getnum(
 	long long		c;
 
 	check_opt(opts, index, false);
+	set_conf_raw_safe(opts, index, str);
 	/* empty strings might just return a default value */
 	if (!str || *str == '\0') {
 		if (sp->flagval == SUBOPT_NEEDS_VAL)
@@ -1502,13 +1503,13 @@ main(
 	char			*dfile;
 	int			dirblocklog;
 	int			dirblocksize;
-	char			*dsize;
+	uint64_t		dbytes;
 	int			dsu;
 	int			dsw;
 	int			dsunit;
 	int			dswidth;
 	int			dsflag;
-	int			force_overwrite;
+	bool			force_overwrite;
 	struct fsxattr		fsx;
 	int			ilflag;
 	int			imaxpct;
@@ -1527,7 +1528,7 @@ main(
 	xfs_rfsblock_t		logblocks;
 	char			*logfile;
 	int			loginternal;
-	char			*logsize;
+	uint64_t		logbytes;
 	xfs_fsblock_t		logstart;
 	int			lvflag;
 	int			lsflag;
@@ -1556,11 +1557,11 @@ main(
 	char			*protostring;
 	int			qflag;
 	xfs_rfsblock_t		rtblocks;
+	uint64_t		rtbytes;
 	xfs_extlen_t		rtextblocks;
 	xfs_rtblock_t		rtextents;
-	char			*rtextsize;
+	uint64_t		rtextbytes;
 	char			*rtfile;
-	char			*rtsize;
 	xfs_sb_t		*sbp;
 	int			sectorlog;
 	uint64_t		sector_mask;
@@ -1608,7 +1609,8 @@ main(
 	qflag = 0;
 	imaxpct = inodelog = inopblock = isize = 0;
 	dfile = logfile = rtfile = NULL;
-	dsize = logsize = rtsize = rtextsize = protofile = NULL;
+	protofile = NULL;
+	rtbytes = rtextbytes = logbytes = dbytes = 0;
 	dsu = dsw = dsunit = dswidth = lalign = lsu = lsunit = 0;
 	dsflag = nodsflag = norsflag = 0;
 	force_overwrite = 0;
@@ -1672,7 +1674,7 @@ main(
 					xi.dname = getstr(value, &dopts, D_NAME);
 					break;
 				case D_SIZE:
-					dsize = getstr(value, &dopts, D_SIZE);
+					dbytes = getnum(value, &dopts, D_SIZE);
 					break;
 				case D_SUNIT:
 					dsunit = getnum(value, &dopts, D_SUNIT);
@@ -1821,7 +1823,7 @@ main(
 					lvflag = 1;
 					break;
 				case L_SIZE:
-					logsize = getstr(value, &lopts, L_SIZE);
+					logbytes = getnum(value, &lopts, L_SIZE);
 					break;
 				case L_SECTLOG:
 					lsectorlog = getnum(value, &lopts,
@@ -1950,8 +1952,7 @@ main(
 
 				switch (getsubopt(&p, subopts, &value)) {
 				case R_EXTSIZE:
-					rtextsize = getstr(value, &ropts,
-							   R_EXTSIZE);
+					rtextbytes = getnum(value, &ropts, R_EXTSIZE);
 					break;
 				case R_FILE:
 					xi.risfile = getnum(value, &ropts,
@@ -1963,7 +1964,7 @@ main(
 							   R_NAME);
 					break;
 				case R_SIZE:
-					rtsize = getstr(value, &ropts, R_SIZE);
+					rtbytes = getnum(value, &ropts, R_SIZE);
 					break;
 				case R_NOALIGN:
 					norsflag = getnum(value, &ropts,
@@ -2066,14 +2067,14 @@ _("Minimum block size for CRC enabled filesystems is %d bytes.\n"),
 	 * sector size mismatches between the new filesystem and the underlying
 	 * host filesystem.
 	 */
-	check_device_type(dfile, &xi.disfile, !dsize, !dfile,
+	check_device_type(dfile, &xi.disfile, !dbytes, !dfile,
 			  Nflag ? NULL : &xi.dcreat, force_overwrite, "d");
 	if (!loginternal)
-		check_device_type(xi.logname, &xi.lisfile, !logsize, !xi.logname,
-				  Nflag ? NULL : &xi.lcreat,
+		check_device_type(xi.logname, &xi.lisfile, !logbytes,
+				  !xi.logname, Nflag ? NULL : &xi.lcreat,
 				  force_overwrite, "l");
 	if (xi.rtname)
-		check_device_type(xi.rtname, &xi.risfile, !rtsize, !xi.rtname,
+		check_device_type(xi.rtname, &xi.risfile, !rtbytes, !xi.rtname,
 				  Nflag ? NULL : &xi.rcreat,
 				  force_overwrite, "r");
 	if (xi.disfile || xi.lisfile || xi.risfile)
@@ -2254,10 +2255,7 @@ _("rmapbt not supported with realtime devices\n"));
 	}
 
 
-	if (dsize) {
-		uint64_t dbytes;
-
-		dbytes = getnum(dsize, &dopts, D_SIZE);
+	if (dbytes) {
 		if (dbytes % XFS_MIN_BLOCKSIZE) {
 			fprintf(stderr,
 			_("illegal data length %lld, not a multiple of %d\n"),
@@ -2286,10 +2284,7 @@ _("rmapbt not supported with realtime devices\n"));
 		usage();
 	}
 
-	if (logsize) {
-		uint64_t logbytes;
-
-		logbytes = getnum(logsize, &lopts, L_SIZE);
+	if (logbytes) {
 		if (logbytes % XFS_MIN_BLOCKSIZE) {
 			fprintf(stderr,
 			_("illegal log length %lld, not a multiple of %d\n"),
@@ -2303,10 +2298,7 @@ _("rmapbt not supported with realtime devices\n"));
 				(long long)logbytes, blocksize,
 				(long long)(logblocks << blocklog));
 	}
-	if (rtsize) {
-		uint64_t rtbytes;
-
-		rtbytes = getnum(rtsize, &ropts, R_SIZE);
+	if (rtbytes) {
 		if (rtbytes % XFS_MIN_BLOCKSIZE) {
 			fprintf(stderr,
 			_("illegal rt length %lld, not a multiple of %d\n"),
@@ -2323,10 +2315,7 @@ _("rmapbt not supported with realtime devices\n"));
 	/*
 	 * If specified, check rt extent size against its constraints.
 	 */
-	if (rtextsize) {
-		uint64_t rtextbytes;
-
-		rtextbytes = getnum(rtextsize, &ropts, R_EXTSIZE);
+	if (rtextbytes) {
 		if (rtextbytes % blocksize) {
 			fprintf(stderr,
 		_("illegal rt extent size %lld, not a multiple of %d\n"),
@@ -2343,7 +2332,7 @@ _("rmapbt not supported with realtime devices\n"));
 		uint64_t	rswidth;
 		uint64_t	rtextbytes;
 
-		if (!norsflag && !xi.risfile && !(!rtsize && xi.disfile))
+		if (!norsflag && !xi.risfile && !(!rtbytes && xi.disfile))
 			rswidth = ft.rtswidth;
 		else
 			rswidth = 0;
@@ -2458,15 +2447,16 @@ _("rmapbt not supported with realtime devices\n"));
 		rtfile = _("volume rt");
 	else if (!xi.rtdev)
 		rtfile = _("none");
-	if (dsize && xi.dsize > 0 && dblocks > DTOBT(xi.dsize)) {
+	if (dbytes && xi.dsize > 0 && dblocks > DTOBT(xi.dsize)) {
 		fprintf(stderr,
 			_("size %s specified for data subvolume is too large, "
 			"maximum is %lld blocks\n"),
-			dsize, (long long)DTOBT(xi.dsize));
+			get_conf_raw_safe(&dopts, D_SIZE),
+			(long long)DTOBT(xi.dsize));
 		usage();
-	} else if (!dsize && xi.dsize > 0)
+	} else if (!dbytes && xi.dsize > 0)
 		dblocks = DTOBT(xi.dsize);
-	else if (!dsize) {
+	else if (!dbytes) {
 		fprintf(stderr, _("can't get size of data subvolume\n"));
 		usage();
 	}
@@ -2499,22 +2489,23 @@ reported by the device (%u).\n"),
 reported by the device (%u).\n"),
 			lsectorsize, xi.lbsize);
 	}
-	if (rtsize && xi.rtsize > 0 && xi.rtbsize > sectorsize) {
+	if (rtbytes && xi.rtsize > 0 && xi.rtbsize > sectorsize) {
 		fprintf(stderr, _(
 "Warning: the realtime subvolume sector size %u is less than the sector size\n\
 reported by the device (%u).\n"),
 			sectorsize, xi.rtbsize);
 	}
 
-	if (rtsize && xi.rtsize > 0 && rtblocks > DTOBT(xi.rtsize)) {
+	if (rtbytes && xi.rtsize > 0 && rtblocks > DTOBT(xi.rtsize)) {
 		fprintf(stderr,
 			_("size %s specified for rt subvolume is too large, "
 			"maximum is %lld blocks\n"),
-			rtsize, (long long)DTOBT(xi.rtsize));
+			get_conf_raw_safe(&ropts, R_SIZE),
+			(long long)DTOBT(xi.rtsize));
 		usage();
-	} else if (!rtsize && xi.rtsize > 0)
+	} else if (!rtbytes && xi.rtsize > 0)
 		rtblocks = DTOBT(xi.rtsize);
-	else if (rtsize && !xi.rtdev) {
+	else if (rtbytes && !xi.rtdev) {
 		fprintf(stderr,
 			_("size specified for non-existent rt subvolume\n"));
 		usage();
@@ -2720,26 +2711,27 @@ an AG size that is one stripe unit smaller, for example %llu.\n"),
 				   sb_feat.inode_align);
 	ASSERT(min_logblocks);
 	min_logblocks = MAX(XFS_MIN_LOG_BLOCKS, min_logblocks);
-	if (!logsize && dblocks >= (1024*1024*1024) >> blocklog)
+	if (!logbytes && dblocks >= (1024*1024*1024) >> blocklog)
 		min_logblocks = MAX(min_logblocks, XFS_MIN_LOG_BYTES>>blocklog);
-	if (logsize && xi.logBBsize > 0 && logblocks > DTOBT(xi.logBBsize)) {
+	if (logbytes && xi.logBBsize > 0 && logblocks > DTOBT(xi.logBBsize)) {
 		fprintf(stderr,
 _("size %s specified for log subvolume is too large, maximum is %lld blocks\n"),
-			logsize, (long long)DTOBT(xi.logBBsize));
+			get_conf_raw_safe(&lopts, L_SIZE),
+			(long long)DTOBT(xi.logBBsize));
 		usage();
-	} else if (!logsize && xi.logBBsize > 0) {
+	} else if (!logbytes && xi.logBBsize > 0) {
 		logblocks = DTOBT(xi.logBBsize);
-	} else if (logsize && !xi.logdev && !loginternal) {
+	} else if (logbytes && !xi.logdev && !loginternal) {
 		fprintf(stderr,
 			_("size specified for non-existent log subvolume\n"));
 		usage();
-	} else if (loginternal && logsize && logblocks >= dblocks) {
+	} else if (loginternal && logbytes && logblocks >= dblocks) {
 		fprintf(stderr, _("size %lld too large for internal log\n"),
 			(long long)logblocks);
 		usage();
 	} else if (!loginternal && !xi.logdev) {
 		logblocks = 0;
-	} else if (loginternal && !logsize) {
+	} else if (loginternal && !logbytes) {
 
 		if (dblocks < GIGABYTES(1, blocklog)) {
 			/* tiny filesystems get minimum sized logs. */
@@ -2803,7 +2795,7 @@ _("size %s specified for log subvolume is too large, maximum is %lld blocks\n"),
 		 * Readjust the log size to fit within an AG if it was sized
 		 * automatically.
 		 */
-		if (!logsize) {
+		if (!logbytes) {
 			logblocks = MIN(logblocks,
 					libxfs_alloc_ag_max_usable(mp));
 
-- 
2.13.3


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

* [PATCH 4/6 v2] mkfs: merge tables for opts parsing into one table
  2017-08-15 15:08 ` [PATCH 1/6 v2] mkfs: Save raw user input field to the opts struct Jan Tulak
  2017-08-15 15:08   ` [PATCH 3/6 v2] mkfs: remove intermediate getstr followed by getnum Jan Tulak
@ 2017-08-15 15:08   ` Jan Tulak
  2017-08-15 15:08   ` [PATCH 5/6 v2] mkfs: move getnum within the file Jan Tulak
                     ` (2 subsequent siblings)
  4 siblings, 0 replies; 37+ messages in thread
From: Jan Tulak @ 2017-08-15 15:08 UTC (permalink / raw)
  To: linux-xfs; +Cc: Jan Tulak

Merge separate instances of opt_params into one indexable table. Git
makes this patch looks a bit more complicated, but it does not change
values or structure of anything else. It only moves all the "struct
opt_params dopts = {...}", changes indentation for these substructures
and replaces their usage (dopts -> opts[OPT_D]).

The reason for this is to be able to address all options from any single
one, even across OPT_X. Right now, we can do automated conflict checks
only within one OPT_X, but after this, it is possible to extend the
conflict declaration to other options as well.

Signed-off-by: Jan Tulak <jtulak@redhat.com>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
---
Change:
only rebased against changes in previous patches
---
 mkfs/xfs_mkfs.c | 1345 +++++++++++++++++++++++++++++--------------------------
 1 file changed, 698 insertions(+), 647 deletions(-)

diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
index 8e32bb34..cfb3fffa 100644
--- a/mkfs/xfs_mkfs.c
+++ b/mkfs/xfs_mkfs.c
@@ -39,6 +39,7 @@ static int  ispow2(unsigned int i);
 unsigned int		blocksize;
 unsigned int		sectorsize;
 
+#define MAX_OPTS	16
 #define MAX_SUBOPTS	16
 #define SUBOPT_NEEDS_VAL	(-1LL)
 #define MAX_CONFLICTS	8
@@ -49,6 +50,10 @@ unsigned int		sectorsize;
  *
  * Description of the structure members follows:
  *
+ * index MANDATORY
+ *   An integer denoting the position of the specific option in opts array,
+ *   counting from 0 up to MAX_OPTS.
+ *
  * name MANDATORY
  *   Name is a single char, e.g., for '-d file', name is 'd'.
  *
@@ -114,6 +119,7 @@ unsigned int		sectorsize;
  *
  */
 struct opt_params {
+	int		index;
 	const char	name;
 	const char	*subopts[MAX_SUBOPTS];
 
@@ -129,584 +135,592 @@ struct opt_params {
 		long long	flagval;
 		char		*raw_input;
 	}		subopt_params[MAX_SUBOPTS];
-};
-
-struct opt_params bopts = {
-	.name = 'b',
-	.subopts = {
+} opts[MAX_OPTS] = {
+#define OPT_B	0
+	{
+		.index = OPT_B,
+		.name = 'b',
+		.subopts = {
 #define	B_LOG		0
-		"log",
+			"log",
 #define	B_SIZE		1
-		"size",
-		NULL
-	},
-	.subopt_params = {
-		{ .index = B_LOG,
-		  .conflicts = { B_SIZE,
-				 LAST_CONFLICT },
-		  .minval = XFS_MIN_BLOCKSIZE_LOG,
-		  .maxval = XFS_MAX_BLOCKSIZE_LOG,
-		  .flagval = SUBOPT_NEEDS_VAL,
+			"size",
+			NULL
 		},
-		{ .index = B_SIZE,
-		  .convert = true,
-		  .is_power_2 = true,
-		  .conflicts = { B_LOG,
-				 LAST_CONFLICT },
-		  .minval = XFS_MIN_BLOCKSIZE,
-		  .maxval = XFS_MAX_BLOCKSIZE,
-		  .flagval = SUBOPT_NEEDS_VAL,
+		.subopt_params = {
+			{ .index = B_LOG,
+			  .conflicts = { B_SIZE,
+					 LAST_CONFLICT },
+			  .minval = XFS_MIN_BLOCKSIZE_LOG,
+			  .maxval = XFS_MAX_BLOCKSIZE_LOG,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = B_SIZE,
+			  .convert = true,
+			  .is_power_2 = true,
+			  .conflicts = { B_LOG,
+					 LAST_CONFLICT },
+			  .minval = XFS_MIN_BLOCKSIZE,
+			  .maxval = XFS_MAX_BLOCKSIZE,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
 		},
 	},
-};
-
-struct opt_params dopts = {
-	.name = 'd',
-	.subopts = {
-#define	D_AGCOUNT	0
-		"agcount",
-#define	D_FILE		1
-		"file",
-#define	D_NAME		2
-		"name",
-#define	D_SIZE		3
-		"size",
-#define D_SUNIT		4
-		"sunit",
-#define D_SWIDTH	5
-		"swidth",
-#define D_AGSIZE	6
-		"agsize",
-#define D_SU		7
-		"su",
-#define D_SW		8
-		"sw",
-#define D_SECTLOG	9
-		"sectlog",
-#define D_SECTSIZE	10
-		"sectsize",
-#define D_NOALIGN	11
-		"noalign",
-#define D_RTINHERIT	12
-		"rtinherit",
-#define D_PROJINHERIT	13
-		"projinherit",
-#define D_EXTSZINHERIT	14
-		"extszinherit",
-		NULL
-	},
-	.subopt_params = {
-		{ .index = D_AGCOUNT,
-		  .conflicts = { D_AGSIZE,
-				 LAST_CONFLICT },
-		  .minval = 1,
-		  .maxval = XFS_MAX_AGNUMBER,
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = D_FILE,
-		  .conflicts = { LAST_CONFLICT },
-		  .minval = 0,
-		  .maxval = 1,
-		  .flagval = 1,
-		},
-		{ .index = D_NAME,
-		  .conflicts = { LAST_CONFLICT },
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = D_SIZE,
-		  .conflicts = { LAST_CONFLICT },
-		  .convert = true,
-		  .minval = XFS_AG_MIN_BYTES,
-		  .maxval = LLONG_MAX,
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = D_SUNIT,
-		  .conflicts = { D_NOALIGN,
-				 D_SU,
-				 D_SW,
-				 LAST_CONFLICT },
-		  .minval = 0,
-		  .maxval = UINT_MAX,
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = D_SWIDTH,
-		  .conflicts = { D_NOALIGN,
-				 D_SU,
-				 D_SW,
-				 LAST_CONFLICT },
-		  .minval = 0,
-		  .maxval = UINT_MAX,
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = D_AGSIZE,
-		  .conflicts = { D_AGCOUNT,
-				 LAST_CONFLICT },
-		  .convert = true,
-		  .minval = XFS_AG_MIN_BYTES,
-		  .maxval = XFS_AG_MAX_BYTES,
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = D_SU,
-		  .conflicts = { D_NOALIGN,
-				 D_SUNIT,
-				 D_SWIDTH,
-				 LAST_CONFLICT },
-		  .convert = true,
-		  .minval = 0,
-		  .maxval = UINT_MAX,
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = D_SW,
-		  .conflicts = { D_NOALIGN,
-				 D_SUNIT,
-				 D_SWIDTH,
-				 LAST_CONFLICT },
-		  .minval = 0,
-		  .maxval = UINT_MAX,
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = D_SECTLOG,
-		  .conflicts = { D_SECTSIZE,
-				 LAST_CONFLICT },
-		  .minval = XFS_MIN_SECTORSIZE_LOG,
-		  .maxval = XFS_MAX_SECTORSIZE_LOG,
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = D_SECTSIZE,
-		  .conflicts = { D_SECTLOG,
-				 LAST_CONFLICT },
-		  .convert = true,
-		  .is_power_2 = true,
-		  .minval = XFS_MIN_SECTORSIZE,
-		  .maxval = XFS_MAX_SECTORSIZE,
-		  .flagval = SUBOPT_NEEDS_VAL,
+#define OPT_D	1
+	{
+		.index = OPT_D,
+		.name = 'd',
+		.subopts = {
+	#define	D_AGCOUNT	0
+			"agcount",
+	#define	D_FILE		1
+			"file",
+	#define	D_NAME		2
+			"name",
+	#define	D_SIZE		3
+			"size",
+	#define D_SUNIT		4
+			"sunit",
+	#define D_SWIDTH	5
+			"swidth",
+	#define D_AGSIZE	6
+			"agsize",
+	#define D_SU		7
+			"su",
+	#define D_SW		8
+			"sw",
+	#define D_SECTLOG	9
+			"sectlog",
+	#define D_SECTSIZE	10
+			"sectsize",
+	#define D_NOALIGN	11
+			"noalign",
+	#define D_RTINHERIT	12
+			"rtinherit",
+	#define D_PROJINHERIT	13
+			"projinherit",
+	#define D_EXTSZINHERIT	14
+			"extszinherit",
+			NULL
 		},
-		{ .index = D_NOALIGN,
-		  .conflicts = { D_SU,
-				 D_SW,
-				 D_SUNIT,
-				 D_SWIDTH,
-				 LAST_CONFLICT },
-		  .minval = 0,
-		  .maxval = 1,
-		  .flagval = 1,
-		},
-		{ .index = D_RTINHERIT,
-		  .conflicts = { LAST_CONFLICT },
-		  .minval = 1,
-		  .maxval = 1,
-		  .flagval = 1,
-		},
-		{ .index = D_PROJINHERIT,
-		  .conflicts = { LAST_CONFLICT },
-		  .minval = 0,
-		  .maxval = UINT_MAX,
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = D_EXTSZINHERIT,
-		  .conflicts = { LAST_CONFLICT },
-		  .minval = 0,
-		  .maxval = UINT_MAX,
-		  .flagval = SUBOPT_NEEDS_VAL,
+		.subopt_params = {
+			{ .index = D_AGCOUNT,
+			  .conflicts = { D_AGSIZE,
+					 LAST_CONFLICT },
+			  .minval = 1,
+			  .maxval = XFS_MAX_AGNUMBER,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = D_FILE,
+			  .conflicts = { LAST_CONFLICT },
+			  .minval = 0,
+			  .maxval = 1,
+			  .flagval = 1,
+			},
+			{ .index = D_NAME,
+			  .conflicts = { LAST_CONFLICT },
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = D_SIZE,
+			  .conflicts = { LAST_CONFLICT },
+			  .convert = true,
+			  .minval = XFS_AG_MIN_BYTES,
+			  .maxval = LLONG_MAX,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = D_SUNIT,
+			  .conflicts = { D_NOALIGN,
+					 D_SU,
+					 D_SW,
+					 LAST_CONFLICT },
+			  .minval = 0,
+			  .maxval = UINT_MAX,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = D_SWIDTH,
+			  .conflicts = { D_NOALIGN,
+					 D_SU,
+					 D_SW,
+					 LAST_CONFLICT },
+			  .minval = 0,
+			  .maxval = UINT_MAX,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = D_AGSIZE,
+			  .conflicts = { D_AGCOUNT,
+					 LAST_CONFLICT },
+			  .convert = true,
+			  .minval = XFS_AG_MIN_BYTES,
+			  .maxval = XFS_AG_MAX_BYTES,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = D_SU,
+			  .conflicts = { D_NOALIGN,
+					 D_SUNIT,
+					 D_SWIDTH,
+					 LAST_CONFLICT },
+			  .convert = true,
+			  .minval = 0,
+			  .maxval = UINT_MAX,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = D_SW,
+			  .conflicts = { D_NOALIGN,
+					 D_SUNIT,
+					 D_SWIDTH,
+					 LAST_CONFLICT },
+			  .minval = 0,
+			  .maxval = UINT_MAX,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = D_SECTLOG,
+			  .conflicts = { D_SECTSIZE,
+					 LAST_CONFLICT },
+			  .minval = XFS_MIN_SECTORSIZE_LOG,
+			  .maxval = XFS_MAX_SECTORSIZE_LOG,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = D_SECTSIZE,
+			  .conflicts = { D_SECTLOG,
+					 LAST_CONFLICT },
+			  .convert = true,
+			  .is_power_2 = true,
+			  .minval = XFS_MIN_SECTORSIZE,
+			  .maxval = XFS_MAX_SECTORSIZE,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = D_NOALIGN,
+			  .conflicts = { D_SU,
+					 D_SW,
+					 D_SUNIT,
+					 D_SWIDTH,
+					 LAST_CONFLICT },
+			  .minval = 0,
+			  .maxval = 1,
+			  .flagval = 1,
+			},
+			{ .index = D_RTINHERIT,
+			  .conflicts = { LAST_CONFLICT },
+			  .minval = 0,
+			  .maxval = 1,
+			  .flagval = 1,
+			},
+			{ .index = D_PROJINHERIT,
+			  .conflicts = { LAST_CONFLICT },
+			  .minval = 0,
+			  .maxval = UINT_MAX,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = D_EXTSZINHERIT,
+			  .conflicts = { LAST_CONFLICT },
+			  .minval = 0,
+			  .maxval = UINT_MAX,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
 		},
 	},
-};
-
-
-struct opt_params iopts = {
-	.name = 'i',
-	.subopts = {
+#define OPT_I	2
+	{
+		.index = OPT_I,
+		.name = 'i',
+		.subopts = {
 #define	I_ALIGN		0
-		"align",
+			"align",
 #define	I_LOG		1
-		"log",
+			"log",
 #define	I_MAXPCT	2
-		"maxpct",
+			"maxpct",
 #define	I_PERBLOCK	3
-		"perblock",
+			"perblock",
 #define	I_SIZE		4
-		"size",
+			"size",
 #define	I_ATTR		5
-		"attr",
+			"attr",
 #define	I_PROJID32BIT	6
-		"projid32bit",
+			"projid32bit",
 #define I_SPINODES	7
-		"sparse",
-		NULL
-	},
-	.subopt_params = {
-		{ .index = I_ALIGN,
-		  .conflicts = { LAST_CONFLICT },
-		  .minval = 0,
-		  .maxval = 1,
-		  .flagval = 1,
-		},
-		{ .index = I_LOG,
-		  .conflicts = { I_PERBLOCK,
-				 I_SIZE,
-				 LAST_CONFLICT },
-		  .minval = XFS_DINODE_MIN_LOG,
-		  .maxval = XFS_DINODE_MAX_LOG,
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = I_MAXPCT,
-		  .conflicts = { LAST_CONFLICT },
-		  .minval = 0,
-		  .maxval = 100,
-		  .flagval = SUBOPT_NEEDS_VAL,
+			"sparse",
+			NULL
 		},
-		{ .index = I_PERBLOCK,
-		  .conflicts = { I_LOG,
-				 I_SIZE,
-				 LAST_CONFLICT },
-		  .is_power_2 = true,
-		  .minval = XFS_MIN_INODE_PERBLOCK,
-		  .maxval = XFS_MAX_BLOCKSIZE / XFS_DINODE_MIN_SIZE,
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = I_SIZE,
-		  .conflicts = { I_PERBLOCK,
-				 I_LOG,
-				 LAST_CONFLICT },
-		  .is_power_2 = true,
-		  .minval = XFS_DINODE_MIN_SIZE,
-		  .maxval = XFS_DINODE_MAX_SIZE,
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = I_ATTR,
-		  .conflicts = { LAST_CONFLICT },
-		  .minval = 0,
-		  .maxval = 2,
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = I_PROJID32BIT,
-		  .conflicts = { LAST_CONFLICT },
-		  .minval = 0,
-		  .maxval = 1,
-		  .flagval = 1,
-		},
-		{ .index = I_SPINODES,
-		  .conflicts = { LAST_CONFLICT },
-		  .minval = 0,
-		  .maxval = 1,
-		  .flagval = 1,
+		.subopt_params = {
+			{ .index = I_ALIGN,
+			  .conflicts = { LAST_CONFLICT },
+			  .minval = 0,
+			  .maxval = 1,
+			  .flagval = 1,
+			},
+			{ .index = I_LOG,
+			  .conflicts = { I_PERBLOCK,
+					 I_SIZE,
+					 LAST_CONFLICT },
+			  .minval = XFS_DINODE_MIN_LOG,
+			  .maxval = XFS_DINODE_MAX_LOG,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = I_MAXPCT,
+			  .conflicts = { LAST_CONFLICT },
+			  .minval = 0,
+			  .maxval = 100,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = I_PERBLOCK,
+			  .conflicts = { I_LOG,
+					 I_SIZE,
+					 LAST_CONFLICT },
+			  .is_power_2 = true,
+			  .minval = XFS_MIN_INODE_PERBLOCK,
+			  .maxval = XFS_MAX_BLOCKSIZE / XFS_DINODE_MIN_SIZE,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = I_SIZE,
+			  .conflicts = { I_PERBLOCK,
+					 I_LOG,
+					 LAST_CONFLICT },
+			  .is_power_2 = true,
+			  .minval = XFS_DINODE_MIN_SIZE,
+			  .maxval = XFS_DINODE_MAX_SIZE,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = I_ATTR,
+			  .conflicts = { LAST_CONFLICT },
+			  .minval = 0,
+			  .maxval = 2,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = I_PROJID32BIT,
+			  .conflicts = { LAST_CONFLICT },
+			  .minval = 0,
+			  .maxval = 1,
+			  .flagval = 1,
+			},
+			{ .index = I_SPINODES,
+			  .conflicts = { LAST_CONFLICT },
+			  .minval = 0,
+			  .maxval = 1,
+			  .flagval = 1,
+			},
 		},
 	},
-};
-
-struct opt_params lopts = {
-	.name = 'l',
-	.subopts = {
-#define	L_AGNUM		0
-		"agnum",
-#define	L_INTERNAL	1
-		"internal",
-#define	L_SIZE		2
-		"size",
-#define L_VERSION	3
-		"version",
-#define L_SUNIT		4
-		"sunit",
-#define L_SU		5
-		"su",
-#define L_DEV		6
-		"logdev",
-#define	L_SECTLOG	7
-		"sectlog",
-#define	L_SECTSIZE	8
-		"sectsize",
-#define	L_FILE		9
-		"file",
-#define	L_NAME		10
-		"name",
-#define	L_LAZYSBCNTR	11
-		"lazy-count",
-		NULL
-	},
-	.subopt_params = {
-		{ .index = L_AGNUM,
-		  .conflicts = { L_DEV,
-				 LAST_CONFLICT },
-		  .minval = 0,
-		  .maxval = UINT_MAX,
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = L_INTERNAL,
-		  .conflicts = { L_FILE,
-				 L_DEV,
-				 LAST_CONFLICT },
-		  .minval = 0,
-		  .maxval = 1,
-		  .flagval = 1,
+#define OPT_L	3
+	{
+		.index = OPT_L,
+		.name = 'l',
+		.subopts = {
+	#define	L_AGNUM		0
+			"agnum",
+	#define	L_INTERNAL	1
+			"internal",
+	#define	L_SIZE		2
+			"size",
+	#define L_VERSION	3
+			"version",
+	#define L_SUNIT		4
+			"sunit",
+	#define L_SU		5
+			"su",
+	#define L_DEV		6
+			"logdev",
+	#define	L_SECTLOG	7
+			"sectlog",
+	#define	L_SECTSIZE	8
+			"sectsize",
+	#define	L_FILE		9
+			"file",
+	#define	L_NAME		10
+			"name",
+	#define	L_LAZYSBCNTR	11
+			"lazy-count",
+			NULL
 		},
-		{ .index = L_SIZE,
-		  .conflicts = { LAST_CONFLICT },
-		  .convert = true,
-		  .minval = 2 * 1024 * 1024LL,	/* XXX: XFS_MIN_LOG_BYTES */
-		  .maxval = XFS_MAX_LOG_BYTES,
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = L_VERSION,
-		  .conflicts = { LAST_CONFLICT },
-		  .minval = 1,
-		  .maxval = 2,
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = L_SUNIT,
-		  .conflicts = { L_SU,
-				 LAST_CONFLICT },
-		  .minval = 1,
-		  .maxval = BTOBB(XLOG_MAX_RECORD_BSIZE),
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = L_SU,
-		  .conflicts = { L_SUNIT,
-				 LAST_CONFLICT },
-		  .convert = true,
-		  .minval = BBTOB(1),
-		  .maxval = XLOG_MAX_RECORD_BSIZE,
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = L_DEV,
-		  .conflicts = { L_AGNUM,
-				 L_INTERNAL,
-				 LAST_CONFLICT },
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = L_SECTLOG,
-		  .conflicts = { L_SECTSIZE,
-				 LAST_CONFLICT },
-		  .minval = XFS_MIN_SECTORSIZE_LOG,
-		  .maxval = XFS_MAX_SECTORSIZE_LOG,
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = L_SECTSIZE,
-		  .conflicts = { L_SECTLOG,
-				 LAST_CONFLICT },
-		  .convert = true,
-		  .is_power_2 = true,
-		  .minval = XFS_MIN_SECTORSIZE,
-		  .maxval = XFS_MAX_SECTORSIZE,
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = L_FILE,
-		  .conflicts = { L_INTERNAL,
-				 LAST_CONFLICT },
-		  .minval = 0,
-		  .maxval = 1,
-		  .flagval = 1,
-		},
-		{ .index = L_NAME,
-		  .conflicts = { L_AGNUM,
-				 L_INTERNAL,
-				 LAST_CONFLICT },
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = L_LAZYSBCNTR,
-		  .conflicts = { LAST_CONFLICT },
-		  .minval = 0,
-		  .maxval = 1,
-		  .flagval = 1,
+		.subopt_params = {
+			{ .index = L_AGNUM,
+			  .conflicts = { L_DEV,
+					 LAST_CONFLICT },
+			  .minval = 0,
+			  .maxval = UINT_MAX,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = L_INTERNAL,
+			  .conflicts = { L_FILE,
+					 L_DEV,
+					 LAST_CONFLICT },
+			  .minval = 0,
+			  .maxval = 1,
+			  .flagval = 1,
+			},
+			{ .index = L_SIZE,
+			  .conflicts = { LAST_CONFLICT },
+			  .convert = true,
+			  .minval = 2 * 1024 * 1024LL,	/* XXX: XFS_MIN_LOG_BYTES */
+			  .maxval = XFS_MAX_LOG_BYTES,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = L_VERSION,
+			  .conflicts = { LAST_CONFLICT },
+			  .minval = 1,
+			  .maxval = 2,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = L_SUNIT,
+			  .conflicts = { L_SU,
+					 LAST_CONFLICT },
+			  .minval = 1,
+			  .maxval = BTOBB(XLOG_MAX_RECORD_BSIZE),
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = L_SU,
+			  .conflicts = { L_SUNIT,
+					 LAST_CONFLICT },
+			  .convert = true,
+			  .minval = BBTOB(1),
+			  .maxval = XLOG_MAX_RECORD_BSIZE,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = L_DEV,
+			  .conflicts = { L_AGNUM,
+					 L_INTERNAL,
+					 LAST_CONFLICT },
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = L_SECTLOG,
+			  .conflicts = { L_SECTSIZE,
+					 LAST_CONFLICT },
+			  .minval = XFS_MIN_SECTORSIZE_LOG,
+			  .maxval = XFS_MAX_SECTORSIZE_LOG,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = L_SECTSIZE,
+			  .conflicts = { L_SECTLOG,
+					 LAST_CONFLICT },
+			  .convert = true,
+			  .is_power_2 = true,
+			  .minval = XFS_MIN_SECTORSIZE,
+			  .maxval = XFS_MAX_SECTORSIZE,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = L_FILE,
+			  .conflicts = { L_INTERNAL,
+					 LAST_CONFLICT },
+			  .minval = 0,
+			  .maxval = 1,
+			  .flagval = 1,
+			},
+			{ .index = L_NAME,
+			  .conflicts = { L_AGNUM,
+					 L_INTERNAL,
+					 LAST_CONFLICT },
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = L_LAZYSBCNTR,
+			  .conflicts = { LAST_CONFLICT },
+			  .minval = 0,
+			  .maxval = 1,
+			  .flagval = 1,
+			},
 		},
 	},
-};
-
-struct opt_params nopts = {
-	.name = 'n',
-	.subopts = {
-#define	N_LOG		0
-		"log",
-#define	N_SIZE		1
-		"size",
-#define	N_VERSION	2
-		"version",
-#define	N_FTYPE		3
-		"ftype",
-	NULL,
-	},
-	.subopt_params = {
-		{ .index = N_LOG,
-		  .conflicts = { N_SIZE,
-				 LAST_CONFLICT },
-		  .minval = XFS_MIN_REC_DIRSIZE,
-		  .maxval = XFS_MAX_BLOCKSIZE_LOG,
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = N_SIZE,
-		  .conflicts = { N_LOG,
-				 LAST_CONFLICT },
-		  .convert = true,
-		  .is_power_2 = true,
-		  .minval = 1 << XFS_MIN_REC_DIRSIZE,
-		  .maxval = XFS_MAX_BLOCKSIZE,
-		  .flagval = SUBOPT_NEEDS_VAL,
+#define OPT_N	4
+	{
+		.index = OPT_N,
+		.name = 'n',
+		.subopts = {
+	#define	N_LOG		0
+			"log",
+	#define	N_SIZE		1
+			"size",
+	#define	N_VERSION	2
+			"version",
+	#define	N_FTYPE		3
+			"ftype",
+		NULL,
 		},
-		{ .index = N_VERSION,
-		  .conflicts = { LAST_CONFLICT },
-		  .minval = 2,
-		  .maxval = 2,
-		  .flagval = SUBOPT_NEEDS_VAL,
+		.subopt_params = {
+			{ .index = N_LOG,
+			  .conflicts = { N_SIZE,
+					 LAST_CONFLICT },
+			  .minval = XFS_MIN_REC_DIRSIZE,
+			  .maxval = XFS_MAX_BLOCKSIZE_LOG,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = N_SIZE,
+			  .conflicts = { N_LOG,
+					 LAST_CONFLICT },
+			  .convert = true,
+			  .is_power_2 = true,
+			  .minval = 1 << XFS_MIN_REC_DIRSIZE,
+			  .maxval = XFS_MAX_BLOCKSIZE,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = N_VERSION,
+			  .conflicts = { LAST_CONFLICT },
+			  .minval = 2,
+			  .maxval = 2,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = N_FTYPE,
+			  .conflicts = { LAST_CONFLICT },
+			  .minval = 0,
+			  .maxval = 1,
+			  .flagval = 1,
+			},
 		},
-		{ .index = N_FTYPE,
-		  .conflicts = { LAST_CONFLICT },
-		  .minval = 0,
-		  .maxval = 1,
-		  .flagval = 1,
-		},
-	},
-};
-
-struct opt_params ropts = {
-	.name = 'r',
-	.subopts = {
-#define	R_EXTSIZE	0
-		"extsize",
-#define	R_SIZE		1
-		"size",
-#define	R_DEV		2
-		"rtdev",
-#define	R_FILE		3
-		"file",
-#define	R_NAME		4
-		"name",
-#define R_NOALIGN	5
-		"noalign",
-		NULL
 	},
-	.subopt_params = {
-		{ .index = R_EXTSIZE,
-		  .conflicts = { LAST_CONFLICT },
-		  .convert = true,
-		  .minval = XFS_MIN_RTEXTSIZE,
-		  .maxval = XFS_MAX_RTEXTSIZE,
-		  .flagval = SUBOPT_NEEDS_VAL,
+#define OPT_R	5
+	{
+		.index = OPT_R,
+		.name = 'r',
+		.subopts = {
+	#define	R_EXTSIZE	0
+			"extsize",
+	#define	R_SIZE		1
+			"size",
+	#define	R_DEV		2
+			"rtdev",
+	#define	R_FILE		3
+			"file",
+	#define	R_NAME		4
+			"name",
+	#define R_NOALIGN	5
+			"noalign",
+			NULL
 		},
-		{ .index = R_SIZE,
-		  .conflicts = { LAST_CONFLICT },
-		  .convert = true,
-		  .minval = 0,
-		  .maxval = LLONG_MAX,
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = R_DEV,
-		  .conflicts = { LAST_CONFLICT },
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = R_FILE,
-		  .minval = 0,
-		  .maxval = 1,
-		  .flagval = 1,
-		  .conflicts = { LAST_CONFLICT },
-		},
-		{ .index = R_NAME,
-		  .conflicts = { LAST_CONFLICT },
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = R_NOALIGN,
-		  .minval = 0,
-		  .maxval = 1,
-		  .flagval = 1,
-		  .conflicts = { LAST_CONFLICT },
+		.subopt_params = {
+			{ .index = R_EXTSIZE,
+			  .conflicts = { LAST_CONFLICT },
+			  .convert = true,
+			  .minval = XFS_MIN_RTEXTSIZE,
+			  .maxval = XFS_MAX_RTEXTSIZE,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = R_SIZE,
+			  .conflicts = { LAST_CONFLICT },
+			  .convert = true,
+			  .minval = 0,
+			  .maxval = LLONG_MAX,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = R_DEV,
+			  .conflicts = { LAST_CONFLICT },
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = R_FILE,
+			  .minval = 0,
+			  .maxval = 1,
+			  .flagval = 1,
+			  .conflicts = { LAST_CONFLICT },
+			},
+			{ .index = R_NAME,
+			  .conflicts = { LAST_CONFLICT },
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = R_NOALIGN,
+			  .minval = 0,
+			  .maxval = 1,
+			  .flagval = 1,
+			  .conflicts = { LAST_CONFLICT },
+			},
 		},
 	},
-};
-
-struct opt_params sopts = {
-	.name = 's',
-	.subopts = {
-#define	S_LOG		0
-		"log",
-#define	S_SECTLOG	1
-		"sectlog",
-#define	S_SIZE		2
-		"size",
-#define	S_SECTSIZE	3
-		"sectsize",
-		NULL
-	},
-	.subopt_params = {
-		{ .index = S_LOG,
-		  .conflicts = { S_SIZE,
-				 S_SECTSIZE,
-				 LAST_CONFLICT },
-		  .minval = XFS_MIN_SECTORSIZE_LOG,
-		  .maxval = XFS_MAX_SECTORSIZE_LOG,
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = S_SECTLOG,
-		  .conflicts = { S_SIZE,
-				 S_SECTSIZE,
-				 LAST_CONFLICT },
-		  .minval = XFS_MIN_SECTORSIZE_LOG,
-		  .maxval = XFS_MAX_SECTORSIZE_LOG,
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = S_SIZE,
-		  .conflicts = { S_LOG,
-				 S_SECTLOG,
-				 LAST_CONFLICT },
-		  .convert = true,
-		  .is_power_2 = true,
-		  .minval = XFS_MIN_SECTORSIZE,
-		  .maxval = XFS_MAX_SECTORSIZE,
-		  .flagval = SUBOPT_NEEDS_VAL,
+#define OPT_S	6
+	{
+		.index = OPT_S,
+		.name = 's',
+		.subopts = {
+	#define	S_LOG		0
+			"log",
+	#define	S_SECTLOG	1
+			"sectlog",
+	#define	S_SIZE		2
+			"size",
+	#define	S_SECTSIZE	3
+			"sectsize",
+			NULL
 		},
-		{ .index = S_SECTSIZE,
-		  .conflicts = { S_LOG,
-				 S_SECTLOG,
-				 LAST_CONFLICT },
-		  .convert = true,
-		  .is_power_2 = true,
-		  .minval = XFS_MIN_SECTORSIZE,
-		  .maxval = XFS_MAX_SECTORSIZE,
-		  .flagval = SUBOPT_NEEDS_VAL,
+		.subopt_params = {
+			{ .index = S_LOG,
+			  .conflicts = { S_SIZE,
+					 S_SECTSIZE,
+					 LAST_CONFLICT },
+			  .minval = XFS_MIN_SECTORSIZE_LOG,
+			  .maxval = XFS_MAX_SECTORSIZE_LOG,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = S_SECTLOG,
+			  .conflicts = { S_SIZE,
+					 S_SECTSIZE,
+					 LAST_CONFLICT },
+			  .minval = XFS_MIN_SECTORSIZE_LOG,
+			  .maxval = XFS_MAX_SECTORSIZE_LOG,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = S_SIZE,
+			  .conflicts = { S_LOG,
+					 S_SECTLOG,
+					 LAST_CONFLICT },
+			  .convert = true,
+			  .is_power_2 = true,
+			  .minval = XFS_MIN_SECTORSIZE,
+			  .maxval = XFS_MAX_SECTORSIZE,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = S_SECTSIZE,
+			  .conflicts = { S_LOG,
+					 S_SECTLOG,
+					 LAST_CONFLICT },
+			  .convert = true,
+			  .is_power_2 = true,
+			  .minval = XFS_MIN_SECTORSIZE,
+			  .maxval = XFS_MAX_SECTORSIZE,
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
 		},
 	},
-};
-
-struct opt_params mopts = {
-	.name = 'm',
-	.subopts = {
-#define	M_CRC		0
-		"crc",
-#define M_FINOBT	1
-		"finobt",
-#define M_UUID		2
-		"uuid",
-#define M_RMAPBT	3
-		"rmapbt",
-#define M_REFLINK	4
-		"reflink",
-		NULL
-	},
-	.subopt_params = {
-		{ .index = M_CRC,
-		  .conflicts = { LAST_CONFLICT },
-		  .minval = 0,
-		  .maxval = 1,
-		  .flagval = 1,
-		},
-		{ .index = M_FINOBT,
-		  .conflicts = { LAST_CONFLICT },
-		  .minval = 0,
-		  .maxval = 1,
-		  .flagval = 1,
+#define OPT_M	7
+	{
+		.index = OPT_M,
+		.name = 'm',
+		.subopts = {
+	#define	M_CRC		0
+			"crc",
+	#define M_FINOBT	1
+			"finobt",
+	#define M_UUID		2
+			"uuid",
+	#define M_RMAPBT	3
+			"rmapbt",
+	#define M_REFLINK	4
+			"reflink",
+			NULL
 		},
-		{ .index = M_UUID,
-		  .conflicts = { LAST_CONFLICT },
-		  .flagval = SUBOPT_NEEDS_VAL,
-		},
-		{ .index = M_RMAPBT,
-		  .conflicts = { LAST_CONFLICT },
-		  .minval = 0,
-		  .maxval = 1,
-		  .flagval = 1,
-		},
-		{ .index = M_REFLINK,
-		  .conflicts = { LAST_CONFLICT },
-		  .minval = 0,
-		  .maxval = 1,
-		  .flagval = 1,
+		.subopt_params = {
+			{ .index = M_CRC,
+			  .conflicts = { LAST_CONFLICT },
+			  .minval = 0,
+			  .maxval = 1,
+			  .flagval = 1,
+			},
+			{ .index = M_FINOBT,
+			  .conflicts = { LAST_CONFLICT },
+			  .minval = 0,
+			  .maxval = 1,
+			  .flagval = 1,
+			},
+			{ .index = M_UUID,
+			  .conflicts = { LAST_CONFLICT },
+			  .flagval = SUBOPT_NEEDS_VAL,
+			},
+			{ .index = M_RMAPBT,
+			.conflicts = { LAST_CONFLICT },
+			.minval = 0,
+			.maxval = 1,
+			.flagval = 1,
+			},
+			{ .index = M_REFLINK,
+			  .conflicts = { LAST_CONFLICT },
+			  .minval = 0,
+			  .maxval = 1,
+			  .flagval = 1,
+			},
 		},
 	},
 };
@@ -740,22 +754,23 @@ struct opt_params mopts = {
  * the string to be saved.
  */
 static int
-set_conf_raw(struct opt_params *opt, const int subopt, const char *value)
+set_conf_raw(const int opt, const int subopt, const char *value)
 {
-	if (subopt < 0 || subopt >= MAX_SUBOPTS) {
+	if (subopt < 0 || subopt >= MAX_SUBOPTS ||
+	    opt < 0 || opt >= MAX_OPTS) {
 		fprintf(stderr,
 			_("This is a bug: set_conf_raw called with invalid "
-			  "opt/subopt: %c/%d\n"),
-			opt->name, subopt);
+			  "opt/subopt: %d/%d\n"),
+			opt, subopt);
 		return -EINVAL;
 	}
 	if (value == NULL) {
-		if (opt->subopt_params[subopt].raw_input != NULL)
-			free(opt->subopt_params[subopt].raw_input);
-		opt->subopt_params[subopt].raw_input = NULL;
+		if (opts[opt].subopt_params[subopt].raw_input != NULL)
+			free(opts[opt].subopt_params[subopt].raw_input);
+		opts[opt].subopt_params[subopt].raw_input = NULL;
 	} else {
-		opt->subopt_params[subopt].raw_input = strdup(value);
-		if (opt->subopt_params[subopt].raw_input == NULL)
+		opts[opt].subopt_params[subopt].raw_input = strdup(value);
+		if (opts[opt].subopt_params[subopt].raw_input == NULL)
 			return -ENOMEM;
 	}
 	return 0;
@@ -765,7 +780,7 @@ set_conf_raw(struct opt_params *opt, const int subopt, const char *value)
  * Same as set_conf_raw(), except if any error occurs, return NULL.
  */
 static void
-set_conf_raw_safe(struct opt_params *opt, const int subopt, const char *value)
+set_conf_raw_safe(const int opt, const int subopt, const char *value)
 {
 	if (set_conf_raw(opt, subopt, value) != 0) {
 		exit(1);
@@ -777,26 +792,26 @@ set_conf_raw_safe(struct opt_params *opt, const int subopt, const char *value)
  * the string to be saved into the out pointer.
  */
 static int
-get_conf_raw(const struct opt_params *opt, const int subopt, char **out)
+get_conf_raw(const int opt, const int subopt, char **out)
 {
-	if (subopt < 0 || subopt >= MAX_SUBOPTS) {
+	if (subopt < 0 || subopt >= MAX_SUBOPTS ||
+	    opt < 0 || opt >= MAX_OPTS) {
 		fprintf(stderr,
 			_("This is a bug: get_conf_raw called with invalid "
-			  "opt/subopt: %c/%d\n"),
-			opt->name, subopt);
+			  "opt/subopt: %d/%d\n"),
+			opt, subopt);
 		return -EINVAL;
 	}
 
-	if (opt->subopt_params[subopt].raw_input == NULL) {
+	if (opts[opt].subopt_params[subopt].raw_input == NULL) {
 		*out = NULL;
 		return 0;
 	}
 
-	*out = strdup(opt->subopt_params[subopt].raw_input);
+	*out = strdup(opts[opt].subopt_params[subopt].raw_input);
 	if (*out == NULL)
 		return -ENOMEM;
 	return 0;
-
 }
 
 /*
@@ -804,7 +819,7 @@ get_conf_raw(const struct opt_params *opt, const int subopt, char **out)
  * If any error occurs, return NULL.
  */
 static char *
-get_conf_raw_safe(const struct opt_params *opt, const int subopt)
+get_conf_raw_safe(const int opt, const int subopt)
 {
 	char *str;
 
@@ -1415,7 +1430,7 @@ getnum(
 	long long		c;
 
 	check_opt(opts, index, false);
-	set_conf_raw_safe(opts, index, str);
+	set_conf_raw_safe(opts->index, index, str);
 	/* empty strings might just return a default value */
 	if (!str || *str == '\0') {
 		if (sp->flagval == SUBOPT_NEEDS_VAL)
@@ -1630,17 +1645,19 @@ main(
 		case 'b':
 			p = optarg;
 			while (*p != '\0') {
-				char	**subopts = (char **)bopts.subopts;
+				char	**subopts =
+						(char **)opts[OPT_B].subopts;
 				char	*value;
 
 				switch (getsubopt(&p, subopts, &value)) {
 				case B_LOG:
-					blocklog = getnum(value, &bopts, B_LOG);
+					blocklog = getnum(value, &opts[OPT_B],
+								B_LOG);
 					blocksize = 1 << blocklog;
 					blflag = 1;
 					break;
 				case B_SIZE:
-					blocksize = getnum(value, &bopts,
+					blocksize = getnum(value, &opts[OPT_B],
 							   B_SIZE);
 					blocklog = libxfs_highbit32(blocksize);
 					bsflag = 1;
@@ -1653,78 +1670,86 @@ main(
 		case 'd':
 			p = optarg;
 			while (*p != '\0') {
-				char	**subopts = (char **)dopts.subopts;
+				char	**subopts =
+						(char **)opts[OPT_D].subopts;
 				char	*value;
 
 				switch (getsubopt(&p, subopts, &value)) {
 				case D_AGCOUNT:
-					agcount = getnum(value, &dopts,
+					agcount = getnum(value, &opts[OPT_D],
 							 D_AGCOUNT);
 					daflag = 1;
 					break;
 				case D_AGSIZE:
-					agsize = getnum(value, &dopts, D_AGSIZE);
+					agsize = getnum(value, &opts[OPT_D],
+								D_AGSIZE);
 					dasize = 1;
 					break;
 				case D_FILE:
-					xi.disfile = getnum(value, &dopts,
-							    D_FILE);
+					xi.disfile = getnum(value,
+						&opts[OPT_D], D_FILE);
 					break;
 				case D_NAME:
-					xi.dname = getstr(value, &dopts, D_NAME);
+					xi.dname = getstr(value, &opts[OPT_D],
+								D_NAME);
 					break;
 				case D_SIZE:
-					dbytes = getnum(value, &dopts, D_SIZE);
+					dbytes = getnum(value, &opts[OPT_D],
+								D_SIZE);
 					break;
 				case D_SUNIT:
-					dsunit = getnum(value, &dopts, D_SUNIT);
+					dsunit = getnum(value, &opts[OPT_D],
+								D_SUNIT);
 					dsflag = 1;
 					break;
 				case D_SWIDTH:
-					dswidth = getnum(value, &dopts,
+					dswidth = getnum(value, &opts[OPT_D],
 							 D_SWIDTH);
 					dsflag = 1;
 					break;
 				case D_SU:
-					dsu = getnum(value, &dopts, D_SU);
+					dsu = getnum(value, &opts[OPT_D],
+								D_SU);
 					dsflag = 1;
 					break;
 				case D_SW:
-					dsw = getnum(value, &dopts, D_SW);
+					dsw = getnum(value, &opts[OPT_D],
+								D_SW);
 					dsflag = 1;
 					break;
 				case D_NOALIGN:
-					nodsflag = getnum(value, &dopts,
+					nodsflag = getnum(value, &opts[OPT_D],
 								D_NOALIGN);
 					break;
 				case D_SECTLOG:
-					sectorlog = getnum(value, &dopts,
+					sectorlog = getnum(value, &opts[OPT_D],
 							   D_SECTLOG);
 					sectorsize = 1 << sectorlog;
 					slflag = 1;
 					break;
 				case D_SECTSIZE:
-					sectorsize = getnum(value, &dopts,
-							    D_SECTSIZE);
+					sectorsize = getnum(value,
+						&opts[OPT_D], D_SECTSIZE);
 					sectorlog =
 						libxfs_highbit32(sectorsize);
 					ssflag = 1;
 					break;
 				case D_RTINHERIT:
-					c = getnum(value, &dopts, D_RTINHERIT);
+					c = getnum(value, &opts[OPT_D],
+								D_RTINHERIT);
 					if (c)
 						fsx.fsx_xflags |=
 							XFS_DIFLAG_RTINHERIT;
 					break;
 				case D_PROJINHERIT:
-					fsx.fsx_projid = getnum(value, &dopts,
-								D_PROJINHERIT);
+					fsx.fsx_projid = getnum(value,
+						&opts[OPT_D], D_PROJINHERIT);
 					fsx.fsx_xflags |=
 						XFS_DIFLAG_PROJINHERIT;
 					break;
 				case D_EXTSZINHERIT:
-					fsx.fsx_extsize = getnum(value, &dopts,
-								 D_EXTSZINHERIT);
+					fsx.fsx_extsize = getnum(value,
+						&opts[OPT_D], D_EXTSZINHERIT);
 					fsx.fsx_xflags |=
 						XFS_DIFLAG_EXTSZINHERIT;
 					break;
@@ -1736,46 +1761,51 @@ main(
 		case 'i':
 			p = optarg;
 			while (*p != '\0') {
-				char	**subopts = (char **)iopts.subopts;
+				char	**subopts =
+						(char **)opts[OPT_I].subopts;
 				char	*value;
 
 				switch (getsubopt(&p, subopts, &value)) {
 				case I_ALIGN:
 					sb_feat.inode_align = getnum(value,
-								&iopts, I_ALIGN);
+						&opts[OPT_I], I_ALIGN);
 					break;
 				case I_LOG:
-					inodelog = getnum(value, &iopts, I_LOG);
+					inodelog = getnum(value, &opts[OPT_I],
+								I_LOG);
 					isize = 1 << inodelog;
 					ilflag = 1;
 					break;
 				case I_MAXPCT:
-					imaxpct = getnum(value, &iopts,
+					imaxpct = getnum(value, &opts[OPT_I],
 							 I_MAXPCT);
 					imflag = 1;
 					break;
 				case I_PERBLOCK:
-					inopblock = getnum(value, &iopts,
+					inopblock = getnum(value, &opts[OPT_I],
 							   I_PERBLOCK);
 					ipflag = 1;
 					break;
 				case I_SIZE:
-					isize = getnum(value, &iopts, I_SIZE);
+					isize = getnum(value, &opts[OPT_I],
+								I_SIZE);
 					inodelog = libxfs_highbit32(isize);
 					isflag = 1;
 					break;
 				case I_ATTR:
 					sb_feat.attr_version =
-						getnum(value, &iopts, I_ATTR);
+						getnum(value, &opts[OPT_I],
+								I_ATTR);
 					break;
 				case I_PROJID32BIT:
 					sb_feat.projid16bit =
-						!getnum(value, &iopts,
+						!getnum(value, &opts[OPT_I],
 							I_PROJID32BIT);
 					break;
 				case I_SPINODES:
 					sb_feat.spinodes = getnum(value,
-							&iopts, I_SPINODES);
+								&opts[OPT_I],
+								I_SPINODES);
 					break;
 				default:
 					unknown('i', value);
@@ -1785,63 +1815,70 @@ main(
 		case 'l':
 			p = optarg;
 			while (*p != '\0') {
-				char	**subopts = (char **)lopts.subopts;
+				char	**subopts =
+						(char **)opts[OPT_L].subopts;
 				char	*value;
 
 				switch (getsubopt(&p, subopts, &value)) {
 				case L_AGNUM:
-					logagno = getnum(value, &lopts, L_AGNUM);
+					logagno = getnum(value, &opts[OPT_L],
+								L_AGNUM);
 					laflag = 1;
 					break;
 				case L_FILE:
-					xi.lisfile = getnum(value, &lopts,
-							    L_FILE);
+					xi.lisfile = getnum(value,
+						&opts[OPT_L], L_FILE);
 					break;
 				case L_INTERNAL:
-					loginternal = getnum(value, &lopts,
-							     L_INTERNAL);
+					loginternal = getnum(value,
+						&opts[OPT_L], L_INTERNAL);
 					liflag = 1;
 					break;
 				case L_SU:
-					lsu = getnum(value, &lopts, L_SU);
+					lsu = getnum(value, &opts[OPT_L],
+								L_SU);
 					lsuflag = 1;
 					break;
 				case L_SUNIT:
-					lsunit = getnum(value, &lopts, L_SUNIT);
+					lsunit = getnum(value, &opts[OPT_L],
+								L_SUNIT);
 					lsunitflag = 1;
 					break;
 				case L_NAME:
 				case L_DEV:
-					logfile = getstr(value, &lopts, L_NAME);
+					logfile = getstr(value, &opts[OPT_L],
+								L_NAME);
 					xi.logname = logfile;
 					ldflag = 1;
 					loginternal = 0;
 					break;
 				case L_VERSION:
 					sb_feat.log_version =
-						getnum(value, &lopts, L_VERSION);
+						getnum(value, &opts[OPT_L],
+								L_VERSION);
 					lvflag = 1;
 					break;
 				case L_SIZE:
-					logbytes = getnum(value, &lopts, L_SIZE);
+					logbytes = getnum(value,
+						&opts[OPT_L], L_SIZE);
 					break;
 				case L_SECTLOG:
-					lsectorlog = getnum(value, &lopts,
-							    L_SECTLOG);
+					lsectorlog = getnum(value,
+						&opts[OPT_L], L_SECTLOG);
 					lsectorsize = 1 << lsectorlog;
 					lslflag = 1;
 					break;
 				case L_SECTSIZE:
-					lsectorsize = getnum(value, &lopts,
-							     L_SECTSIZE);
+					lsectorsize = getnum(value,
+						&opts[OPT_L], L_SECTSIZE);
 					lsectorlog =
 						libxfs_highbit32(lsectorsize);
 					lssflag = 1;
 					break;
 				case L_LAZYSBCNTR:
 					sb_feat.lazy_sb_counters =
-							getnum(value, &lopts,
-							       L_LAZYSBCNTR);
+						getnum(value, &opts[OPT_L],
+							L_LAZYSBCNTR);
 					break;
 				default:
 					unknown('l', value);
@@ -1856,19 +1893,21 @@ main(
 		case 'm':
 			p = optarg;
 			while (*p != '\0') {
-				char	**subopts = (char **)mopts.subopts;
+				char	**subopts =
+						(char **)opts[OPT_M].subopts;
 				char	*value;
 
 				switch (getsubopt(&p, subopts, &value)) {
 				case M_CRC:
 					sb_feat.crcs_enabled =
-						getnum(value, &mopts, M_CRC);
+						getnum(value, &opts[OPT_M],
+								M_CRC);
 					if (sb_feat.crcs_enabled)
 						sb_feat.dirftype = true;
 					break;
 				case M_FINOBT:
 					sb_feat.finobt = getnum(
-						value, &mopts, M_FINOBT);
+						value, &opts[OPT_M], M_FINOBT);
 					break;
 				case M_UUID:
 					if (!value || *value == '\0')
@@ -1878,11 +1917,12 @@ main(
 					break;
 				case M_RMAPBT:
 					sb_feat.rmapbt = getnum(
-						value, &mopts, M_RMAPBT);
+						value, &opts[OPT_M], M_RMAPBT);
 					break;
 				case M_REFLINK:
-					sb_feat.reflink = getnum(
-						value, &mopts, M_REFLINK);
+					sb_feat.reflink =
+						getnum(value, &opts[OPT_M],
+							M_REFLINK);
 					break;
 				default:
 					unknown('m', value);
@@ -1892,38 +1932,41 @@ main(
 		case 'n':
 			p = optarg;
 			while (*p != '\0') {
-				char	**subopts = (char **)nopts.subopts;
+				char	**subopts =
+						(char **)opts[OPT_N].subopts;
 				char	*value;
 
 				switch (getsubopt(&p, subopts, &value)) {
 				case N_LOG:
-					dirblocklog = getnum(value, &nopts,
-							     N_LOG);
+					dirblocklog = getnum(value,
+						&opts[OPT_N], N_LOG);
 					dirblocksize = 1 << dirblocklog;
 					nlflag = 1;
 					break;
 				case N_SIZE:
-					dirblocksize = getnum(value, &nopts,
-							      N_SIZE);
+					dirblocksize = getnum(value,
+						&opts[OPT_N], N_SIZE);
 					dirblocklog =
 						libxfs_highbit32(dirblocksize);
 					nsflag = 1;
 					break;
 				case N_VERSION:
-					value = getstr(value, &nopts, N_VERSION);
+					value = getstr(value, &opts[OPT_N],
+								N_VERSION);
 					if (!strcasecmp(value, "ci")) {
 						/* ASCII CI mode */
 						sb_feat.nci = true;
 					} else {
 						sb_feat.dir_version =
-							getnum(value, &nopts,
+							getnum(value,
+							       &opts[OPT_N],
 							       N_VERSION);
 					}
 					nvflag = 1;
 					break;
 				case N_FTYPE:
-					sb_feat.dirftype = getnum(value, &nopts,
-								  N_FTYPE);
+					sb_feat.dirftype = getnum(value,
+						&opts[OPT_N], N_FTYPE);
 					break;
 				default:
 					unknown('n', value);
@@ -1947,27 +1990,30 @@ main(
 		case 'r':
 			p = optarg;
 			while (*p != '\0') {
-				char	**subopts = (char **)ropts.subopts;
+				char	**subopts =
+						(char **)opts[OPT_R].subopts;
 				char	*value;
 
 				switch (getsubopt(&p, subopts, &value)) {
 				case R_EXTSIZE:
-					rtextbytes = getnum(value, &ropts, R_EXTSIZE);
+					rtextbytes = getnum(value,
+						&opts[OPT_R], R_EXTSIZE);
 					break;
 				case R_FILE:
-					xi.risfile = getnum(value, &ropts,
-							    R_FILE);
+					xi.risfile = getnum(value,
+						&opts[OPT_R], R_FILE);
 					break;
 				case R_NAME:
 				case R_DEV:
-					xi.rtname = getstr(value, &ropts,
+					xi.rtname = getstr(value, &opts[OPT_R],
 							   R_NAME);
 					break;
 				case R_SIZE:
-					rtbytes = getnum(value, &ropts, R_SIZE);
+					rtbytes = getnum(value, &opts[OPT_R],
+								R_SIZE);
 					break;
 				case R_NOALIGN:
-					norsflag = getnum(value, &ropts,
+					norsflag = getnum(value, &opts[OPT_R],
 								R_NOALIGN);
 					break;
 				default:
@@ -1978,7 +2024,8 @@ main(
 		case 's':
 			p = optarg;
 			while (*p != '\0') {
-				char	**subopts = (char **)sopts.subopts;
+				char	**subopts =
+						(char **)opts[OPT_S].subopts;
 				char	*value;
 
 				switch (getsubopt(&p, subopts, &value)) {
@@ -1986,8 +2033,9 @@ main(
 				case S_SECTLOG:
 					if (lssflag)
 						conflict('s', subopts,
-							 S_SECTSIZE, S_SECTLOG);
-					sectorlog = getnum(value, &sopts,
+							 S_SECTSIZE,
+							 S_SECTLOG);
+					sectorlog = getnum(value, &opts[OPT_S],
 							   S_SECTLOG);
 					lsectorlog = sectorlog;
 					sectorsize = 1 << sectorlog;
@@ -1997,10 +2045,11 @@ main(
 				case S_SIZE:
 				case S_SECTSIZE:
 					if (lslflag)
-						conflict('s', subopts, S_SECTLOG,
+						conflict('s', subopts,
+							 S_SECTLOG,
 							 S_SECTSIZE);
-					sectorsize = getnum(value, &sopts,
-							    S_SECTSIZE);
+					sectorsize = getnum(value,
+						&opts[OPT_S], S_SECTSIZE);
 					lsectorsize = sectorsize;
 					sectorlog =
 						libxfs_highbit32(sectorsize);
@@ -2023,7 +2072,8 @@ main(
 		fprintf(stderr, _("extra arguments\n"));
 		usage();
 	} else if (argc - optind == 1) {
-		dfile = xi.volname = getstr(argv[optind], &dopts, D_NAME);
+		dfile = xi.volname = getstr(argv[optind],
+					&opts[OPT_D], D_NAME);
 	} else
 		dfile = xi.dname;
 
@@ -2202,7 +2252,8 @@ _("32 bit Project IDs always enabled on CRC enabled filesytems\n"));
 		 * then issue an error.
 		 * The same is also for sparse inodes.
 		 */
-		if (sb_feat.finobt && mopts.subopt_params[M_FINOBT].seen) {
+		if (sb_feat.finobt &&
+		    opts[OPT_M].subopt_params[M_FINOBT].seen) {
 			fprintf(stderr,
 _("finobt not supported without CRC support\n"));
 			usage();
@@ -2451,7 +2502,7 @@ _("rmapbt not supported with realtime devices\n"));
 		fprintf(stderr,
 			_("size %s specified for data subvolume is too large, "
 			"maximum is %lld blocks\n"),
-			get_conf_raw_safe(&dopts, D_SIZE),
+			get_conf_raw_safe(OPT_D, D_SIZE),
 			(long long)DTOBT(xi.dsize));
 		usage();
 	} else if (!dbytes && xi.dsize > 0)
@@ -2500,7 +2551,7 @@ reported by the device (%u).\n"),
 		fprintf(stderr,
 			_("size %s specified for rt subvolume is too large, "
 			"maximum is %lld blocks\n"),
-			get_conf_raw_safe(&ropts, R_SIZE),
+			get_conf_raw_safe(OPT_R, R_SIZE),
 			(long long)DTOBT(xi.rtsize));
 		usage();
 	} else if (!rtbytes && xi.rtsize > 0)
@@ -2716,7 +2767,7 @@ an AG size that is one stripe unit smaller, for example %llu.\n"),
 	if (logbytes && xi.logBBsize > 0 && logblocks > DTOBT(xi.logBBsize)) {
 		fprintf(stderr,
 _("size %s specified for log subvolume is too large, maximum is %lld blocks\n"),
-			get_conf_raw_safe(&lopts, L_SIZE),
+			get_conf_raw_safe(OPT_L, L_SIZE),
 			(long long)DTOBT(xi.logBBsize));
 		usage();
 	} else if (!logbytes && xi.logBBsize > 0) {
-- 
2.13.3


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

* [PATCH 5/6 v2] mkfs: move getnum within the file
  2017-08-15 15:08 ` [PATCH 1/6 v2] mkfs: Save raw user input field to the opts struct Jan Tulak
  2017-08-15 15:08   ` [PATCH 3/6 v2] mkfs: remove intermediate getstr followed by getnum Jan Tulak
  2017-08-15 15:08   ` [PATCH 4/6 v2] mkfs: merge tables for opts parsing into one table Jan Tulak
@ 2017-08-15 15:08   ` Jan Tulak
  2017-08-15 15:08   ` [PATCH 6/6 v2] mkfs: extend opt_params with a value field Jan Tulak
  2017-08-15 23:07   ` [PATCH 1/6 v2] mkfs: Save raw user input field to the opts struct Eric Sandeen
  4 siblings, 0 replies; 37+ messages in thread
From: Jan Tulak @ 2017-08-15 15:08 UTC (permalink / raw)
  To: linux-xfs; +Cc: Jan Tulak

Move getnum, check_opt and illegal_option within the file. We have to do
this to avoid dependency issues with the following patch. There is no
other change in this patch, just cut&paste of these functions.

Signed-off-by: Jan Tulak <jtulak@redhat.com>
---
Change: only rebased against changes in previous patches
---
 mkfs/xfs_mkfs.c | 236 ++++++++++++++++++++++++++++----------------------------
 1 file changed, 118 insertions(+), 118 deletions(-)

diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
index cfb3fffa..1aedc804 100644
--- a/mkfs/xfs_mkfs.c
+++ b/mkfs/xfs_mkfs.c
@@ -832,6 +832,124 @@ get_conf_raw_safe(const int opt, const int subopt)
 	return str;
 }
 
+static __attribute__((noreturn)) void
+illegal_option(
+	const char		*value,
+	struct opt_params	*opts,
+	int			index,
+	const char		*reason)
+{
+	fprintf(stderr,
+		_("Illegal value %s for -%c %s option. %s\n"),
+		value, opts->name, opts->subopts[index],
+		reason ? reason : "");
+	usage();
+}
+
+/*
+ * Check for conflicts and option respecification.
+ */
+static void
+check_opt(
+	struct opt_params	*opts,
+	int			index,
+	bool			str_seen)
+{
+	struct subopt_param	*sp = &opts->subopt_params[index];
+	int			i;
+
+	if (sp->index != index) {
+		fprintf(stderr,
+	("Developer screwed up option parsing (%d/%d)! Please report!\n"),
+			sp->index, index);
+		reqval(opts->name, (char **)opts->subopts, index);
+	}
+
+	/*
+	 * Check for respecification of the option. This is more complex than it
+	 * seems because some options are parsed twice - once as a string during
+	 * input parsing, then later the string is passed to getnum for
+	 * conversion into a number and bounds checking. Hence the two variables
+	 * used to track the different uses based on the @str parameter passed
+	 * to us.
+	 */
+	if (!str_seen) {
+		if (sp->seen)
+			respec(opts->name, (char **)opts->subopts, index);
+		sp->seen = true;
+	} else {
+		if (sp->str_seen)
+			respec(opts->name, (char **)opts->subopts, index);
+		sp->str_seen = true;
+	}
+
+	/* check for conflicts with the option */
+	for (i = 0; i < MAX_CONFLICTS; i++) {
+		int conflict_opt = sp->conflicts[i];
+
+		if (conflict_opt == LAST_CONFLICT)
+			break;
+		if (opts->subopt_params[conflict_opt].seen ||
+		    opts->subopt_params[conflict_opt].str_seen)
+			conflict(opts->name, (char **)opts->subopts,
+				 conflict_opt, index);
+	}
+}
+
+static long long
+getnum(
+	const char		*str,
+	struct opt_params	*opts,
+	int			index)
+{
+	struct subopt_param	*sp = &opts->subopt_params[index];
+	long long		c;
+
+	check_opt(opts, index, false);
+	set_conf_raw_safe(opts->index, index, str);
+	/* empty strings might just return a default value */
+	if (!str || *str == '\0') {
+		if (sp->flagval == SUBOPT_NEEDS_VAL)
+			reqval(opts->name, (char **)opts->subopts, index);
+		return sp->flagval;
+	}
+
+	if (sp->minval == 0 && sp->maxval == 0) {
+		fprintf(stderr,
+			_("Option -%c %s has undefined minval/maxval."
+			  "Can't verify value range. This is a bug.\n"),
+			opts->name, opts->subopts[index]);
+		exit(1);
+	}
+
+	/*
+	 * Some values are pure numbers, others can have suffixes that define
+	 * the units of the number. Those get passed to cvtnum(), otherwise we
+	 * convert it ourselves to guarantee there is no trailing garbage in the
+	 * number.
+	 */
+	if (sp->convert)
+		c = cvtnum(blocksize, sectorsize, str);
+	else {
+		char		*str_end;
+
+		c = strtoll(str, &str_end, 0);
+		if (c == 0 && str_end == str)
+			illegal_option(str, opts, index, NULL);
+		if (*str_end != '\0')
+			illegal_option(str, opts, index, NULL);
+	}
+
+	/* Validity check the result. */
+	if (c < sp->minval)
+		illegal_option(str, opts, index, _("value is too small"));
+	else if (c > sp->maxval)
+		illegal_option(str, opts, index, _("value is too large"));
+	if (sp->is_power_2 && !ispow2(c))
+		illegal_option(str, opts, index, _("value must be a power of 2"));
+	return c;
+}
+
 /*
  * Convert lsu to lsunit for 512 bytes blocks and check validity of the values.
  */
@@ -1356,124 +1474,6 @@ sb_set_features(
 
 }
 
-static __attribute__((noreturn)) void
-illegal_option(
-	const char		*value,
-	struct opt_params	*opts,
-	int			index,
-	const char		*reason)
-{
-	fprintf(stderr,
-		_("Illegal value %s for -%c %s option. %s\n"),
-		value, opts->name, opts->subopts[index],
-		reason ? reason : "");
-	usage();
-}
-
-/*
- * Check for conflicts and option respecification.
- */
-static void
-check_opt(
-	struct opt_params	*opts,
-	int			index,
-	bool			str_seen)
-{
-	struct subopt_param	*sp = &opts->subopt_params[index];
-	int			i;
-
-	if (sp->index != index) {
-		fprintf(stderr,
-	("Developer screwed up option parsing (%d/%d)! Please report!\n"),
-			sp->index, index);
-		reqval(opts->name, (char **)opts->subopts, index);
-	}
-
-	/*
-	 * Check for respecification of the option. This is more complex than it
-	 * seems because some options are parsed twice - once as a string during
-	 * input parsing, then later the string is passed to getnum for
-	 * conversion into a number and bounds checking. Hence the two variables
-	 * used to track the different uses based on the @str parameter passed
-	 * to us.
-	 */
-	if (!str_seen) {
-		if (sp->seen)
-			respec(opts->name, (char **)opts->subopts, index);
-		sp->seen = true;
-	} else {
-		if (sp->str_seen)
-			respec(opts->name, (char **)opts->subopts, index);
-		sp->str_seen = true;
-	}
-
-	/* check for conflicts with the option */
-	for (i = 0; i < MAX_CONFLICTS; i++) {
-		int conflict_opt = sp->conflicts[i];
-
-		if (conflict_opt == LAST_CONFLICT)
-			break;
-		if (opts->subopt_params[conflict_opt].seen ||
-		    opts->subopt_params[conflict_opt].str_seen)
-			conflict(opts->name, (char **)opts->subopts,
-				 conflict_opt, index);
-	}
-}
-
-static long long
-getnum(
-	const char		*str,
-	struct opt_params	*opts,
-	int			index)
-{
-	struct subopt_param	*sp = &opts->subopt_params[index];
-	long long		c;
-
-	check_opt(opts, index, false);
-	set_conf_raw_safe(opts->index, index, str);
-	/* empty strings might just return a default value */
-	if (!str || *str == '\0') {
-		if (sp->flagval == SUBOPT_NEEDS_VAL)
-			reqval(opts->name, (char **)opts->subopts, index);
-		return sp->flagval;
-	}
-
-	if (sp->minval == 0 && sp->maxval == 0) {
-		fprintf(stderr,
-			_("Option -%c %s has undefined minval/maxval."
-			  "Can't verify value range. This is a bug.\n"),
-			opts->name, opts->subopts[index]);
-		exit(1);
-	}
-
-	/*
-	 * Some values are pure numbers, others can have suffixes that define
-	 * the units of the number. Those get passed to cvtnum(), otherwise we
-	 * convert it ourselves to guarantee there is no trailing garbage in the
-	 * number.
-	 */
-	if (sp->convert)
-		c = cvtnum(blocksize, sectorsize, str);
-	else {
-		char		*str_end;
-
-		c = strtoll(str, &str_end, 0);
-		if (c == 0 && str_end == str)
-			illegal_option(str, opts, index, NULL);
-		if (*str_end != '\0')
-			illegal_option(str, opts, index, NULL);
-	}
-
-	/* Validity check the result. */
-	if (c < sp->minval)
-		illegal_option(str, opts, index, _("value is too small"));
-	else if (c > sp->maxval)
-		illegal_option(str, opts, index, _("value is too large"));
-	if (sp->is_power_2 && !ispow2(c))
-		illegal_option(str, opts, index, _("value must be a power of 2"));
-	return c;
-}
-
 /*
  * Option is a string - do all the option table work, and check there
  * is actually an option string. Otherwise we don't do anything with the string
-- 
2.13.3


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

* [PATCH 6/6 v2] mkfs: extend opt_params with a value field
  2017-08-15 15:08 ` [PATCH 1/6 v2] mkfs: Save raw user input field to the opts struct Jan Tulak
                     ` (2 preceding siblings ...)
  2017-08-15 15:08   ` [PATCH 5/6 v2] mkfs: move getnum within the file Jan Tulak
@ 2017-08-15 15:08   ` Jan Tulak
  2017-08-16 21:13     ` Eric Sandeen
  2017-08-15 23:07   ` [PATCH 1/6 v2] mkfs: Save raw user input field to the opts struct Eric Sandeen
  4 siblings, 1 reply; 37+ messages in thread
From: Jan Tulak @ 2017-08-15 15:08 UTC (permalink / raw)
  To: linux-xfs; +Cc: Jan Tulak

This patch adds infrastructure that will be used in subsequent patches.

The Value field is the actual value used in computations for creating
the filesystem.  This is initialized with sensible default values. If
initialized to 0, the value is considered disabled. User input will
override default values.  If the field is a string and not a number, the
value is set to a positive non-zero number when user input has been
supplied.

Add functions that can be used to get/set values to opts table.

Signed-off-by: Jan Tulak <jtulak@redhat.com>

---
Change:
* whitespaces
* rename "collateral" -> "connected"
* reorder subopt_params to avoid padding issues
* translation and indentation for fprintf
---
 mkfs/xfs_mkfs.c | 176 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 176 insertions(+)

diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
index 1aedc804..17ee46a7 100644
--- a/mkfs/xfs_mkfs.c
+++ b/mkfs/xfs_mkfs.c
@@ -117,6 +117,13 @@ unsigned int		sectorsize;
  *     Filled raw string from the user, so we never lose that information e.g.
  *     to print it back in case of an issue.
  *
+ *   value OPTIONAL
+ *     The actual value used in computations for creating the filesystem.
+ *     This is initialized with sensible default values. If initialized to 0,
+ *     the value is considered disabled. User input will override default
+ *     values. If the field is a string and not a number, the value is set to
+ *     a positive non-zero number when user input has been supplied.
+ *
  */
 struct opt_params {
 	int		index;
@@ -133,6 +140,7 @@ struct opt_params {
 		long long	minval;
 		long long	maxval;
 		long long	flagval;
+		long long	value;
 		char		*raw_input;
 	}		subopt_params[MAX_SUBOPTS];
 } opts[MAX_OPTS] = {
@@ -750,6 +758,162 @@ struct opt_params {
 #define WHACK_SIZE (128 * 1024)
 
 /*
+ * Get and set values to the opts table.
+ */
+static int
+get_conf_val_unsafe(int opt, int subopt, uint64_t *output)
+{
+	if (subopt < 0 || subopt >= MAX_SUBOPTS ||
+	    opt < 0 || opt >= MAX_OPTS) {
+		fprintf(stderr,
+			_("This is a bug: get_conf_val called with invalid "
+			  "opt/subopt: %d/%d\n"),
+			opt, subopt);
+		return -EINVAL;
+	}
+	*output = opts[opt].subopt_params[subopt].value;
+	return 0;
+}
+
+static long long
+get_conf_val(int opt, int subopt)
+{
+	uint64_t res;
+	if (get_conf_val_unsafe(opt, subopt, &res) != 0)
+		exit(1);
+	return res;
+}
+
+static int
+set_conf_val_unsafe(int opt, int subopt, uint64_t val)
+{
+	if (subopt < 0 || subopt >= MAX_SUBOPTS ||
+	    opt < 0 || opt >= MAX_OPTS) {
+		fprintf(stderr,
+			_("This is a bug: set_conf_val called with invalid "
+			  "opt/subopt: %d/%d\n"),
+			opt, subopt);
+		return -EINVAL;
+	}
+	struct subopt_param *sp = &opts[opt].subopt_params[subopt];
+	sp->value = val;
+
+	return 0;
+}
+
+static void
+set_conf_val(int opt, int subopt, uint64_t val)
+{
+	if (set_conf_val_unsafe(opt, subopt, val) != 0)
+		exit(1);
+}
+
+/*
+ * A wrapper around set_conf_val which updates also connected values.
+ * E.g. when changing S_LOG, update S_SIZE too.
+ */
+static void
+set_conf_val_connected(int opt, int subopt, uint64_t val)
+{
+	set_conf_val(opt, subopt, val);
+
+	switch (opt) {
+	case OPT_B:
+		switch (subopt) {
+		case B_LOG:
+			set_conf_val(OPT_B, B_SIZE, 1 << val);
+			break;
+		case B_SIZE:
+			set_conf_val(OPT_B, B_LOG, libxfs_highbit32(val));
+			break;
+		}
+		break;
+	case OPT_D:
+		switch (subopt) {
+		case D_SECTLOG:
+			set_conf_val(OPT_S, S_LOG, val);
+			set_conf_val(OPT_S, S_SECTLOG, val);
+			set_conf_val(OPT_D, D_SECTSIZE, 1 << val);
+			set_conf_val(OPT_S, S_SECTSIZE, 1 << val);
+			set_conf_val(OPT_S, S_SIZE, 1 << val);
+			break;
+		case D_SECTSIZE:
+			set_conf_val(OPT_S, S_SIZE, val);
+			set_conf_val(OPT_S, S_SECTSIZE, val);
+			set_conf_val(OPT_D, D_SECTLOG, libxfs_highbit32(val));
+			set_conf_val(OPT_S, S_LOG, libxfs_highbit32(val));
+			set_conf_val(OPT_S, S_SECTLOG, libxfs_highbit32(val));
+			break;
+		}
+		break;
+	case OPT_I:
+		switch (subopt) {
+		case I_LOG:
+			set_conf_val(OPT_I, I_SIZE, 1 << val);
+			break;
+		case I_SIZE:
+			set_conf_val(OPT_I, I_LOG, libxfs_highbit32(val));
+			break;
+		}
+		break;
+	case OPT_L:
+		switch (subopt) {
+		case L_SECTLOG:
+			set_conf_val(OPT_L, L_SECTSIZE, 1 << val);
+			break;
+		case L_SECTSIZE:
+			set_conf_val(OPT_L, L_SECTLOG, libxfs_highbit32(val));
+			break;
+		}
+		break;
+	case OPT_M:
+		switch (subopt) {
+		}
+		break;
+	case OPT_N:
+		switch (subopt) {
+		case N_LOG:
+			set_conf_val(OPT_N, N_SIZE, 1 << val);
+			break;
+		case N_SIZE:
+			set_conf_val(OPT_N, N_LOG, libxfs_highbit32(val));
+			break;
+		}
+		break;
+	case OPT_R:
+		switch (subopt) {
+		}
+		break;
+	case OPT_S:
+		switch (subopt) {
+		case S_LOG:
+		case S_SECTLOG:
+			set_conf_val(OPT_S, S_LOG, val);
+			set_conf_val(OPT_D, D_SECTLOG, val);
+			set_conf_val(OPT_L, L_SECTLOG, val);
+			set_conf_val(OPT_D, D_SECTSIZE, 1 << val);
+			set_conf_val(OPT_S, S_SIZE, 1 << val);
+			set_conf_val(OPT_S, S_SECTSIZE, 1 << val);
+			set_conf_val(OPT_L, L_SECTLOG, val);
+			set_conf_val(OPT_L, L_SECTSIZE, 1 << val);
+			set_conf_val(OPT_L, L_SECTSIZE, val);
+			break;
+		case S_SIZE:
+		case S_SECTSIZE:
+			set_conf_val(OPT_S, S_SIZE, val);
+			set_conf_val(OPT_D, D_SECTSIZE, val);
+			set_conf_val(OPT_D, D_SECTLOG, libxfs_highbit32(val));
+			set_conf_val(OPT_S, S_LOG, libxfs_highbit32(val));
+			set_conf_val(OPT_S, S_SECTLOG, libxfs_highbit32(val));
+			set_conf_val(OPT_L, L_SECTSIZE, val);
+			set_conf_val(OPT_L, L_SECTLOG, libxfs_highbit32(val));
+			break;
+		}
+		break;
+	}
+}
+
+/*
  * Return 0 on success, -ENOMEM if it could not allocate enough memory for
  * the string to be saved.
  */
@@ -951,6 +1115,18 @@ getnum(
 }
 
 /*
+ * A wrapper for getnum and set_conf_val.
+ */
+static inline long long
+parse_conf_val(int opt, int subopt, char *value)
+{
+	long long num = getnum(value, &opts[opt], subopt);
+
+	set_conf_val_connected(opt, subopt, num);
+	return num;
+}
+
+/*
  * Convert lsu to lsunit for 512 bytes blocks and check validity of the values.
  */
 static void
-- 
2.13.3


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

* Re: [PATCH 5/6] mkfs: move getnum within the file
  2017-08-15 10:14     ` Jan Tulak
@ 2017-08-15 21:09       ` Eric Sandeen
  2017-08-16  9:25         ` Jan Tulak
  0 siblings, 1 reply; 37+ messages in thread
From: Eric Sandeen @ 2017-08-15 21:09 UTC (permalink / raw)
  To: Jan Tulak, Darrick J. Wong; +Cc: linux-xfs

On 8/15/17 5:14 AM, Jan Tulak wrote:
> On Tue, Aug 15, 2017 at 1:07 AM, Darrick J. Wong
> <darrick.wong@oracle.com> wrote:
>> On Fri, Aug 11, 2017 at 02:30:36PM +0200, Jan Tulak wrote:
>>> Move getnum, check_opt and illegal_option within the file. We have to do
>>> this to avoid dependency issues with the following patch. There is no
>>> other change in this patch, just cut&paste of these functions.
>>>
>>> Signed-off-by: Jan Tulak <jtulak@redhat.com>
>>> ---
>>>  mkfs/xfs_mkfs.c | 236 ++++++++++++++++++++++++++++----------------------------
>>>  1 file changed, 118 insertions(+), 118 deletions(-)
>>>
>>> diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
>>> index e3f7d345..3e7ba5f0 100644
>>> --- a/mkfs/xfs_mkfs.c
>>> +++ b/mkfs/xfs_mkfs.c
>>> @@ -813,6 +813,124 @@ get_conf_raw_safe(const int opt, const int subopt)
>>>       return str;
>>>  }
>>>
>>> +static __attribute__((noreturn)) void
>>> +illegal_option(
>>
>> How about declaring the functions at the top and leaving the definitions
>> where they are?
> 
> If I remember, Eric thought the opposite. :-)

I don't remember, but at this point I'm ok with whatever, this part
just isn't that important.

Thanks,
-Eric

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

* Re: [PATCH 1/6 v2] mkfs: Save raw user input field to the opts struct
  2017-08-15 15:08 ` [PATCH 1/6 v2] mkfs: Save raw user input field to the opts struct Jan Tulak
                     ` (3 preceding siblings ...)
  2017-08-15 15:08   ` [PATCH 6/6 v2] mkfs: extend opt_params with a value field Jan Tulak
@ 2017-08-15 23:07   ` Eric Sandeen
  2017-08-16  9:11     ` Jan Tulak
  4 siblings, 1 reply; 37+ messages in thread
From: Eric Sandeen @ 2017-08-15 23:07 UTC (permalink / raw)
  To: Jan Tulak, linux-xfs

On 8/15/17 10:08 AM, Jan Tulak wrote:
> Save exactly what the user gave us for every option.  This way, we will
> never lose the information if we need it to print back an issue.
> (Just add the infrastructure now, used in the next patches.)
> 
> Signed-off-by: Jan Tulak <jtulak@redhat.com>

Sorry for not getting to the V1 review, catching up from a week off.

> ---
> CHANGE:
> * test for NULL before strdup in get_conf_raw
> * Translation and indentation for fprints
> * add set_conf_raw_safe
> ---
>  mkfs/xfs_mkfs.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 88 insertions(+)
> 
> diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
> index 7bb6408f..adfbd376 100644
> --- a/mkfs/xfs_mkfs.c
> +++ b/mkfs/xfs_mkfs.c
> @@ -107,6 +107,11 @@ unsigned int		sectorsize;
>   *     sets what is used with simple specifying the subopt (-d file).
>   *     A special SUBOPT_NEEDS_VAL can be used to require a user-given
>   *     value in any case.
> + *
> + *   raw_input INTERNAL
> + *     Filled raw string from the user, so we never lose that information e.g.
> + *     to print it back in case of an issue.
> + *
>   */
>  struct opt_params {
>  	const char	name;
> @@ -122,6 +127,7 @@ struct opt_params {
>  		long long	minval;
>  		long long	maxval;
>  		long long	defaultval;
> +		char		*raw_input;
>  	}		subopt_params[MAX_SUBOPTS];
>  };
>  
> @@ -730,6 +736,88 @@ struct opt_params mopts = {
>  #define WHACK_SIZE (128 * 1024)
>  
>  /*
> + * Return 0 on success, -ENOMEM if it could not allocate enough memory for
> + * the string to be saved.
> + */
> +static int
> +set_conf_raw(struct opt_params *opt, const int subopt, const char *value)
> +{
> +	if (subopt < 0 || subopt >= MAX_SUBOPTS) {
> +		fprintf(stderr,
> +			_("This is a bug: set_conf_raw called with invalid "
> +			  "opt/subopt: %c/%d\n"),

Usually best to just out-dent these long strings to column zero:

_("This is a bug: set_conf_raw called with invalid opt/subopt: %c/%d\n"),

and that makes them super grep-able.  Other places in xfsprogs do that.

> +			opt->name, subopt);
> +		return -EINVAL;
> +	}
> +	if (value == NULL) {
> +		if (opt->subopt_params[subopt].raw_input != NULL)
> +			free(opt->subopt_params[subopt].raw_input);
> +		opt->subopt_params[subopt].raw_input = NULL;
> +	} else {
> +		opt->subopt_params[subopt].raw_input = strdup(value);
> +		if (opt->subopt_params[subopt].raw_input == NULL)
> +			return -ENOMEM;
> +	}
> +	return 0;
> +}
> +
> +/*
> + * Same as set_conf_raw(), except if any error occurs, return NULL.
> + */

Hm, that's not what this void function does.

> +static void
> +set_conf_raw_safe(struct opt_params *opt, const int subopt, const char *value)
> +{
> +	if (set_conf_raw(opt, subopt, value) != 0) {
> +		exit(1);
> +	}

So on -ENOMEM error, we get a silent exit()?

Also, not sure about the point of the wrapper.  Nothing in this series
calls set_conf_raw() directly - do later patches use it?  If not,
just lose the wrapper, I'd say, and roll up the behavior in set_conf_raw.

> +}
> +
> +/*
> + * Return 0 on success, -ENOMEM if it could not allocate enough memory for
> + * the string to be saved into the out pointer.

..., or -EINVAL if ___?  I guess this is the downside of excessive commenting ;)

> + */
> +static int
> +get_conf_raw(const struct opt_params *opt, const int subopt, char **out)
> +{
> +	if (subopt < 0 || subopt >= MAX_SUBOPTS) {
> +		fprintf(stderr,
> +			_("This is a bug: get_conf_raw called with invalid "
> +			  "opt/subopt: %c/%d\n"),

Again I'd outdent this error string.

> +			opt->name, subopt);
> +		return -EINVAL;
> +	}
> +
> +	if (opt->subopt_params[subopt].raw_input == NULL) {
> +		*out = NULL;
> +		return 0;
> +	}
> +
> +	*out = strdup(opt->subopt_params[subopt].raw_input);
> +	if (*out == NULL)
> +		return -ENOMEM;
> +	return 0;
> +
> +}
> +
> +/*
> + * Same as get_conf_raw(), except it returns the string through return.
> + * If any error occurs, return NULL.
> + */
> +static char *
> +get_conf_raw_safe(const struct opt_params *opt, const int subopt)
> +{
> +	char *str;
> +
> +	str = NULL;
> +
> +	if (get_conf_raw(opt, subopt, &str) == -ENOMEM) {
> +		fprintf(stderr, "Out of memory!");

Seems like using strerror() would be better than a hand-rolled, un-
translatable string?

> +		return NULL;
> +	}

Again, I don't see that any subsequent patches ever call get_conf_raw();
is there any reason to even have this wrapper now?

> +	return str;
> +}
> +
> +/*
>   * Convert lsu to lsunit for 512 bytes blocks and check validity of the values.
>   */
>  static void
> 

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

* Re: [PATCH 3/6 v2] mkfs: remove intermediate getstr followed by getnum
  2017-08-15 15:08   ` [PATCH 3/6 v2] mkfs: remove intermediate getstr followed by getnum Jan Tulak
@ 2017-08-15 23:20     ` Eric Sandeen
  2017-08-17 11:36     ` Dave Chinner
  1 sibling, 0 replies; 37+ messages in thread
From: Eric Sandeen @ 2017-08-15 23:20 UTC (permalink / raw)
  To: Jan Tulak, linux-xfs

On 8/15/17 10:08 AM, Jan Tulak wrote:
> Some options loaded a number as a string with getstr and converted it to
> number with getnum later in the code, without any reason for this
> approach.  (They were probably forgotten in some past cleaning.)
> 
> This patch changes them to skip the string and use getnum directly in
> the main option-parsing loop, as do all the other numerical options.
> And as we now have two variables of the same type for the same value,
> merge them together. (e.g. former string dsize and number dbytes).
> 
> Signed-off-by: Jan Tulak <jtulak@redhat.com>
> 
> ---
> UPDATE:
> * in getnum: set_conf_raw -> set_conf_raw_safe

Looks fine, though if you take my advice on patch1, it'll
be set_conf_raw_safe -> set_conf_raw again ;)

-Eric


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

* Re: [PATCH 1/6 v2] mkfs: Save raw user input field to the opts struct
  2017-08-15 23:07   ` [PATCH 1/6 v2] mkfs: Save raw user input field to the opts struct Eric Sandeen
@ 2017-08-16  9:11     ` Jan Tulak
  2017-08-16 14:42       ` Eric Sandeen
  0 siblings, 1 reply; 37+ messages in thread
From: Jan Tulak @ 2017-08-16  9:11 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: linux-xfs

On Wed, Aug 16, 2017 at 1:07 AM, Eric Sandeen <sandeen@sandeen.net> wrote:
> On 8/15/17 10:08 AM, Jan Tulak wrote:
>> Save exactly what the user gave us for every option.  This way, we will
>> never lose the information if we need it to print back an issue.
>> (Just add the infrastructure now, used in the next patches.)
>>
>> Signed-off-by: Jan Tulak <jtulak@redhat.com>
>
> Sorry for not getting to the V1 review, catching up from a week off.

I hope you enjoyed your holiday. :-)

>
>> ---
>> CHANGE:
>> * test for NULL before strdup in get_conf_raw
>> * Translation and indentation for fprints
>> * add set_conf_raw_safe
>> ---
>>  mkfs/xfs_mkfs.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>  1 file changed, 88 insertions(+)
>>
>> diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
>> index 7bb6408f..adfbd376 100644
>> --- a/mkfs/xfs_mkfs.c
>> +++ b/mkfs/xfs_mkfs.c
>> @@ -107,6 +107,11 @@ unsigned int             sectorsize;
>>   *     sets what is used with simple specifying the subopt (-d file).
>>   *     A special SUBOPT_NEEDS_VAL can be used to require a user-given
>>   *     value in any case.
>> + *
>> + *   raw_input INTERNAL
>> + *     Filled raw string from the user, so we never lose that information e.g.
>> + *     to print it back in case of an issue.
>> + *
>>   */
>>  struct opt_params {
>>       const char      name;
>> @@ -122,6 +127,7 @@ struct opt_params {
>>               long long       minval;
>>               long long       maxval;
>>               long long       defaultval;
>> +             char            *raw_input;
>>       }               subopt_params[MAX_SUBOPTS];
>>  };
>>
>> @@ -730,6 +736,88 @@ struct opt_params mopts = {
>>  #define WHACK_SIZE (128 * 1024)
>>
>>  /*
>> + * Return 0 on success, -ENOMEM if it could not allocate enough memory for
>> + * the string to be saved.
>> + */
>> +static int
>> +set_conf_raw(struct opt_params *opt, const int subopt, const char *value)
>> +{
>> +     if (subopt < 0 || subopt >= MAX_SUBOPTS) {
>> +             fprintf(stderr,
>> +                     _("This is a bug: set_conf_raw called with invalid "
>> +                       "opt/subopt: %c/%d\n"),
>
> Usually best to just out-dent these long strings to column zero:
>
> _("This is a bug: set_conf_raw called with invalid opt/subopt: %c/%d\n"),
>
> and that makes them super grep-able.  Other places in xfsprogs do that.

True, I will change it.

>
>> +                     opt->name, subopt);
>> +             return -EINVAL;
>> +     }
>> +     if (value == NULL) {
>> +             if (opt->subopt_params[subopt].raw_input != NULL)
>> +                     free(opt->subopt_params[subopt].raw_input);
>> +             opt->subopt_params[subopt].raw_input = NULL;
>> +     } else {
>> +             opt->subopt_params[subopt].raw_input = strdup(value);
>> +             if (opt->subopt_params[subopt].raw_input == NULL)
>> +                     return -ENOMEM;
>> +     }
>> +     return 0;
>> +}
>> +
>> +/*
>> + * Same as set_conf_raw(), except if any error occurs, return NULL.
>> + */
>
> Hm, that's not what this void function does.

copypasta of comment :(

>
>> +static void
>> +set_conf_raw_safe(struct opt_params *opt, const int subopt, const char *value)
>> +{
>> +     if (set_conf_raw(opt, subopt, value) != 0) {
>> +             exit(1);
>> +     }
>
> So on -ENOMEM error, we get a silent exit()?
>
> Also, not sure about the point of the wrapper.  Nothing in this series
> calls set_conf_raw() directly - do later patches use it?  If not,
> just lose the wrapper, I'd say, and roll up the behavior in set_conf_raw.
>
>> +}
>> +
>> +/*
>> + * Return 0 on success, -ENOMEM if it could not allocate enough memory for
>> + * the string to be saved into the out pointer.
>
> ..., or -EINVAL if ___?  I guess this is the downside of excessive commenting ;)
>
>> + */
>> +static int
>> +get_conf_raw(const struct opt_params *opt, const int subopt, char **out)
>> +{
>> +     if (subopt < 0 || subopt >= MAX_SUBOPTS) {
>> +             fprintf(stderr,
>> +                     _("This is a bug: get_conf_raw called with invalid "
>> +                       "opt/subopt: %c/%d\n"),
>
> Again I'd outdent this error string.
>
>> +                     opt->name, subopt);
>> +             return -EINVAL;
>> +     }
>> +
>> +     if (opt->subopt_params[subopt].raw_input == NULL) {
>> +             *out = NULL;
>> +             return 0;
>> +     }
>> +
>> +     *out = strdup(opt->subopt_params[subopt].raw_input);
>> +     if (*out == NULL)
>> +             return -ENOMEM;
>> +     return 0;
>> +
>> +}
>> +
>> +/*
>> + * Same as get_conf_raw(), except it returns the string through return.
>> + * If any error occurs, return NULL.
>> + */
>> +static char *
>> +get_conf_raw_safe(const struct opt_params *opt, const int subopt)
>> +{
>> +     char *str;
>> +
>> +     str = NULL;
>> +
>> +     if (get_conf_raw(opt, subopt, &str) == -ENOMEM) {
>> +             fprintf(stderr, "Out of memory!");
>
> Seems like using strerror() would be better than a hand-rolled, un-
> translatable string?

Every day there is something new. :-)

>
>> +             return NULL;
>> +     }
>
> Again, I don't see that any subsequent patches ever call get_conf_raw();
> is there any reason to even have this wrapper now?

Luis had a pretty strong opinion about having them there when he will
need them in his own patches later on and I saw no reason why not to
add them right now when the functions are created. After all, they
will be useful later on also for me, when I want to limit the amount
of asserts and be more return-oriented. It's just not in this
patchset.

Jan

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

* Re: [PATCH 5/6] mkfs: move getnum within the file
  2017-08-15 21:09       ` Eric Sandeen
@ 2017-08-16  9:25         ` Jan Tulak
  0 siblings, 0 replies; 37+ messages in thread
From: Jan Tulak @ 2017-08-16  9:25 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: Darrick J. Wong, linux-xfs

On Tue, Aug 15, 2017 at 11:09 PM, Eric Sandeen <sandeen@sandeen.net> wrote:
> On 8/15/17 5:14 AM, Jan Tulak wrote:
>> On Tue, Aug 15, 2017 at 1:07 AM, Darrick J. Wong
>> <darrick.wong@oracle.com> wrote:
>>> On Fri, Aug 11, 2017 at 02:30:36PM +0200, Jan Tulak wrote:
>>>> Move getnum, check_opt and illegal_option within the file. We have to do
>>>> this to avoid dependency issues with the following patch. There is no
>>>> other change in this patch, just cut&paste of these functions.
>>>>
>>>> Signed-off-by: Jan Tulak <jtulak@redhat.com>
>>>> ---
>>>>  mkfs/xfs_mkfs.c | 236 ++++++++++++++++++++++++++++----------------------------
>>>>  1 file changed, 118 insertions(+), 118 deletions(-)
>>>>
>>>> diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
>>>> index e3f7d345..3e7ba5f0 100644
>>>> --- a/mkfs/xfs_mkfs.c
>>>> +++ b/mkfs/xfs_mkfs.c
>>>> @@ -813,6 +813,124 @@ get_conf_raw_safe(const int opt, const int subopt)
>>>>       return str;
>>>>  }
>>>>
>>>> +static __attribute__((noreturn)) void
>>>> +illegal_option(
>>>
>>> How about declaring the functions at the top and leaving the definitions
>>> where they are?
>>
>> If I remember, Eric thought the opposite. :-)
>
> I don't remember, but at this point I'm ok with whatever, this part
> just isn't that important.
>

Just for the record, from the previous run:

On Thu, Jul 27, 2017 at 1:27 AM, Eric Sandeen <sandeen@sandeen.net> wrote:
> On 7/20/17 4:29 AM, Jan Tulak wrote:
>> Move getnum, check_opt and illegal_option within the file. We have to do
>> this to avoid dependency issues with the following patch. There is no
>> other change in this patch, just cut&paste of these functions.
>
> Yeah, nice to have these up at the top of the file anyway.
>
> Reviewed-by: Eric Sandeen <sandeen@redhat.com>

:-)

Jan

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

* Re: [PATCH 1/6 v2] mkfs: Save raw user input field to the opts struct
  2017-08-16  9:11     ` Jan Tulak
@ 2017-08-16 14:42       ` Eric Sandeen
  2017-08-16 15:38         ` Jan Tulak
  0 siblings, 1 reply; 37+ messages in thread
From: Eric Sandeen @ 2017-08-16 14:42 UTC (permalink / raw)
  To: Jan Tulak; +Cc: linux-xfs

On 8/16/17 4:11 AM, Jan Tulak wrote:
> On Wed, Aug 16, 2017 at 1:07 AM, Eric Sandeen <sandeen@sandeen.net> wrote:
>> On 8/15/17 10:08 AM, Jan Tulak wrote:
>>> Save exactly what the user gave us for every option.  This way, we will
>>> never lose the information if we need it to print back an issue.
>>> (Just add the infrastructure now, used in the next patches.)
>>>
>>> Signed-off-by: Jan Tulak <jtulak@redhat.com>
>>
>> Sorry for not getting to the V1 review, catching up from a week off.
> 
> I hope you enjoyed your holiday. :-)

...


>>> +static char *
>>> +get_conf_raw_safe(const struct opt_params *opt, const int subopt)
>>> +{
>>> +     char *str;
>>> +
>>> +     str = NULL;
>>> +
>>> +     if (get_conf_raw(opt, subopt, &str) == -ENOMEM) {
>>> +             fprintf(stderr, "Out of memory!");
>>
>> Seems like using strerror() would be better than a hand-rolled, un-
>> translatable string?
> 
> Every day there is something new. :-)

Yeah, sorry.  But in general, strings need to be translatable; (that was
pointed out before) and strerror() would do that for your for free.

>>
>>> +             return NULL;
>>> +     }
>>
>> Again, I don't see that any subsequent patches ever call get_conf_raw();
>> is there any reason to even have this wrapper now?
> 
> Luis had a pretty strong opinion about having them there when he will
> need them in his own patches later on and I saw no reason why not to
> add them right now when the functions are created. After all, they
> will be useful later on also for me, when I want to limit the amount
> of asserts and be more return-oriented. It's just not in this
> patchset.

Hm, ok.  Let me reread that, thread - I'm just looking at this patchset
as sent.

In general, I'm not clear on what your "_safe" and "_unsafe" variants
are about but maybe it was discussed in the prior thread I skipped.

Thanks,
-Eric

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

* Re: [PATCH 1/6 v2] mkfs: Save raw user input field to the opts struct
  2017-08-16 14:42       ` Eric Sandeen
@ 2017-08-16 15:38         ` Jan Tulak
  0 siblings, 0 replies; 37+ messages in thread
From: Jan Tulak @ 2017-08-16 15:38 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: linux-xfs

On Wed, Aug 16, 2017 at 4:42 PM, Eric Sandeen <sandeen@sandeen.net> wrote:
> On 8/16/17 4:11 AM, Jan Tulak wrote:
>> On Wed, Aug 16, 2017 at 1:07 AM, Eric Sandeen <sandeen@sandeen.net> wrote:
>>> On 8/15/17 10:08 AM, Jan Tulak wrote:
>>>> Save exactly what the user gave us for every option.  This way, we will
>>>> never lose the information if we need it to print back an issue.
>>>> (Just add the infrastructure now, used in the next patches.)
>>>>
>>>> Signed-off-by: Jan Tulak <jtulak@redhat.com>
>>>
>>>
>>>> +             return NULL;
>>>> +     }
>>>
>>> Again, I don't see that any subsequent patches ever call get_conf_raw();
>>> is there any reason to even have this wrapper now?
>>
>> Luis had a pretty strong opinion about having them there when he will
>> need them in his own patches later on and I saw no reason why not to
>> add them right now when the functions are created. After all, they
>> will be useful later on also for me, when I want to limit the amount
>> of asserts and be more return-oriented. It's just not in this
>> patchset.
>
> Hm, ok.  Let me reread that, thread - I'm just looking at this patchset
> as sent.
>
> In general, I'm not clear on what your "_safe" and "_unsafe" variants
> are about but maybe it was discussed in the prior thread I skipped.

>

It is about being able to decide what should happen when an error
occurs and how good practice it is to just call exit() instead of
propagating the error upwards in the stack. Right now, we can abort
without a big issue (at least technically), but, for example, with a
config file parsing, we will want to print the line of the config file
which is invalid.

These two threads should give you the details:

https://www.spinics.net/lists/linux-xfs/msg08635.html
https://www.spinics.net/lists/linux-xfs/msg08636.html

In any case, I will wait with sending further versions of these
patches until you had the time to look at it.

Cheers,
Jan

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

* Re: [PATCH 6/6 v2] mkfs: extend opt_params with a value field
  2017-08-15 15:08   ` [PATCH 6/6 v2] mkfs: extend opt_params with a value field Jan Tulak
@ 2017-08-16 21:13     ` Eric Sandeen
  2017-08-16 21:38       ` Darrick J. Wong
  0 siblings, 1 reply; 37+ messages in thread
From: Eric Sandeen @ 2017-08-16 21:13 UTC (permalink / raw)
  To: Jan Tulak, linux-xfs

On 8/15/17 10:08 AM, Jan Tulak wrote:
> This patch adds infrastructure that will be used in subsequent patches.
> 
> The Value field is the actual value used in computations for creating
> the filesystem.  This is initialized with sensible default values. If
> initialized to 0, the value is considered disabled. User input will
> override default values.  If the field is a string and not a number, the
> value is set to a positive non-zero number when user input has been
> supplied.
> 
> Add functions that can be used to get/set values to opts table.

Ok, I need to back up here a bit and look at this conceptually.

(Again, though, if this is infra for some other patchset, I'd just send
it with /that/ patchset, not this one ...)

But anyway, things like this confuse and worry me:

> +	case OPT_S:
> +		switch (subopt) {
> +		case S_LOG:
> +		case S_SECTLOG:
> +			set_conf_val(OPT_S, S_LOG, val);
> +			set_conf_val(OPT_D, D_SECTLOG, val);
> +			set_conf_val(OPT_L, L_SECTLOG, val);
> +			set_conf_val(OPT_D, D_SECTSIZE, 1 << val);
> +			set_conf_val(OPT_S, S_SIZE, 1 << val);
> +			set_conf_val(OPT_S, S_SECTSIZE, 1 << val);
> +			set_conf_val(OPT_L, L_SECTLOG, val);
> +			set_conf_val(OPT_L, L_SECTSIZE, 1 << val);
> +			set_conf_val(OPT_L, L_SECTSIZE, val);> +			break;
> +		case S_SIZE:
> +		case S_SECTSIZE:
> +			set_conf_val(OPT_S, S_SIZE, val);
> +			set_conf_val(OPT_D, D_SECTSIZE, val);
> +			set_conf_val(OPT_D, D_SECTLOG, libxfs_highbit32(val));
> +			set_conf_val(OPT_S, S_LOG, libxfs_highbit32(val));
> +			set_conf_val(OPT_S, S_SECTLOG, libxfs_highbit32(val));
> +			set_conf_val(OPT_L, L_SECTSIZE, val);
> +			set_conf_val(OPT_L, L_SECTLOG, libxfs_highbit32(val));
> +			break;
> +		}
> +		break;
> +	}

Partly because this seems to be going opposite of the simplicity
we were aiming for - before all this work, if we set teh data sector size,
via any of these options, it got stored in a variable - "sectorsize".

Now, if we issue "-s size=4k" the code will calculate and set that same
value (or its log) into 7 to (or 9?) different internal variables?
Why is that needed?  There is/are only one (or two) sector size(s) in the
filesystem, so should there not be one point of truth here?

But also because the above is wrong; it is possible for the filesystem data
portion and log portion to have different sector sizes, if the log is external. [1]
The above would seem to break that, always setting data & log sizes together.

On top of that, it's getting so complicated that it seems to be difficult to get
right; i.e. this:

> +			set_conf_val(OPT_L, L_SECTSIZE, 1 << val);
> +			set_conf_val(OPT_L, L_SECTSIZE, val);

surely isn't correct.  I found that when noticing that 1 block sets 9 vals, while
the other only 7, and wondered why.  So that accounts for one.  After another minute
of scrutiny I see that OPT_S, S_SECTSIZE isn't set in the 2nd chunk, so that's a bug
as well.

This makes me fear fragility in this approach.

One goal of all this work, I thought, was to clearly describe interdependencies between
options, but the above seems to add nasty, hidden, implicit, and wrong dependencies
between log & data sector sizes (for example).

If we have several commandline options that all set the same fundamental property,
(i.e. data sector size), then it seems that should somehow be stored in one single
point of truth within mkfs as it was before.

-Eric

[1] # mkfs.xfs -dfile,name=fsfile,size=1g,sectsize=4k -lfile,name=logfile,size=512m,sectsize=512

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

* Re: [PATCH 6/6 v2] mkfs: extend opt_params with a value field
  2017-08-16 21:13     ` Eric Sandeen
@ 2017-08-16 21:38       ` Darrick J. Wong
  2017-08-17 10:08         ` Jan Tulak
  0 siblings, 1 reply; 37+ messages in thread
From: Darrick J. Wong @ 2017-08-16 21:38 UTC (permalink / raw)
  To: Eric Sandeen; +Cc: Jan Tulak, linux-xfs

On Wed, Aug 16, 2017 at 04:13:52PM -0500, Eric Sandeen wrote:
> On 8/15/17 10:08 AM, Jan Tulak wrote:
> > This patch adds infrastructure that will be used in subsequent patches.
> > 
> > The Value field is the actual value used in computations for creating
> > the filesystem.  This is initialized with sensible default values. If
> > initialized to 0, the value is considered disabled. User input will
> > override default values.  If the field is a string and not a number, the
> > value is set to a positive non-zero number when user input has been
> > supplied.
> > 
> > Add functions that can be used to get/set values to opts table.
> 
> Ok, I need to back up here a bit and look at this conceptually.
> 
> (Again, though, if this is infra for some other patchset, I'd just send
> it with /that/ patchset, not this one ...)
> 
> But anyway, things like this confuse and worry me:
> 
> > +	case OPT_S:
> > +		switch (subopt) {
> > +		case S_LOG:
> > +		case S_SECTLOG:
> > +			set_conf_val(OPT_S, S_LOG, val);
> > +			set_conf_val(OPT_D, D_SECTLOG, val);
> > +			set_conf_val(OPT_L, L_SECTLOG, val);
> > +			set_conf_val(OPT_D, D_SECTSIZE, 1 << val);
> > +			set_conf_val(OPT_S, S_SIZE, 1 << val);
> > +			set_conf_val(OPT_S, S_SECTSIZE, 1 << val);
> > +			set_conf_val(OPT_L, L_SECTLOG, val);
> > +			set_conf_val(OPT_L, L_SECTSIZE, 1 << val);
> > +			set_conf_val(OPT_L, L_SECTSIZE, val);> +			break;
> > +		case S_SIZE:
> > +		case S_SECTSIZE:
> > +			set_conf_val(OPT_S, S_SIZE, val);
> > +			set_conf_val(OPT_D, D_SECTSIZE, val);
> > +			set_conf_val(OPT_D, D_SECTLOG, libxfs_highbit32(val));
> > +			set_conf_val(OPT_S, S_LOG, libxfs_highbit32(val));
> > +			set_conf_val(OPT_S, S_SECTLOG, libxfs_highbit32(val));
> > +			set_conf_val(OPT_L, L_SECTSIZE, val);
> > +			set_conf_val(OPT_L, L_SECTLOG, libxfs_highbit32(val));
> > +			break;
> > +		}
> > +		break;
> > +	}
> 
> Partly because this seems to be going opposite of the simplicity
> we were aiming for - before all this work, if we set teh data sector size,
> via any of these options, it got stored in a variable - "sectorsize".
> 
> Now, if we issue "-s size=4k" the code will calculate and set that same
> value (or its log) into 7 to (or 9?) different internal variables?
> Why is that needed?  There is/are only one (or two) sector size(s) in the
> filesystem, so should there not be one point of truth here?
> 
> But also because the above is wrong; it is possible for the filesystem data
> portion and log portion to have different sector sizes, if the log is external. [1]
> The above would seem to break that, always setting data & log sizes together.
> 
> On top of that, it's getting so complicated that it seems to be difficult to get
> right; i.e. this:
> 
> > +			set_conf_val(OPT_L, L_SECTSIZE, 1 << val);
> > +			set_conf_val(OPT_L, L_SECTSIZE, val);
> 
> surely isn't correct.  I found that when noticing that 1 block sets 9 vals, while
> the other only 7, and wondered why.  So that accounts for one.  After another minute
> of scrutiny I see that OPT_S, S_SECTSIZE isn't set in the 2nd chunk, so that's a bug
> as well.
> 
> This makes me fear fragility in this approach.
> 
> One goal of all this work, I thought, was to clearly describe interdependencies between
> options, but the above seems to add nasty, hidden, implicit, and wrong dependencies
> between log & data sector sizes (for example).

FWIW I thought all this really did was replace the dozens of local
variables holding geometry info with a huge nested struct, which is a
reasonable start on adding support for a config file (where is that,
anyway?) but didn't make any functional changes.

Ofc I didn't realize that xfs/191-input-validation isn't a totally
thorough exerciser of all the mkfs options.

> If we have several commandline options that all set the same fundamental property,
> (i.e. data sector size), then it seems that should somehow be stored in one single
> point of truth within mkfs as it was before.
> 
> -Eric
> 
> [1] # mkfs.xfs -dfile,name=fsfile,size=1g,sectsize=4k -lfile,name=logfile,size=512m,sectsize=512

I see -d sectsize is in the --help screen but not the manpage.  Can we
fix that?

--D

> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 6/6 v2] mkfs: extend opt_params with a value field
  2017-08-16 21:38       ` Darrick J. Wong
@ 2017-08-17 10:08         ` Jan Tulak
  2017-08-17 11:03           ` Dave Chinner
  2017-08-17 15:26           ` Eric Sandeen
  0 siblings, 2 replies; 37+ messages in thread
From: Jan Tulak @ 2017-08-17 10:08 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: Eric Sandeen, linux-xfs

On Wed, Aug 16, 2017 at 11:38 PM, Darrick J. Wong
<darrick.wong@oracle.com> wrote:
> On Wed, Aug 16, 2017 at 04:13:52PM -0500, Eric Sandeen wrote:
>> On 8/15/17 10:08 AM, Jan Tulak wrote:
>> > This patch adds infrastructure that will be used in subsequent patches.
>> >
>> > The Value field is the actual value used in computations for creating
>> > the filesystem.  This is initialized with sensible default values. If
>> > initialized to 0, the value is considered disabled. User input will
>> > override default values.  If the field is a string and not a number, the
>> > value is set to a positive non-zero number when user input has been
>> > supplied.
>> >
>> > Add functions that can be used to get/set values to opts table.
>>
>> Ok, I need to back up here a bit and look at this conceptually.
>>
>> (Again, though, if this is infra for some other patchset, I'd just send
>> it with /that/ patchset, not this one ...)

Ehh... yes, of course. I moved the patch for which this is
infrastructure to the other set but did not move this one.

>>
>> But anyway, things like this confuse and worry me:
>>
>> > +   case OPT_S:
>> > +           switch (subopt) {
>> > +           case S_LOG:
>> > +           case S_SECTLOG:
>> > +                   set_conf_val(OPT_S, S_LOG, val);
>> > +                   set_conf_val(OPT_D, D_SECTLOG, val);
>> > +                   set_conf_val(OPT_L, L_SECTLOG, val);
>> > +                   set_conf_val(OPT_D, D_SECTSIZE, 1 << val);
>> > +                   set_conf_val(OPT_S, S_SIZE, 1 << val);
>> > +                   set_conf_val(OPT_S, S_SECTSIZE, 1 << val);
>> > +                   set_conf_val(OPT_L, L_SECTLOG, val);
>> > +                   set_conf_val(OPT_L, L_SECTSIZE, 1 << val);
>> > +                   set_conf_val(OPT_L, L_SECTSIZE, val);> +                        break;
>> > +           case S_SIZE:
>> > +           case S_SECTSIZE:
>> > +                   set_conf_val(OPT_S, S_SIZE, val);
>> > +                   set_conf_val(OPT_D, D_SECTSIZE, val);
>> > +                   set_conf_val(OPT_D, D_SECTLOG, libxfs_highbit32(val));
>> > +                   set_conf_val(OPT_S, S_LOG, libxfs_highbit32(val));
>> > +                   set_conf_val(OPT_S, S_SECTLOG, libxfs_highbit32(val));
>> > +                   set_conf_val(OPT_L, L_SECTSIZE, val);
>> > +                   set_conf_val(OPT_L, L_SECTLOG, libxfs_highbit32(val));
>> > +                   break;
>> > +           }
>> > +           break;
>> > +   }
>>
>> Partly because this seems to be going opposite of the simplicity
>> we were aiming for - before all this work, if we set teh data sector size,
>> via any of these options, it got stored in a variable - "sectorsize".
>>
>> Now, if we issue "-s size=4k" the code will calculate and set that same
>> value (or its log) into 7 to (or 9?) different internal variables?
>> Why is that needed?  There is/are only one (or two) sector size(s) in the
>> filesystem, so should there not be one point of truth here?
>>
>> But also because the above is wrong; it is possible for the filesystem data
>> portion and log portion to have different sector sizes, if the log is external. [1]
>> The above would seem to break that, always setting data & log sizes together.

But in the current for-next tree mkfs does set data and log sector
size at the same time,
this patch is not doing anything new:

                                case S_SECTSIZE:
                                        if (lslflag)
                                                conflict('s', subopts,
S_SECTLOG,
                                                         S_SECTSIZE);
                                        sectorsize = getnum(value, &sopts,
                                                            S_SECTSIZE);
                                        lsectorsize = sectorsize;
                                        sectorlog =
                                                libxfs_highbit32(sectorsize);
                                        lsectorlog = sectorlog;
                                        lssflag = ssflag = 1;
                                        break;

The only difference here is that sectorsize was one variable into
which multiple options assigned a value, while now we fill every
related member of the structure with the same value. Which is is
cumbersome, I admit that. I had an idea which could limit this
duplicated assignments, but it has its own disadvantages: if the
values of -d sectlog and sectize and -s size and log options were all
pointers to the same variable, it would be enough to set only one. But
then we are unknowingly modifying the other options whenever we touch
any of those, which is not nice as well. But I will give it another
though, maybe I will came up with an idea...

Anyway, back to the data/log sector size - when I was making this
change, my understanding of the code was that -s size will set both
data and log sector size, and -d/-l sectsize will set only one of
them. If this behaviour is not the desired one, then it needs to be
fixed anyway, no matter if my patch is there or not. But it is perhaps
obscured by the fact that here I'm setting both S_SIZE and D_SECTSIZE,
which adds a noise.

>>
>> On top of that, it's getting so complicated that it seems to be difficult to get
>> right; i.e. this:
>>
>> > +                   set_conf_val(OPT_L, L_SECTSIZE, 1 << val);
>> > +                   set_conf_val(OPT_L, L_SECTSIZE, val);
>>
>> surely isn't correct.  I found that when noticing that 1 block sets 9 vals, while
>> the other only 7, and wondered why.  So that accounts for one.  After another minute
>> of scrutiny I see that OPT_S, S_SECTSIZE isn't set in the 2nd chunk, so that's a bug
>> as well.

Yup, these are bugs.

>>
>> This makes me fear fragility in this approach.
>>
>> One goal of all this work, I thought, was to clearly describe interdependencies between
>> options, but the above seems to add nasty, hidden, implicit, and wrong dependencies
>> between log & data sector sizes (for example).

The fragility is the reason why I moved it out of the main() loop
where these correlated options were set until now into this specific
function, so at least we know what to watch for. But the dependency
between log & data sector sizes was there before. The issue is that
S_SIZE and D_SECTSIZE have the same meaning, but are not automatically
connected.

>
> FWIW I thought all this really did was replace the dozens of local
> variables holding geometry info with a huge nested struct, which is a
> reasonable start on adding support for a config file (where is that,
> anyway?) but didn't make any functional changes.

That is the goal, yes. Any functional changes in this are a bug.

>
> Ofc I didn't realize that xfs/191-input-validation isn't a totally
> thorough exerciser of all the mkfs options.

Missing combinations can be added, but it only tests whether mkfs
accepts or refuses the combination.
I have another test in the making, which really makes the filesystem
and then tests if its geometry and properties are all right,
but I have difficulties with evaluating correct sizes when the test
device can be of any size and have different sector size, so I can't
diff a correct output from xfs_info. The only usable way I found so
far is to limit it to fs images only, where I have some control over
the size.

>
>> If we have several commandline options that all set the same fundamental property,
>> (i.e. data sector size), then it seems that should somehow be stored in one single
>> point of truth within mkfs as it was before.
>>
>> -Eric
>>
>> [1] # mkfs.xfs -dfile,name=fsfile,size=1g,sectsize=4k -lfile,name=logfile,size=512m,sectsize=512
>
> I see -d sectsize is in the --help screen but not the manpage.  Can we
> fix that?

I made it, but Dave would rather see the -d sectsize option removed.
Which I'm not sure about...
See "[PATCH] xfsprogs: add sectsize/sectlog to the man page"

Cheers,
Jan

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

* Re: [PATCH 6/6 v2] mkfs: extend opt_params with a value field
  2017-08-17 10:08         ` Jan Tulak
@ 2017-08-17 11:03           ` Dave Chinner
  2017-08-17 14:56             ` Jan Tulak
  2017-08-17 15:26           ` Eric Sandeen
  1 sibling, 1 reply; 37+ messages in thread
From: Dave Chinner @ 2017-08-17 11:03 UTC (permalink / raw)
  To: Jan Tulak; +Cc: Darrick J. Wong, Eric Sandeen, linux-xfs

Hi folks,

I'm going to put my 2c worth in here in the form of a patch.  The
tl;dr of it all is that I think we need to reset and reflect on what
I was originally trying to acheive with the table based option
parsing: factoring and simplifying mkfs into an easy to understand,
maintainable code base....

And, while I remember, there's a handful of input validation bugs I
found in the code whiel I was doing this (like missing conflict
checks).

Anyway, have a look, based on the current for-next branch.

> >> [1] # mkfs.xfs -dfile,name=fsfile,size=1g,sectsize=4k -lfile,name=logfile,size=512m,sectsize=512
> >
> > I see -d sectsize is in the --help screen but not the manpage.  Can we
> > fix that?
> 
> I made it, but Dave would rather see the -d sectsize option removed.
> Which I'm not sure about...
> See "[PATCH] xfsprogs: add sectsize/sectlog to the man page"

Slash and burn - there is so much useless, redundant crap in the CLI
we've been holding onto for 15 years that we should just get rid of
it. That's what I was intending to do originally with this rework
and I still see no reason why we should be keeping stuff that just
causes user confusion and implemention complexity.

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

mkfs.xfs: factor the crap out of input parsing

From: Dave Chinner <dchinner@redhat.com>

Up front: this compiles, but I haven't even smoke tested it.
It's a patch for discussion and reflection, not for testing....

After spending most of today talking to Eric about this mkfs
factoring that doesn't seem to be going in the right direction,
I figured I'd spend the afternoon and pick up where I left the
original patchset I wrote all those years ago.

The primary goal I had for that work was to make mkfs.xfs
maintainable and lay a solid foundation for being able to modify it
in future. The goal wasn't to store all the config information the
options table - the goal was to provide a structure that we could
refactor the code around. We seem to have lost sight of this.

So, what this patch does is make a start on factoring the crap out
of the input parsing and parameter validation. It's based on the
current for-next tree, so I've ignored all the other patches that
are out there, even though there are some with changes in them that
are useful and good.

Instead, I hacked together a quick global "cli geometry" structure
that holds the handful of values that can be set from the CLI, and
pushed all the other feature flag things into the existing sb_feat
global structure.

I then factored the sub options parsing loop using a table setup
with to call a suboption specific parser function that does the
table based option parsing. This gets *all* the suboption parsing
out of the main option parsing loop which is soooo much simpler:


                case 'b':
                case 'd':
                case 'i':
                case 'l':
                case 'm':
                case 'n':
                case 'r':
                case 's':
                        parse_subopts(c, optarg);
                        break;

Having done that, I started on the mess that followed the option
parsing loop and started separating that out into functions that
validate and set a clear set of parameters that the mkfs code then
later uses. Hence we end up with code like this in the main
function.

        /*
         * Extract as much of the valid config as we can from the CLI input
         * before opening the libxfs devices.
         */
        validate_blocksize(&blocksize, &blocklog);
        validate_sectorsize(&sectorsize, &sectorlog, &ft, dfile, Nflag,
                            force_overwrite);
        validate_log_sectorsize(&lsectorsize, &lsectorlog,
                                sectorsize, sectorlog);
        validate_sb_features();

        validate_dirblocksize(&dirblocksize, &dirblocklog, blocklog);
        validate_inodesize(&isize, &inodelog, &inopblock, blocklog);

It's far, far easier to see what mkfs is doing now, and what appears
to be random futzing with flags and input parameters has turned into
code that has clear and obvious meaning.

This is what the table based input option parsing was supposed to
lead to. Instead of a forest of similar but not at all the same
flags and varaibles, we get clear, obvious code that can then be
easily understood. Then we can abstract out all the calculated and
validated config variables into a single structure that we then use
to build the on-disk filesystem structure. And once the building of
the fs structure uses abstracted config structures, we can look at
adding new input and output methods that manipulate those config
structures rather than the CLI option parsing table.....

Luis, some of this factoring isn't that much different in concept
from your original patch set for config file support. The difference
is in the way it is acheived - by abstracting it into individual
option parameter type parser functions. Jan - the combining of all
the option parameter structures is similar in concept to your merged
tables, but it does it via a separate table designed specifically
the generic sub-option parsing code. So some of the concepts should
be recognisable, the difference is in the simplicity of
implementation.

Now, I need to be clear here: do not think that the hacky "cli
geometry" structure is a permanent fixture or will even last through
tomorrow. It's just a means to an end to make the initial factoring
simple and fast. That's the mistake that's been made with the option
parsing - we've ended up focussing on the option parsing table
rather than where the option table parsing was supposed to take us.

Keep in mind that I said to Eric 4 hours ago "I might send a patch"
less than 5 hours ago because it's the best way to get people to
understand why I think we need to reset and where we need to go
first before even thinking about other ways of getting config
information into and out of mkfs.

So, yeah, there's still a lot of work in this to finish it off to
the point where I can think about how to split it for review (maybe
another full day of uninterrrupted hacking on my part), but I'm done
for the day now and I think everyone needs to have a look and a
think about it before I get back to it in the morning...

Signed-Off-By: Dave Chinner <dchinner@redhat.com>
---
 mkfs/xfs_mkfs.c | 1690 ++++++++++++++++++++++++++++++-------------------------
 1 file changed, 916 insertions(+), 774 deletions(-)

diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
index 7bb6408f9b77..aeb081add83e 100644
--- a/mkfs/xfs_mkfs.c
+++ b/mkfs/xfs_mkfs.c
@@ -24,11 +24,11 @@
 /*
  * Prototypes for internal functions.
  */
-static void conflict(char opt, char *tab[], int oldidx, int newidx);
+static void conflict(char opt, const char *tab[], int oldidx, int newidx);
 static void illegal(const char *value, const char *opt);
 static __attribute__((noreturn)) void usage (void);
-static __attribute__((noreturn)) void reqval(char opt, char *tab[], int idx);
-static void respec(char opt, char *tab[], int idx);
+static __attribute__((noreturn)) void reqval(char opt, const char *tab[], int idx);
+static void respec(char opt, const char *tab[], int idx);
 static void unknown(char opt, char *s);
 static int  ispow2(unsigned int i);
 
@@ -428,6 +428,8 @@ struct opt_params lopts = {
 		{ .index = L_INTERNAL,
 		  .conflicts = { L_FILE,
 				 L_DEV,
+				 L_SECTLOG,
+				 L_SECTSIZE,
 				 LAST_CONFLICT },
 		  .minval = 0,
 		  .maxval = 1,
@@ -469,6 +471,7 @@ struct opt_params lopts = {
 		},
 		{ .index = L_SECTLOG,
 		  .conflicts = { L_SECTSIZE,
+				 L_INTERNAL,
 				 LAST_CONFLICT },
 		  .minval = XFS_MIN_SECTORSIZE_LOG,
 		  .maxval = XFS_MAX_SECTORSIZE_LOG,
@@ -476,6 +479,7 @@ struct opt_params lopts = {
 		},
 		{ .index = L_SECTSIZE,
 		  .conflicts = { L_SECTLOG,
+				 L_INTERNAL,
 				 LAST_CONFLICT },
 		  .convert = true,
 		  .is_power_2 = true,
@@ -729,74 +733,6 @@ struct opt_params mopts = {
  */
 #define WHACK_SIZE (128 * 1024)
 
-/*
- * Convert lsu to lsunit for 512 bytes blocks and check validity of the values.
- */
-static void
-calc_stripe_factors(
-	int		dsu,
-	int		dsw,
-	int		dsectsz,
-	int		lsu,
-	int		lsectsz,
-	int		*dsunit,
-	int		*dswidth,
-	int		*lsunit)
-{
-	/* Handle data sunit/swidth options */
-	if ((*dsunit && !*dswidth) || (!*dsunit && *dswidth)) {
-		fprintf(stderr,
-			_("both data sunit and data swidth options "
-			"must be specified\n"));
-		usage();
-	}
-
-	if (dsu || dsw) {
-		if ((dsu && !dsw) || (!dsu && dsw)) {
-			fprintf(stderr,
-				_("both data su and data sw options "
-				"must be specified\n"));
-			usage();
-		}
-
-		if (dsu % dsectsz) {
-			fprintf(stderr,
-				_("data su must be a multiple of the "
-				"sector size (%d)\n"), dsectsz);
-			usage();
-		}
-
-		*dsunit  = (int)BTOBBT(dsu);
-		*dswidth = *dsunit * dsw;
-	}
-
-	if (*dsunit && (*dswidth % *dsunit != 0)) {
-		fprintf(stderr,
-			_("data stripe width (%d) must be a multiple of the "
-			"data stripe unit (%d)\n"), *dswidth, *dsunit);
-		usage();
-	}
-
-	/* Handle log sunit options */
-
-	if (lsu)
-		*lsunit = (int)BTOBBT(lsu);
-
-	/* verify if lsu/lsunit is a multiple block size */
-	if (lsu % blocksize != 0) {
-		fprintf(stderr,
-_("log stripe unit (%d) must be a multiple of the block size (%d)\n"),
-		lsu, blocksize);
-		exit(1);
-	}
-	if ((BBTOB(*lsunit) % blocksize != 0)) {
-		fprintf(stderr,
-_("log stripe unit (%d) must be a multiple of the block size (%d)\n"),
-		BBTOB(*lsunit), blocksize);
-		exit(1);
-	}
-}
-
 static void
 check_device_type(
 	const char	*name,
@@ -1161,6 +1097,31 @@ struct sb_feat_args {
 	bool	parent_pointers;
 	bool	rmapbt;
 	bool	reflink;
+	bool	nodalign;
+	bool	nortalign;
+	uuid_t	m_uuid;
+};
+
+/*
+ * Default values for superblock features
+ */
+struct sb_feat_args	sb_feat = {
+	.finobt = 1,
+	.spinodes = 0,
+	.log_version = 2,
+	.attr_version = 2,
+	.dir_version = XFS_DFL_DIR_VERSION,
+	.inode_align = XFS_IFLAG_ALIGN,
+	.nci = false,
+	.lazy_sb_counters = true,
+	.projid16bit = false,
+	.crcs_enabled = true,
+	.dirftype = true,
+	.parent_pointers = false,
+	.rmapbt = false,
+	.reflink = false,
+	.nodalign = false,
+	.nortalign = false,
 };
 
 static void
@@ -1283,7 +1244,7 @@ check_opt(
 		fprintf(stderr,
 	("Developer screwed up option parsing (%d/%d)! Please report!\n"),
 			sp->index, index);
-		reqval(opts->name, (char **)opts->subopts, index);
+		reqval(opts->name, opts->subopts, index);
 	}
 
 	/*
@@ -1296,11 +1257,11 @@ check_opt(
 	 */
 	if (!str_seen) {
 		if (sp->seen)
-			respec(opts->name, (char **)opts->subopts, index);
+			respec(opts->name, opts->subopts, index);
 		sp->seen = true;
 	} else {
 		if (sp->str_seen)
-			respec(opts->name, (char **)opts->subopts, index);
+			respec(opts->name, opts->subopts, index);
 		sp->str_seen = true;
 	}
 
@@ -1312,7 +1273,7 @@ check_opt(
 			break;
 		if (opts->subopt_params[conflict_opt].seen ||
 		    opts->subopt_params[conflict_opt].str_seen)
-			conflict(opts->name, (char **)opts->subopts,
+			conflict(opts->name, opts->subopts,
 				 conflict_opt, index);
 	}
 }
@@ -1330,7 +1291,7 @@ getnum(
 	/* empty strings might just return a default value */
 	if (!str || *str == '\0') {
 		if (sp->defaultval == SUBOPT_NEEDS_VAL)
-			reqval(opts->name, (char **)opts->subopts, index);
+			reqval(opts->name, opts->subopts, index);
 		return sp->defaultval;
 	}
 
@@ -1386,615 +1347,472 @@ getstr(
 
 	/* empty strings for string options are not valid */
 	if (!str || *str == '\0')
-		reqval(opts->name, (char **)opts->subopts, index);
+		reqval(opts->name, opts->subopts, index);
 	return str;
 }
 
-int
-main(
-	int			argc,
-	char			**argv)
+/* geometry specified on input. 0 is not specified */
+struct cli_geometry {
+	int	sectorsize;
+	int	blocksize;
+	char	*dsize;
+	int64_t	agsize;
+	int	agcount;
+	int	dsunit;
+	int	dswidth;
+	int	dsu;
+	int	dsw;
+	int	inodesize;
+	int	inopblock;
+	int	imaxpct;
+	int	dirblocksize;
+	int	logagno;
+	char	*logsize;
+	int	lsectorsize;
+	int	loginternal;
+	int	lsu;
+	int	lsunit;
+	char	*rtextsize;
+	char	*rtsize;
+
+} cligeo;
+
+/* root inode characteristics */
+struct fsxattr		fsx;
+
+/* libxfs file/device setup info */
+libxfs_init_t		xi;
+
+static int
+block_opts_parser(
+	struct opt_params	*opts,
+	int			subopt,
+	char			*value)
 {
-	uint64_t		agcount;
-	xfs_agf_t		*agf;
-	xfs_agi_t		*agi;
-	xfs_agnumber_t		agno;
-	uint64_t		agsize;
-	xfs_alloc_rec_t		*arec;
-	struct xfs_btree_block	*block;
-	int			blflag;
 	int			blocklog;
-	int			bsflag;
-	int			bsize;
-	xfs_buf_t		*buf;
-	int			c;
-	int			daflag;
-	int			dasize;
-	xfs_rfsblock_t		dblocks;
-	char			*dfile;
-	int			dirblocklog;
-	int			dirblocksize;
-	char			*dsize;
-	int			dsu;
-	int			dsw;
-	int			dsunit;
-	int			dswidth;
-	int			dsflag;
-	int			force_overwrite;
-	struct fsxattr		fsx;
-	int			ilflag;
-	int			imaxpct;
-	int			imflag;
+
+	switch (subopt) {
+	case B_LOG:
+		blocklog = getnum(value, &bopts, B_LOG);
+		cligeo.blocksize = 1 << blocklog;
+		break;
+	case B_SIZE:
+		cligeo.blocksize = getnum(value, &bopts, B_SIZE);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int
+data_opts_parser(
+	struct opt_params	*opts,
+	int			subopt,
+	char			*value)
+{
+	int			sectorlog;
+
+	switch (subopt) {
+	case D_AGCOUNT:
+		cligeo.agcount = getnum(value, opts, D_AGCOUNT);
+		break;
+	case D_AGSIZE:
+		cligeo.agsize = getnum(value, opts, D_AGSIZE);
+		break;
+	case D_FILE:
+		xi.disfile = getnum(value, opts, D_FILE);
+		break;
+	case D_NAME:
+		xi.dname = getstr(value, opts, D_NAME);
+		break;
+	case D_SIZE:
+		cligeo.dsize = getstr(value, opts, D_SIZE);
+		break;
+	case D_SUNIT:
+		cligeo.dsunit = getnum(value, opts, D_SUNIT);
+		break;
+	case D_SWIDTH:
+		cligeo.dswidth = getnum(value, opts, D_SWIDTH);
+		break;
+	case D_SU:
+		cligeo.dsu = getnum(value, opts, D_SU);
+		break;
+	case D_SW:
+		cligeo.dsw = getnum(value, opts, D_SW);
+		break;
+	case D_NOALIGN:
+		sb_feat.nodalign = getnum(value, opts, D_NOALIGN);
+		break;
+	case D_SECTLOG:
+		if (cligeo.sectorsize)
+			conflict('d', opts->subopts, D_SECTSIZE, D_SECTLOG);
+		sectorlog = getnum(value, opts, D_SECTLOG);
+		cligeo.sectorsize = 1 << sectorlog;
+		break;
+	case D_SECTSIZE:
+		cligeo.sectorsize = getnum(value, opts, D_SECTSIZE);
+		break;
+	case D_RTINHERIT:
+		if (getnum(value, opts, D_RTINHERIT))
+			fsx.fsx_xflags |= XFS_DIFLAG_RTINHERIT;
+		break;
+	case D_PROJINHERIT:
+		fsx.fsx_projid = getnum(value, opts, D_PROJINHERIT);
+		fsx.fsx_xflags |= XFS_DIFLAG_PROJINHERIT;
+		break;
+	case D_EXTSZINHERIT:
+		fsx.fsx_extsize = getnum(value, opts, D_EXTSZINHERIT);
+		fsx.fsx_xflags |= XFS_DIFLAG_EXTSZINHERIT;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int
+inode_opts_parser(
+	struct opt_params	*opts,
+	int			subopt,
+	char			*value)
+{
 	int			inodelog;
-	int			inopblock;
-	int			ipflag;
-	int			isflag;
-	int			isize;
-	char			*label = NULL;
-	int			laflag;
-	int			lalign;
-	int			ldflag;
-	int			liflag;
-	xfs_agnumber_t		logagno;
-	xfs_rfsblock_t		logblocks;
-	char			*logfile;
-	int			loginternal;
-	char			*logsize;
-	xfs_fsblock_t		logstart;
-	int			lvflag;
-	int			lsflag;
-	int			lsuflag;
-	int			lsunitflag;
+
+	switch (subopt) {
+	case I_ALIGN:
+		sb_feat.inode_align = getnum(value, &iopts, I_ALIGN);
+		break;
+	case I_LOG:
+		inodelog = getnum(value, &iopts, I_LOG);
+		cligeo.inodesize = 1 << inodelog;
+		break;
+	case I_MAXPCT:
+		cligeo.imaxpct = getnum(value, &iopts, I_MAXPCT);
+		break;
+	case I_PERBLOCK:
+		cligeo.inopblock = getnum(value, &iopts, I_PERBLOCK);
+		break;
+	case I_SIZE:
+		cligeo.inodesize = getnum(value, &iopts, I_SIZE);
+		break;
+	case I_ATTR:
+		sb_feat.attr_version = getnum(value, &iopts, I_ATTR);
+		break;
+	case I_PROJID32BIT:
+		sb_feat.projid16bit = !getnum(value, &iopts, I_PROJID32BIT);
+		break;
+	case I_SPINODES:
+		sb_feat.spinodes = getnum(value, &iopts, I_SPINODES);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int
+log_opts_parser(
+	struct opt_params	*opts,
+	int			subopt,
+	char			*value)
+{
 	int			lsectorlog;
-	int			lsectorsize;
-	int			lslflag;
-	int			lssflag;
-	int			lsu;
-	int			lsunit;
-	int			min_logblocks;
-	xfs_mount_t		*mp;
-	xfs_mount_t		mbuf;
-	xfs_extlen_t		nbmblocks;
-	int			nlflag;
-	int			nodsflag;
-	int			norsflag;
-	xfs_alloc_rec_t		*nrec;
-	int			nsflag;
-	int			nvflag;
-	int			Nflag;
-	int			discard = 1;
-	char			*p;
-	char			*protofile;
-	char			*protostring;
-	int			qflag;
-	xfs_rfsblock_t		rtblocks;
-	xfs_extlen_t		rtextblocks;
-	xfs_rtblock_t		rtextents;
-	char			*rtextsize;
-	char			*rtfile;
-	char			*rtsize;
-	xfs_sb_t		*sbp;
-	int			sectorlog;
-	uint64_t		sector_mask;
-	int			slflag;
-	int			ssflag;
-	uint64_t		tmp_agsize;
-	uuid_t			uuid;
-	int			worst_freelist;
-	libxfs_init_t		xi;
-	struct fs_topology	ft;
-	struct sb_feat_args	sb_feat = {
-		.finobt = 1,
-		.spinodes = 0,
-		.log_version = 2,
-		.attr_version = 2,
-		.dir_version = XFS_DFL_DIR_VERSION,
-		.inode_align = XFS_IFLAG_ALIGN,
-		.nci = false,
-		.lazy_sb_counters = true,
-		.projid16bit = false,
-		.crcs_enabled = true,
-		.dirftype = true,
-		.parent_pointers = false,
-		.rmapbt = false,
-		.reflink = false,
-	};
 
-	platform_uuid_generate(&uuid);
-	progname = basename(argv[0]);
-	setlocale(LC_ALL, "");
-	bindtextdomain(PACKAGE, LOCALEDIR);
-	textdomain(PACKAGE);
+	switch (subopt) {
+	case L_AGNUM:
+		cligeo.logagno = getnum(value, &lopts, L_AGNUM);
+		break;
+	case L_FILE:
+		xi.lisfile = getnum(value, &lopts, L_FILE);
+		break;
+	case L_INTERNAL:
+		cligeo.loginternal = getnum(value, &lopts, L_INTERNAL);
+		break;
+	case L_SU:
+		cligeo.lsu = getnum(value, &lopts, L_SU);
+		break;
+	case L_SUNIT:
+		cligeo.lsunit = getnum(value, &lopts, L_SUNIT);
+		break;
+	case L_NAME:
+	case L_DEV:
+		xi.logname = getstr(value, &lopts, L_NAME);
+		cligeo.loginternal = 0;
+		break;
+	case L_VERSION:
+		sb_feat.log_version = getnum(value, &lopts, L_VERSION);
+		break;
+	case L_SIZE:
+		cligeo.logsize = getstr(value, &lopts, L_SIZE);
+		break;
+	case L_SECTLOG:
+		lsectorlog = getnum(value, &lopts, L_SECTLOG);
+		cligeo.lsectorsize = 1 << lsectorlog;
+		break;
+	case L_SECTSIZE:
+		cligeo.lsectorsize = getnum(value, &lopts, L_SECTSIZE);
+		break;
+	case L_LAZYSBCNTR:
+		sb_feat.lazy_sb_counters = getnum(value, &lopts, L_LAZYSBCNTR);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
 
-	blflag = bsflag = slflag = ssflag = lslflag = lssflag = 0;
-	blocklog = blocksize = 0;
-	sectorlog = lsectorlog = 0;
-	sectorsize = lsectorsize = 0;
-	agsize = daflag = dasize = dblocks = 0;
-	ilflag = imflag = ipflag = isflag = 0;
-	liflag = laflag = lsflag = lsuflag = lsunitflag = ldflag = lvflag = 0;
-	loginternal = 1;
-	logagno = logblocks = rtblocks = rtextblocks = 0;
-	Nflag = nlflag = nsflag = nvflag = 0;
-	dirblocklog = dirblocksize = 0;
-	qflag = 0;
-	imaxpct = inodelog = inopblock = isize = 0;
-	dfile = logfile = rtfile = NULL;
-	dsize = logsize = rtsize = rtextsize = protofile = NULL;
-	dsu = dsw = dsunit = dswidth = lalign = lsu = lsunit = 0;
-	dsflag = nodsflag = norsflag = 0;
-	force_overwrite = 0;
-	worst_freelist = 0;
-	memset(&fsx, 0, sizeof(fsx));
+static int
+meta_opts_parser(
+	struct opt_params	*opts,
+	int			subopt,
+	char			*value)
+{
+	switch (subopt) {
+	case M_CRC:
+		sb_feat.crcs_enabled = getnum(value, &mopts, M_CRC);
+		if (sb_feat.crcs_enabled)
+			sb_feat.dirftype = true;
+		break;
+	case M_FINOBT:
+		sb_feat.finobt = getnum(value, &mopts, M_FINOBT);
+		break;
+	case M_UUID:
+		if (!value || *value == '\0')
+			reqval('m', opts->subopts, M_UUID);
+		if (platform_uuid_parse(value, &sb_feat.m_uuid))
+			illegal(value, "m uuid");
+		break;
+	case M_RMAPBT:
+		sb_feat.rmapbt = getnum(value, &mopts, M_RMAPBT);
+		break;
+	case M_REFLINK:
+		sb_feat.reflink = getnum(value, &mopts, M_REFLINK);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
 
-	memset(&xi, 0, sizeof(xi));
-	xi.isdirect = LIBXFS_DIRECT;
-	xi.isreadonly = LIBXFS_EXCLUSIVELY;
+static int
+naming_opts_parser(
+	struct opt_params	*opts,
+	int			subopt,
+	char			*value)
+{
+	int			dirblocklog;
 
-	while ((c = getopt(argc, argv, "b:d:i:l:L:m:n:KNp:qr:s:CfV")) != EOF) {
-		switch (c) {
-		case 'C':
-		case 'f':
-			force_overwrite = 1;
-			break;
-		case 'b':
-			p = optarg;
-			while (*p != '\0') {
-				char	**subopts = (char **)bopts.subopts;
-				char	*value;
-
-				switch (getsubopt(&p, subopts, &value)) {
-				case B_LOG:
-					blocklog = getnum(value, &bopts, B_LOG);
-					blocksize = 1 << blocklog;
-					blflag = 1;
-					break;
-				case B_SIZE:
-					blocksize = getnum(value, &bopts,
-							   B_SIZE);
-					blocklog = libxfs_highbit32(blocksize);
-					bsflag = 1;
-					break;
-				default:
-					unknown('b', value);
-				}
-			}
-			break;
-		case 'd':
-			p = optarg;
-			while (*p != '\0') {
-				char	**subopts = (char **)dopts.subopts;
-				char	*value;
-
-				switch (getsubopt(&p, subopts, &value)) {
-				case D_AGCOUNT:
-					agcount = getnum(value, &dopts,
-							 D_AGCOUNT);
-					daflag = 1;
-					break;
-				case D_AGSIZE:
-					agsize = getnum(value, &dopts, D_AGSIZE);
-					dasize = 1;
-					break;
-				case D_FILE:
-					xi.disfile = getnum(value, &dopts,
-							    D_FILE);
-					break;
-				case D_NAME:
-					xi.dname = getstr(value, &dopts, D_NAME);
-					break;
-				case D_SIZE:
-					dsize = getstr(value, &dopts, D_SIZE);
-					break;
-				case D_SUNIT:
-					dsunit = getnum(value, &dopts, D_SUNIT);
-					dsflag = 1;
-					break;
-				case D_SWIDTH:
-					dswidth = getnum(value, &dopts,
-							 D_SWIDTH);
-					dsflag = 1;
-					break;
-				case D_SU:
-					dsu = getnum(value, &dopts, D_SU);
-					dsflag = 1;
-					break;
-				case D_SW:
-					dsw = getnum(value, &dopts, D_SW);
-					dsflag = 1;
-					break;
-				case D_NOALIGN:
-					nodsflag = getnum(value, &dopts,
-								D_NOALIGN);
-					break;
-				case D_SECTLOG:
-					sectorlog = getnum(value, &dopts,
-							   D_SECTLOG);
-					sectorsize = 1 << sectorlog;
-					slflag = 1;
-					break;
-				case D_SECTSIZE:
-					sectorsize = getnum(value, &dopts,
-							    D_SECTSIZE);
-					sectorlog =
-						libxfs_highbit32(sectorsize);
-					ssflag = 1;
-					break;
-				case D_RTINHERIT:
-					c = getnum(value, &dopts, D_RTINHERIT);
-					if (c)
-						fsx.fsx_xflags |=
-							XFS_DIFLAG_RTINHERIT;
-					break;
-				case D_PROJINHERIT:
-					fsx.fsx_projid = getnum(value, &dopts,
-								D_PROJINHERIT);
-					fsx.fsx_xflags |=
-						XFS_DIFLAG_PROJINHERIT;
-					break;
-				case D_EXTSZINHERIT:
-					fsx.fsx_extsize = getnum(value, &dopts,
-								 D_EXTSZINHERIT);
-					fsx.fsx_xflags |=
-						XFS_DIFLAG_EXTSZINHERIT;
-					break;
-				default:
-					unknown('d', value);
-				}
-			}
-			break;
-		case 'i':
-			p = optarg;
-			while (*p != '\0') {
-				char	**subopts = (char **)iopts.subopts;
-				char	*value;
-
-				switch (getsubopt(&p, subopts, &value)) {
-				case I_ALIGN:
-					sb_feat.inode_align = getnum(value,
-								&iopts, I_ALIGN);
-					break;
-				case I_LOG:
-					inodelog = getnum(value, &iopts, I_LOG);
-					isize = 1 << inodelog;
-					ilflag = 1;
-					break;
-				case I_MAXPCT:
-					imaxpct = getnum(value, &iopts,
-							 I_MAXPCT);
-					imflag = 1;
-					break;
-				case I_PERBLOCK:
-					inopblock = getnum(value, &iopts,
-							   I_PERBLOCK);
-					ipflag = 1;
-					break;
-				case I_SIZE:
-					isize = getnum(value, &iopts, I_SIZE);
-					inodelog = libxfs_highbit32(isize);
-					isflag = 1;
-					break;
-				case I_ATTR:
-					sb_feat.attr_version =
-						getnum(value, &iopts, I_ATTR);
-					break;
-				case I_PROJID32BIT:
-					sb_feat.projid16bit =
-						!getnum(value, &iopts,
-							I_PROJID32BIT);
-					break;
-				case I_SPINODES:
-					sb_feat.spinodes = getnum(value,
-							&iopts, I_SPINODES);
-					break;
-				default:
-					unknown('i', value);
-				}
-			}
-			break;
-		case 'l':
-			p = optarg;
-			while (*p != '\0') {
-				char	**subopts = (char **)lopts.subopts;
-				char	*value;
-
-				switch (getsubopt(&p, subopts, &value)) {
-				case L_AGNUM:
-					logagno = getnum(value, &lopts, L_AGNUM);
-					laflag = 1;
-					break;
-				case L_FILE:
-					xi.lisfile = getnum(value, &lopts,
-							    L_FILE);
-					break;
-				case L_INTERNAL:
-					loginternal = getnum(value, &lopts,
-							     L_INTERNAL);
-					liflag = 1;
-					break;
-				case L_SU:
-					lsu = getnum(value, &lopts, L_SU);
-					lsuflag = 1;
-					break;
-				case L_SUNIT:
-					lsunit = getnum(value, &lopts, L_SUNIT);
-					lsunitflag = 1;
-					break;
-				case L_NAME:
-				case L_DEV:
-					logfile = getstr(value, &lopts, L_NAME);
-					xi.logname = logfile;
-					ldflag = 1;
-					loginternal = 0;
-					break;
-				case L_VERSION:
-					sb_feat.log_version =
-						getnum(value, &lopts, L_VERSION);
-					lvflag = 1;
-					break;
-				case L_SIZE:
-					logsize = getstr(value, &lopts, L_SIZE);
-					break;
-				case L_SECTLOG:
-					lsectorlog = getnum(value, &lopts,
-							    L_SECTLOG);
-					lsectorsize = 1 << lsectorlog;
-					lslflag = 1;
-					break;
-				case L_SECTSIZE:
-					lsectorsize = getnum(value, &lopts,
-							     L_SECTSIZE);
-					lsectorlog =
-						libxfs_highbit32(lsectorsize);
-					lssflag = 1;
-					break;
-				case L_LAZYSBCNTR:
-					sb_feat.lazy_sb_counters =
-							getnum(value, &lopts,
-							       L_LAZYSBCNTR);
-					break;
-				default:
-					unknown('l', value);
-				}
-			}
-			break;
-		case 'L':
-			if (strlen(optarg) > sizeof(sbp->sb_fname))
-				illegal(optarg, "L");
-			label = optarg;
-			break;
-		case 'm':
-			p = optarg;
-			while (*p != '\0') {
-				char	**subopts = (char **)mopts.subopts;
-				char	*value;
-
-				switch (getsubopt(&p, subopts, &value)) {
-				case M_CRC:
-					sb_feat.crcs_enabled =
-						getnum(value, &mopts, M_CRC);
-					if (sb_feat.crcs_enabled)
-						sb_feat.dirftype = true;
-					break;
-				case M_FINOBT:
-					sb_feat.finobt = getnum(
-						value, &mopts, M_FINOBT);
-					break;
-				case M_UUID:
-					if (!value || *value == '\0')
-						reqval('m', subopts, M_UUID);
-					if (platform_uuid_parse(value, &uuid))
-						illegal(optarg, "m uuid");
-					break;
-				case M_RMAPBT:
-					sb_feat.rmapbt = getnum(
-						value, &mopts, M_RMAPBT);
-					break;
-				case M_REFLINK:
-					sb_feat.reflink = getnum(
-						value, &mopts, M_REFLINK);
-					break;
-				default:
-					unknown('m', value);
-				}
-			}
-			break;
-		case 'n':
-			p = optarg;
-			while (*p != '\0') {
-				char	**subopts = (char **)nopts.subopts;
-				char	*value;
-
-				switch (getsubopt(&p, subopts, &value)) {
-				case N_LOG:
-					dirblocklog = getnum(value, &nopts,
-							     N_LOG);
-					dirblocksize = 1 << dirblocklog;
-					nlflag = 1;
-					break;
-				case N_SIZE:
-					dirblocksize = getnum(value, &nopts,
-							      N_SIZE);
-					dirblocklog =
-						libxfs_highbit32(dirblocksize);
-					nsflag = 1;
-					break;
-				case N_VERSION:
-					value = getstr(value, &nopts, N_VERSION);
-					if (!strcasecmp(value, "ci")) {
-						/* ASCII CI mode */
-						sb_feat.nci = true;
-					} else {
-						sb_feat.dir_version =
-							getnum(value, &nopts,
-							       N_VERSION);
-					}
-					nvflag = 1;
-					break;
-				case N_FTYPE:
-					sb_feat.dirftype = getnum(value, &nopts,
-								  N_FTYPE);
-					break;
-				default:
-					unknown('n', value);
-				}
-			}
-			break;
-		case 'N':
-			Nflag = 1;
-			break;
-		case 'K':
-			discard = 0;
-			break;
-		case 'p':
-			if (protofile)
-				respec('p', NULL, 0);
-			protofile = optarg;
-			break;
-		case 'q':
-			qflag = 1;
-			break;
-		case 'r':
-			p = optarg;
-			while (*p != '\0') {
-				char	**subopts = (char **)ropts.subopts;
-				char	*value;
-
-				switch (getsubopt(&p, subopts, &value)) {
-				case R_EXTSIZE:
-					rtextsize = getstr(value, &ropts,
-							   R_EXTSIZE);
-					break;
-				case R_FILE:
-					xi.risfile = getnum(value, &ropts,
-							    R_FILE);
-					break;
-				case R_NAME:
-				case R_DEV:
-					xi.rtname = getstr(value, &ropts,
-							   R_NAME);
-					break;
-				case R_SIZE:
-					rtsize = getstr(value, &ropts, R_SIZE);
-					break;
-				case R_NOALIGN:
-					norsflag = getnum(value, &ropts,
-								R_NOALIGN);
-					break;
-				default:
-					unknown('r', value);
-				}
-			}
-			break;
-		case 's':
-			p = optarg;
-			while (*p != '\0') {
-				char	**subopts = (char **)sopts.subopts;
-				char	*value;
-
-				switch (getsubopt(&p, subopts, &value)) {
-				case S_LOG:
-				case S_SECTLOG:
-					if (lssflag)
-						conflict('s', subopts,
-							 S_SECTSIZE, S_SECTLOG);
-					sectorlog = getnum(value, &sopts,
-							   S_SECTLOG);
-					lsectorlog = sectorlog;
-					sectorsize = 1 << sectorlog;
-					lsectorsize = sectorsize;
-					lslflag = slflag = 1;
-					break;
-				case S_SIZE:
-				case S_SECTSIZE:
-					if (lslflag)
-						conflict('s', subopts, S_SECTLOG,
-							 S_SECTSIZE);
-					sectorsize = getnum(value, &sopts,
-							    S_SECTSIZE);
-					lsectorsize = sectorsize;
-					sectorlog =
-						libxfs_highbit32(sectorsize);
-					lsectorlog = sectorlog;
-					lssflag = ssflag = 1;
-					break;
-				default:
-					unknown('s', value);
-				}
-			}
-			break;
-		case 'V':
-			printf(_("%s version %s\n"), progname, VERSION);
-			exit(0);
-		case '?':
-			unknown(optopt, "");
+	switch (subopt) {
+	case N_LOG:
+		dirblocklog = getnum(value, opts, N_LOG);
+		cligeo.dirblocksize = 1 << dirblocklog;
+		break;
+	case N_SIZE:
+		cligeo.dirblocksize = getnum(value, opts, N_SIZE);
+		break;
+	case N_VERSION:
+		value = getstr(value, &nopts, N_VERSION);
+		if (!strcasecmp(value, "ci")) {
+			/* ASCII CI mode */
+			sb_feat.nci = true;
+		} else {
+			sb_feat.dir_version = getnum(value, opts, N_VERSION);
 		}
+		break;
+	case N_FTYPE:
+		sb_feat.dirftype = getnum(value, opts, N_FTYPE);
+		break;
+	default:
+		return -EINVAL;
 	}
-	if (argc - optind > 1) {
-		fprintf(stderr, _("extra arguments\n"));
-		usage();
-	} else if (argc - optind == 1) {
-		dfile = xi.volname = getstr(argv[optind], &dopts, D_NAME);
-	} else
-		dfile = xi.dname;
+	return 0;
+}
+
+static int
+rtdev_opts_parser(
+	struct opt_params	*opts,
+	int			subopt,
+	char			*value)
+{
+	switch (subopt) {
+	case R_EXTSIZE:
+		cligeo.rtextsize = getstr(value, &ropts, R_EXTSIZE);
+		break;
+	case R_FILE:
+		xi.risfile = getnum(value, &ropts, R_FILE);
+		break;
+	case R_NAME:
+	case R_DEV:
+		xi.rtname = getstr(value, &ropts, R_NAME);
+		break;
+	case R_SIZE:
+		cligeo.rtsize = getstr(value, &ropts, R_SIZE);
+		break;
+	case R_NOALIGN:
+		sb_feat.nortalign = getnum(value, &ropts, R_NOALIGN);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int
+sector_opts_parser(
+	struct opt_params	*opts,
+	int			subopt,
+	char			*value)
+{
+	int			sectorlog;
+
+	switch (subopt) {
+	case S_LOG:
+	case S_SECTLOG:
+		if (cligeo.sectorsize)
+			conflict('s', opts->subopts, S_SECTSIZE, S_SECTLOG);
+		sectorlog = getnum(value, &sopts, S_SECTLOG);
+		cligeo.sectorsize = 1 << sectorlog;
+		cligeo.lsectorsize = cligeo.sectorsize;
+		break;
+	case S_SIZE:
+	case S_SECTSIZE:
+		if (cligeo.sectorsize)
+			conflict('s', opts->subopts, S_SECTLOG, S_SECTSIZE);
+		cligeo.sectorsize = getnum(value, &sopts, S_SECTSIZE);
+		cligeo.lsectorsize = cligeo.sectorsize;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+struct subopts {
+	char		opt;
+	struct opt_params *opts;
+	int		(*parser)();
+} subopt_tab[] = {
+	{ 'b', &bopts, block_opts_parser },
+	{ 'd', &dopts, data_opts_parser },
+	{ 'i', &iopts, inode_opts_parser },
+	{ 'l', &lopts, log_opts_parser },
+	{ 'm', &mopts, meta_opts_parser },
+	{ 'n', &nopts, naming_opts_parser },
+	{ 'r', &ropts, rtdev_opts_parser },
+	{ 's', &sopts, sector_opts_parser },
+	{ '\0', NULL, NULL },
+};
+
+static void
+parse_subopts(
+	char		opt,
+	char		*arg)
+{
+	struct subopts	*sop = &subopt_tab[0];
+	char		*p;
+	int		ret = 0;
+
+	while (sop->opts) {
+		if (sop->opt == opt)
+			break;
+	}
+
+	/* should never happen */
+	if (!sop->opts)
+		return;
+
+	p = arg;
+	while (*p != '\0') {
+		char	**subopts = (char **)sop->opts->subopts;
+		char	*value;
+		int	subopt;
+
+		subopt = getsubopt(&p, subopts, &value);
+
+		ret = (sop->parser)(sop->opts, subopt, value);
+		if (ret)
+			unknown(opt, value);
+	}
+}
+
+static void
+validate_blocksize(
+	unsigned int	*size,
+	int		*size_log)
+{
 
 	/*
 	 * Blocksize and sectorsize first, other things depend on them
 	 * For RAID4/5/6 we want to align sector size and block size,
 	 * so we need to start with the device geometry extraction too.
 	 */
-	if (!blflag && !bsflag) {
-		blocklog = XFS_DFL_BLOCKSIZE_LOG;
-		blocksize = 1 << XFS_DFL_BLOCKSIZE_LOG;
+	if (!cligeo.blocksize) {
+		*size_log = XFS_DFL_BLOCKSIZE_LOG;
+		*size = 1 << XFS_DFL_BLOCKSIZE_LOG;
+	} else {
+		*size = cligeo.blocksize;
+		*size_log = libxfs_highbit32(cligeo.blocksize);
 	}
-	if (blocksize < XFS_MIN_BLOCKSIZE || blocksize > XFS_MAX_BLOCKSIZE) {
-		fprintf(stderr, _("illegal block size %d\n"), blocksize);
+
+	/* validate block sizes are in range */
+	if (*size < XFS_MIN_BLOCKSIZE || *size > XFS_MAX_BLOCKSIZE) {
+		fprintf(stderr, _("illegal block size %d\n"), *size);
 		usage();
 	}
-	if (sb_feat.crcs_enabled && blocksize < XFS_MIN_CRC_BLOCKSIZE) {
+	if (sb_feat.crcs_enabled && *size < XFS_MIN_CRC_BLOCKSIZE) {
 		fprintf(stderr,
 _("Minimum block size for CRC enabled filesystems is %d bytes.\n"),
 			XFS_MIN_CRC_BLOCKSIZE);
 		usage();
 	}
-	if (sb_feat.crcs_enabled && !sb_feat.dirftype) {
-		fprintf(stderr, _("cannot disable ftype with crcs enabled\n"));
-		usage();
-	}
+}
 
-	if (!slflag && !ssflag) {
-		sectorlog = XFS_MIN_SECTORSIZE_LOG;
-		sectorsize = XFS_MIN_SECTORSIZE;
-	}
-	if (!lslflag && !lssflag) {
-		lsectorlog = sectorlog;
-		lsectorsize = sectorsize;
+static void
+validate_sectorsize(
+	unsigned int	*size,
+	int		*size_log,
+	struct fs_topology *ft,
+	char		*dfile,
+	int		Nflag,
+	int		force_overwrite)
+{
+	/* set configured sector sizes in preparation for checks */
+	if (!cligeo.sectorsize) {
+		*size_log = XFS_MIN_SECTORSIZE_LOG;
+		*size = XFS_MIN_SECTORSIZE;
+	} else {
+		*size = cligeo.sectorsize;
+		*size_log = libxfs_highbit32(cligeo.sectorsize);
 	}
 
 	/*
 	 * Before anything else, verify that we are correctly operating on
 	 * files or block devices and set the control parameters correctly.
-	 * Explicitly disable direct IO for image files so we don't error out on
-	 * sector size mismatches between the new filesystem and the underlying
-	 * host filesystem.
 	 */
-	check_device_type(dfile, &xi.disfile, !dsize, !dfile,
+	check_device_type(dfile, &xi.disfile, !cligeo.dsize, !dfile,
 			  Nflag ? NULL : &xi.dcreat, force_overwrite, "d");
-	if (!loginternal)
-		check_device_type(xi.logname, &xi.lisfile, !logsize, !xi.logname,
-				  Nflag ? NULL : &xi.lcreat,
+	if (!cligeo.loginternal)
+		check_device_type(xi.logname, &xi.lisfile, !cligeo.logsize,
+				  !xi.logname, Nflag ? NULL : &xi.lcreat,
 				  force_overwrite, "l");
 	if (xi.rtname)
-		check_device_type(xi.rtname, &xi.risfile, !rtsize, !xi.rtname,
-				  Nflag ? NULL : &xi.rcreat,
+		check_device_type(xi.rtname, &xi.risfile, !cligeo.rtsize,
+				  !xi.rtname, Nflag ? NULL : &xi.rcreat,
 				  force_overwrite, "r");
+
+	/*
+	 * Explicitly disable direct IO for image files so we don't error out on
+	 * sector size mismatches between the new filesystem and the underlying
+	 * host filesystem.
+	 */
 	if (xi.disfile || xi.lisfile || xi.risfile)
 		xi.isdirect = 0;
 
-	memset(&ft, 0, sizeof(ft));
-	get_topology(&xi, &ft, force_overwrite);
+	memset(ft, 0, sizeof(*ft));
+	get_topology(&xi, ft, force_overwrite);
 
-	if (!ssflag) {
+	if (!cligeo.sectorsize) {
 		/*
 		 * Unless specified manually on the command line use the
 		 * advertised sector size of the device.  We use the physical
@@ -2004,56 +1822,93 @@ _("Minimum block size for CRC enabled filesystems is %d bytes.\n"),
 		 */
 
 		/* Older kernels may not have physical/logical distinction */
-		if (!ft.psectorsize)
-			ft.psectorsize = ft.lsectorsize;
+		if (!ft->psectorsize)
+			ft->psectorsize = ft->lsectorsize;
 
-		sectorsize = ft.psectorsize ? ft.psectorsize :
+		*size = ft->psectorsize ? ft->psectorsize :
 					      XFS_MIN_SECTORSIZE;
 
-		if ((blocksize < sectorsize) && (blocksize >= ft.lsectorsize)) {
+		if ((blocksize < *size) && (blocksize >= ft->lsectorsize)) {
 			fprintf(stderr,
 _("specified blocksize %d is less than device physical sector size %d\n"),
-				blocksize, ft.psectorsize);
+				blocksize, ft->psectorsize);
 			fprintf(stderr,
 _("switching to logical sector size %d\n"),
-				ft.lsectorsize);
-			sectorsize = ft.lsectorsize ? ft.lsectorsize :
+				ft->lsectorsize);
+			*size = ft->lsectorsize ? ft->lsectorsize :
 						      XFS_MIN_SECTORSIZE;
 		}
-	}
 
-	if (!ssflag) {
-		sectorlog = libxfs_highbit32(sectorsize);
-		if (loginternal) {
-			lsectorsize = sectorsize;
-			lsectorlog = sectorlog;
-		}
+		*size_log = libxfs_highbit32(*size);
 	}
 
-	if (sectorsize < XFS_MIN_SECTORSIZE ||
-	    sectorsize > XFS_MAX_SECTORSIZE || sectorsize > blocksize) {
-		if (ssflag)
-			fprintf(stderr, _("illegal sector size %d\n"), sectorsize);
+	/* validate specified/probed sector size */
+	if (*size < XFS_MIN_SECTORSIZE ||
+	    *size > XFS_MAX_SECTORSIZE || *size > blocksize) {
+		if (cligeo.sectorsize)
+			fprintf(stderr, _("illegal sector size %d\n"), *size);
 		else
 			fprintf(stderr,
 _("block size %d cannot be smaller than logical sector size %d\n"),
-				blocksize, ft.lsectorsize);
+				blocksize, ft->lsectorsize);
 		usage();
 	}
-	if (sectorsize < ft.lsectorsize) {
+	if (*size < ft->lsectorsize) {
 		fprintf(stderr, _("illegal sector size %d; hw sector is %d\n"),
-			sectorsize, ft.lsectorsize);
+			*size, ft->lsectorsize);
+		usage();
+	}
+}
+
+/*
+ * Grab log sector size and validate.
+ *
+ * XXX: probe sector size on external log device rather than using ssize?
+ */
+static void
+validate_log_sectorsize(
+	int	*lsize,
+	int	*lsize_log,
+	int	sectorsize,
+	int	sectorlog)
+{
+
+	if (cligeo.lsectorsize && cligeo.loginternal) {
+		fprintf(stderr, _("Can't set sector size on internal log!\n"));
 		usage();
 	}
-	if (lsectorsize < XFS_MIN_SECTORSIZE ||
-	    lsectorsize > XFS_MAX_SECTORSIZE || lsectorsize > blocksize) {
-		fprintf(stderr, _("illegal log sector size %d\n"), lsectorsize);
+	if (!cligeo.lsectorsize) {
+		*lsize_log = sectorlog;
+		*lsize = sectorsize;
+	} else {
+		*lsize = cligeo.lsectorsize;
+		*lsize_log = libxfs_highbit32(cligeo.lsectorsize);
+	}
+
+	if (*lsize < XFS_MIN_SECTORSIZE ||
+	    *lsize > XFS_MAX_SECTORSIZE || *lsize > blocksize) {
+		fprintf(stderr, _("illegal log sector size %d\n"), *lsize);
 		usage();
-	} else if (lsectorsize > XFS_MIN_SECTORSIZE && !lsu && !lsunit) {
-		lsu = blocksize;
+	}
+	if (*lsize > XFS_MIN_SECTORSIZE &&
+	    cligeo.lsu <= 0 && cligeo.lsunit <= 0) {
+		cligeo.lsu = blocksize;
 		sb_feat.log_version = 2;
 	}
 
+	/* if lsu or lsunit was specified, automatically use v2 logs */
+	if ((cligeo.lsu || cligeo.lsunit) && sb_feat.log_version == 1) {
+		fprintf(stderr,
+			_("log stripe unit specified, using v2 logs\n"));
+		sb_feat.log_version = 2;
+	}
+
+}
+
+static void
+validate_sb_features(void)
+{
+
 	/*
 	 * Now we have blocks and sector sizes set up, check parameters that are
 	 * no longer optional for CRC enabled filesystems.  Catch them up front
@@ -2061,7 +1916,8 @@ _("block size %d cannot be smaller than logical sector size %d\n"),
 	 */
 	if (sb_feat.crcs_enabled) {
 		/* minimum inode size is 512 bytes, ipflag checked later */
-		if ((isflag || ilflag) && inodelog < XFS_DINODE_DFL_CRC_LOG) {
+		if (cligeo.inodesize &&
+		    cligeo.inodesize < (1 << XFS_DINODE_DFL_CRC_LOG)) {
 			fprintf(stderr,
 _("Minimum inode size for CRCs is %d bytes\n"),
 				1 << XFS_DINODE_DFL_CRC_LOG);
@@ -2103,6 +1959,14 @@ _("V2 attribute format always enabled on CRC enabled filesytems\n"));
 _("32 bit Project IDs always enabled on CRC enabled filesytems\n"));
 			usage();
 		}
+
+		/* ftype always on */
+		if (!sb_feat.dirftype) {
+			fprintf(stderr,
+_("Directory ftype field always enabled on CRC enabled filesytems\n"));
+			usage();
+		}
+
 	} else {
 		/*
 		 * The kernel doesn't currently support crc=0,finobt=1
@@ -2149,103 +2013,137 @@ _("rmapbt not supported with realtime devices\n"));
 		usage();
 		sb_feat.rmapbt = false;
 	}
+}
 
-	if (nsflag || nlflag) {
-		if (dirblocksize < blocksize ||
-					dirblocksize > XFS_MAX_BLOCKSIZE) {
-			fprintf(stderr, _("illegal directory block size %d\n"),
-				dirblocksize);
-			usage();
-		}
-	} else {
+static void
+validate_dirblocksize(
+	int	*size,
+	int	*size_log,
+	int	blocklog)
+{
+
+	if (cligeo.dirblocksize &&
+	    (cligeo.dirblocksize < blocksize ||
+	     cligeo.dirblocksize > XFS_MAX_BLOCKSIZE)) {
+		fprintf(stderr, _("illegal directory block size %d\n"),
+			cligeo.dirblocksize);
+		usage();
+	}
+
+	if (!cligeo.dirblocksize) {
 		if (blocksize < (1 << XFS_MIN_REC_DIRSIZE))
-			dirblocklog = XFS_MIN_REC_DIRSIZE;
+			*size_log = XFS_MIN_REC_DIRSIZE;
 		else
-			dirblocklog = blocklog;
-		dirblocksize = 1 << dirblocklog;
+			*size_log = blocklog;
+		*size = 1 << *size_log;
+	} else {
+		*size = cligeo.dirblocksize;
+		*size_log = libxfs_highbit32(cligeo.dirblocksize);
 	}
+}
 
+static void
+validate_inodesize(
+	int	*size,
+	int	*size_log,
+	int	*inodes_per_block,
+	int	blocklog)
+{
 
-	if (dsize) {
-		uint64_t dbytes;
-
-		dbytes = getnum(dsize, &dopts, D_SIZE);
-		if (dbytes % XFS_MIN_BLOCKSIZE) {
-			fprintf(stderr,
-			_("illegal data length %lld, not a multiple of %d\n"),
-				(long long)dbytes, XFS_MIN_BLOCKSIZE);
-			usage();
-		}
-		dblocks = (xfs_rfsblock_t)(dbytes >> blocklog);
-		if (dbytes % blocksize)
-			fprintf(stderr, _("warning: "
-	"data length %lld not a multiple of %d, truncated to %lld\n"),
-				(long long)dbytes, blocksize,
-				(long long)(dblocks << blocklog));
-	}
-	if (ipflag) {
-		inodelog = blocklog - libxfs_highbit32(inopblock);
-		isize = 1 << inodelog;
-	} else if (!ilflag && !isflag) {
-		inodelog = sb_feat.crcs_enabled ? XFS_DINODE_DFL_CRC_LOG
+	if (cligeo.inopblock) {
+		*inodes_per_block = cligeo.inopblock;
+		*size_log = blocklog - libxfs_highbit32(cligeo.inopblock);
+		*size = 1 << *size_log;
+	} else if (cligeo.inodesize) {
+		*size = cligeo.inodesize;
+		*size_log = libxfs_highbit32(*size);
+		*inodes_per_block = blocksize / *size;
+	} else {
+		*size_log = sb_feat.crcs_enabled ? XFS_DINODE_DFL_CRC_LOG
 						: XFS_DINODE_DFL_LOG;
-		isize = 1 << inodelog;
+		*size = 1 << *size_log;
+		*inodes_per_block = blocksize / *size;
 	}
-	if (sb_feat.crcs_enabled && inodelog < XFS_DINODE_DFL_CRC_LOG) {
+	if (sb_feat.crcs_enabled && *size_log < XFS_DINODE_DFL_CRC_LOG) {
 		fprintf(stderr,
 		_("Minimum inode size for CRCs is %d bytes\n"),
 			1 << XFS_DINODE_DFL_CRC_LOG);
 		usage();
 	}
 
-	if (logsize) {
-		uint64_t logbytes;
+	if (*size > blocksize / XFS_MIN_INODE_PERBLOCK ||
+	    *inodes_per_block < XFS_MIN_INODE_PERBLOCK ||
+	    *size < XFS_DINODE_MIN_SIZE ||
+	    *size > XFS_DINODE_MAX_SIZE) {
+		int	maxsz;
 
-		logbytes = getnum(logsize, &lopts, L_SIZE);
-		if (logbytes % XFS_MIN_BLOCKSIZE) {
+		fprintf(stderr, _("illegal inode size %d\n"), *size);
+		maxsz = MIN(blocksize / XFS_MIN_INODE_PERBLOCK,
+			    XFS_DINODE_MAX_SIZE);
+		if (XFS_DINODE_MIN_SIZE == maxsz)
 			fprintf(stderr,
-			_("illegal log length %lld, not a multiple of %d\n"),
-				(long long)logbytes, XFS_MIN_BLOCKSIZE);
-			usage();
-		}
-		logblocks = (xfs_rfsblock_t)(logbytes >> blocklog);
-		if (logbytes % blocksize)
+			_("allowable inode size with %d byte blocks is %d\n"),
+				blocksize, XFS_DINODE_MIN_SIZE);
+		else
 			fprintf(stderr,
-	_("warning: log length %lld not a multiple of %d, truncated to %lld\n"),
-				(long long)logbytes, blocksize,
-				(long long)(logblocks << blocklog));
+	_("allowable inode size with %d byte blocks is between %d and %d\n"),
+				blocksize, XFS_DINODE_MIN_SIZE, maxsz);
+		exit(1);
 	}
-	if (rtsize) {
-		uint64_t rtbytes;
+}
 
-		rtbytes = getnum(rtsize, &ropts, R_SIZE);
-		if (rtbytes % XFS_MIN_BLOCKSIZE) {
-			fprintf(stderr,
-			_("illegal rt length %lld, not a multiple of %d\n"),
-				(long long)rtbytes, XFS_MIN_BLOCKSIZE);
-			usage();
-		}
-		rtblocks = (xfs_rfsblock_t)(rtbytes >> blocklog);
-		if (rtbytes % blocksize)
-			fprintf(stderr,
-	_("warning: rt length %lld not a multiple of %d, truncated to %lld\n"),
-				(long long)rtbytes, blocksize,
-				(long long)(rtblocks << blocklog));
+static xfs_rfsblock_t
+calc_dev_size(
+	char		*size,
+	struct opt_params *opts,
+	int		sizeopt,
+	int		blocklog,
+	char		*type)
+{
+	uint64_t	 dbytes;
+	xfs_rfsblock_t	dblocks;
+
+	if (!size)
+		return 0;
+
+	dbytes = getnum(size, opts, sizeopt);
+	if (dbytes % XFS_MIN_BLOCKSIZE) {
+		fprintf(stderr,
+		_("illegal %s length %lld, not a multiple of %d\n"),
+			type, (long long)dbytes, XFS_MIN_BLOCKSIZE);
+		usage();
+	}
+	dblocks = (xfs_rfsblock_t)(dbytes >> blocklog);
+	if (dbytes % blocksize) {
+		fprintf(stderr,
+_("warning: %s length %lld not a multiple of %d, truncated to %lld\n"),
+			type, (long long)dbytes, blocksize,
+			(long long)(dblocks << blocklog));
 	}
+	return dblocks;
+}
+
+static void
+validate_rtextsize(
+	xfs_extlen_t		*blocks,
+	struct fs_topology	*ft,
+	int			blocklog)
+{
+	uint64_t		rtextbytes;
+
 	/*
 	 * If specified, check rt extent size against its constraints.
 	 */
-	if (rtextsize) {
-		uint64_t rtextbytes;
+	if (cligeo.rtextsize) {
 
-		rtextbytes = getnum(rtextsize, &ropts, R_EXTSIZE);
+		rtextbytes = getnum(cligeo.rtextsize, &ropts, R_EXTSIZE);
 		if (rtextbytes % blocksize) {
 			fprintf(stderr,
 		_("illegal rt extent size %lld, not a multiple of %d\n"),
 				(long long)rtextbytes, blocksize);
 			usage();
 		}
-		rtextblocks = (xfs_extlen_t)(rtextbytes >> blocklog);
+		*blocks = (xfs_extlen_t)(rtextbytes >> blocklog);
 	} else {
 		/*
 		 * If realtime extsize has not been specified by the user,
@@ -2253,70 +2151,314 @@ _("rmapbt not supported with realtime devices\n"));
 		 * to the stripe width.
 		 */
 		uint64_t	rswidth;
-		uint64_t	rtextbytes;
 
-		if (!norsflag && !xi.risfile && !(!rtsize && xi.disfile))
-			rswidth = ft.rtswidth;
+		if (!sb_feat.nortalign && !xi.risfile &&
+		    !(!cligeo.rtsize && xi.disfile))
+			rswidth = ft->rtswidth;
 		else
 			rswidth = 0;
 
 		/* check that rswidth is a multiple of fs blocksize */
-		if (!norsflag && rswidth && !(BBTOB(rswidth) % blocksize)) {
+		if (!sb_feat.nortalign && rswidth &&
+		    !(BBTOB(rswidth) % blocksize)) {
 			rswidth = DTOBT(rswidth);
 			rtextbytes = rswidth << blocklog;
 			if (XFS_MIN_RTEXTSIZE <= rtextbytes &&
 			    (rtextbytes <= XFS_MAX_RTEXTSIZE)) {
-				rtextblocks = rswidth;
+				*blocks = rswidth;
 			}
 		}
-		if (!rtextblocks) {
-			rtextblocks = (blocksize < XFS_MIN_RTEXTSIZE) ?
+		if (!*blocks) {
+			*blocks = (blocksize < XFS_MIN_RTEXTSIZE) ?
 					XFS_MIN_RTEXTSIZE >> blocklog : 1;
 		}
 	}
-	ASSERT(rtextblocks);
+	ASSERT(*blocks);
+}
 
-	/*
-	 * Check some argument sizes against mins, maxes.
-	 */
-	if (isize > blocksize / XFS_MIN_INODE_PERBLOCK ||
-	    isize < XFS_DINODE_MIN_SIZE ||
-	    isize > XFS_DINODE_MAX_SIZE) {
-		int	maxsz;
+/*
+ * Convert lsu to lsunit for 512 bytes blocks and check validity of the values.
+ */
+static void
+calc_stripe_factors(
+	int		dsectsz,
+	int		lsectsz,
+	int		*dsunit,
+	int		*dswidth,
+	int		*lsunit)
+{
+	int		dsu;
+	int		dsw;
+	int		lsu;
 
-		fprintf(stderr, _("illegal inode size %d\n"), isize);
-		maxsz = MIN(blocksize / XFS_MIN_INODE_PERBLOCK,
-			    XFS_DINODE_MAX_SIZE);
-		if (XFS_DINODE_MIN_SIZE == maxsz)
+	*dsunit = cligeo.dsunit == -1 ? 0 : cligeo.dsunit;
+	*dswidth = cligeo.dswidth == -1 ? 0 : cligeo.dswidth;
+	*lsunit = cligeo.lsunit == -1 ? 0 : cligeo.lsunit;
+
+	dsu = cligeo.dsu == -1 ? 0 : cligeo.dsu;
+	dsw = cligeo.dsw == -1 ? 0 : cligeo.dsw;
+	lsu = cligeo.lsu == -1 ? 0 : cligeo.lsu;
+
+	/* Handle data sunit/swidth options */
+	if ((*dsunit && !*dswidth) || (!*dsunit && *dswidth)) {
+		fprintf(stderr,
+_("both data sunit and data swidth options must be specified\n"));
+		usage();
+	}
+
+	if (dsu || dsw) {
+		if ((dsu && !dsw) || (!dsu && dsw)) {
 			fprintf(stderr,
-			_("allowable inode size with %d byte blocks is %d\n"),
-				blocksize, XFS_DINODE_MIN_SIZE);
-		else
+_("both data su and data sw options must be specified\n"));
+			usage();
+		}
+
+		if (dsu % dsectsz) {
 			fprintf(stderr,
-	_("allowable inode size with %d byte blocks is between %d and %d\n"),
-				blocksize, XFS_DINODE_MIN_SIZE, maxsz);
-		exit(1);
+_("data su must be a multiple of the sector size (%d)\n"), dsectsz);
+			usage();
+		}
+
+		*dsunit  = (int)BTOBBT(dsu);
+		*dswidth = *dsunit * dsw;
 	}
 
-	/* if lsu or lsunit was specified, automatically use v2 logs */
-	if ((lsu || lsunit) && sb_feat.log_version == 1) {
+	if (*dsunit && (*dswidth % *dsunit != 0)) {
 		fprintf(stderr,
-			_("log stripe unit specified, using v2 logs\n"));
-		sb_feat.log_version = 2;
+_("data stripe width (%d) must be a multiple of the data stripe unit (%d)\n"),
+			*dswidth, *dsunit);
+		usage();
 	}
 
-	calc_stripe_factors(dsu, dsw, sectorsize, lsu, lsectorsize,
-				&dsunit, &dswidth, &lsunit);
+	/* Handle log sunit options */
+
+	if (lsu)
+		*lsunit = (int)BTOBBT(lsu);
+
+	/* verify if lsu/lsunit is a multiple block size */
+	if (lsu % blocksize != 0) {
+		fprintf(stderr,
+_("log stripe unit (%d) must be a multiple of the block size (%d)\n"),
+			lsu, blocksize);
+		exit(1);
+	}
+	if ((BBTOB(*lsunit) % blocksize != 0)) {
+		fprintf(stderr,
+_("log stripe unit (%d) must be a multiple of the block size (%d)\n"),
+		BBTOB(*lsunit), blocksize);
+		exit(1);
+	}
 
 	/* If sunit & swidth were manually specified as 0, same as noalign */
-	if (dsflag && !dsunit && !dswidth)
-		nodsflag = 1;
+	if (cligeo.dsunit != -1 && !dsunit && !dswidth)
+		sb_feat.nodalign = true;
+}
+
+int
+main(
+	int			argc,
+	char			**argv)
+{
+	uint64_t		agcount;
+	xfs_agf_t		*agf;
+	xfs_agi_t		*agi;
+	xfs_agnumber_t		agno;
+	uint64_t		agsize;
+	xfs_alloc_rec_t		*arec;
+	struct xfs_btree_block	*block;
+	int			blocklog;
+	int			bsize;
+	xfs_buf_t		*buf;
+	int			c;
+	int			daflag;
+	int			dasize;
+	xfs_rfsblock_t		dblocks;
+	char			*dfile;
+	int			dirblocklog;
+	int			dirblocksize;
+	char			*dsize;
+	int			dsunit;
+	int			dswidth;
+	int			force_overwrite;
+	int			imaxpct;
+	int			imflag;
+	int			inodelog;
+	int			inopblock;
+	int			ipflag;
+	int			isflag;
+	int			isize;
+	char			*label = NULL;
+	int			laflag;
+	int			lalign;
+	int			ldflag;
+	int			liflag;
+	xfs_agnumber_t		logagno;
+	xfs_rfsblock_t		logblocks;
+	char			*logfile;
+	int			loginternal;
+	char			*logsize;
+	xfs_fsblock_t		logstart;
+	int			lvflag;
+	int			lsflag;
+	int			lsuflag;
+	int			lsunitflag;
+	int			lsectorlog;
+	int			lsectorsize;
+	int			lsu;
+	int			lsunit;
+	int			min_logblocks;
+	xfs_mount_t		*mp;
+	xfs_mount_t		mbuf;
+	xfs_extlen_t		nbmblocks;
+	int			nlflag;
+	int			nodsflag;
+	int			norsflag;
+	xfs_alloc_rec_t		*nrec;
+	int			nsflag;
+	int			nvflag;
+	int			Nflag;
+	int			discard = 1;
+	char			*protofile;
+	char			*protostring;
+	int			qflag;
+	xfs_rfsblock_t		rtblocks;
+	xfs_extlen_t		rtextblocks;
+	xfs_rtblock_t		rtextents;
+	char			*rtextsize;
+	char			*rtfile;
+	char			*rtsize;
+	xfs_sb_t		*sbp;
+	int			sectorlog;
+	uint64_t		sector_mask;
+	uint64_t		tmp_agsize;
+	uuid_t			uuid;
+	int			worst_freelist;
+	struct fs_topology	ft;
+
+	platform_uuid_generate(&uuid);
+	progname = basename(argv[0]);
+	setlocale(LC_ALL, "");
+	bindtextdomain(PACKAGE, LOCALEDIR);
+	textdomain(PACKAGE);
+
+	blocklog = blocksize = 0;
+	sectorlog = lsectorlog = 0;
+	sectorsize = lsectorsize = 0;
+	agsize = daflag = dasize = dblocks = 0;
+	imflag = ipflag = isflag = 0;
+	liflag = laflag = lsflag = lsuflag = lsunitflag = ldflag = lvflag = 0;
+	loginternal = 1;
+	logagno = logblocks = rtblocks = rtextblocks = 0;
+	Nflag = nlflag = nsflag = nvflag = 0;
+	dirblocklog = dirblocksize = 0;
+	qflag = 0;
+	imaxpct = inodelog = inopblock = isize = 0;
+	dfile = logfile = rtfile = NULL;
+	dsize = logsize = rtsize = rtextsize = protofile = NULL;
+	dsunit = dswidth = lalign = lsu = lsunit = 0;
+	nodsflag = norsflag = 0;
+	force_overwrite = 0;
+	worst_freelist = 0;
+
+	/*
+	 * set parameters that can be set to zero to -1 or a default value so we
+	 * can tell if they have been set or not This gets rid of all the "was
+	 * it specified" flags.
+	 */
+	cligeo.dsu = -1;
+	cligeo.dsw = -1;
+	cligeo.dsunit = -1;
+	cligeo.dswidth = -1;
+	cligeo.loginternal = 1;
+	cligeo.logagno = -1;
+	cligeo.lsu = -1;
+	cligeo.lsunit = -1;
+
+	xi.isdirect = LIBXFS_DIRECT;
+	xi.isreadonly = LIBXFS_EXCLUSIVELY;
+
+	while ((c = getopt(argc, argv, "b:d:i:l:L:m:n:KNp:qr:s:CfV")) != EOF) {
+		switch (c) {
+		case 'C':
+		case 'f':
+			force_overwrite = 1;
+			break;
+		case 'b':
+		case 'd':
+		case 'i':
+		case 'l':
+		case 'm':
+		case 'n':
+		case 'r':
+		case 's':
+			parse_subopts(c, optarg);
+			break;
+		case 'L':
+			if (strlen(optarg) > sizeof(sbp->sb_fname))
+				illegal(optarg, "L");
+			label = optarg;
+			break;
+		case 'N':
+			Nflag = 1;
+			break;
+		case 'K':
+			discard = 0;
+			break;
+		case 'p':
+			if (protofile)
+				respec('p', NULL, 0);
+			protofile = optarg;
+			break;
+		case 'q':
+			qflag = 1;
+			break;
+		case 'V':
+			printf(_("%s version %s\n"), progname, VERSION);
+			exit(0);
+		case '?':
+			unknown(optopt, "");
+		}
+	}
+	if (argc - optind > 1) {
+		fprintf(stderr, _("extra arguments\n"));
+		usage();
+	} else if (argc - optind == 1) {
+		dfile = xi.volname = getstr(argv[optind], &dopts, D_NAME);
+	} else
+		dfile = xi.dname;
+
+	/*
+	 * Extract as much of the valid config as we can from the CLI input
+	 * before opening the libxfs devices.
+	 */
+	validate_blocksize(&blocksize, &blocklog);
+	validate_sectorsize(&sectorsize, &sectorlog, &ft, dfile, Nflag,
+			    force_overwrite);
+	validate_log_sectorsize(&lsectorsize, &lsectorlog,
+				sectorsize, sectorlog);
+	validate_sb_features();
+
+	validate_dirblocksize(&dirblocksize, &dirblocklog, blocklog);
+	validate_inodesize(&isize, &inodelog, &inopblock, blocklog);
+
+	/*
+	 * if the device size was specified convert it to a block count
+	 * now we have a valid block size. These will be set to zero if
+	 * nothing was specified, indicating we should use the full device.
+	 */
+	dblocks = calc_dev_size(cligeo.dsize, &dopts, D_SIZE, blocklog, "data");
+	logblocks = calc_dev_size(cligeo.logsize, &lopts, L_SIZE, blocklog, "log");
+	rtblocks = calc_dev_size(cligeo.rtsize, &ropts, R_SIZE, blocklog, "rt");
+
+	validate_rtextsize(&rtextblocks, &ft, blocklog);
+
+	calc_stripe_factors(sectorsize, lsectorsize, &dsunit, &dswidth, &lsunit);
 
-	xi.setblksize = sectorsize;
 
 	/*
 	 * Initialize.  This will open the log and rt devices as well.
 	 */
+	xi.setblksize = sectorsize;
 	if (!libxfs_init(&xi))
 		usage();
 	if (!xi.ddev) {
@@ -3364,7 +3506,7 @@ _("size %s specified for log subvolume is too large, maximum is %lld blocks\n"),
 static void
 conflict(
 	char		opt,
-	char		*tab[],
+	const char	*tab[],
 	int		oldidx,
 	int		newidx)
 {
@@ -3393,7 +3535,7 @@ ispow2(
 static void __attribute__((noreturn))
 reqval(
 	char		opt,
-	char		*tab[],
+	const char	*tab[],
 	int		idx)
 {
 	fprintf(stderr, _("-%c %s option requires a value\n"), opt, tab[idx]);
@@ -3403,7 +3545,7 @@ reqval(
 static void
 respec(
 	char		opt,
-	char		*tab[],
+	const char	*tab[],
 	int		idx)
 {
 	fprintf(stderr, "-%c ", opt);

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

* Re: [PATCH 3/6 v2] mkfs: remove intermediate getstr followed by getnum
  2017-08-15 15:08   ` [PATCH 3/6 v2] mkfs: remove intermediate getstr followed by getnum Jan Tulak
  2017-08-15 23:20     ` Eric Sandeen
@ 2017-08-17 11:36     ` Dave Chinner
  1 sibling, 0 replies; 37+ messages in thread
From: Dave Chinner @ 2017-08-17 11:36 UTC (permalink / raw)
  To: Jan Tulak; +Cc: linux-xfs

On Tue, Aug 15, 2017 at 05:08:09PM +0200, Jan Tulak wrote:
> Some options loaded a number as a string with getstr and converted it to
> number with getnum later in the code, without any reason for this
> approach.  (They were probably forgotten in some past cleaning.)

Ah, no. That was done very intentionally.

> @@ -1672,7 +1674,7 @@ main(
>  					xi.dname = getstr(value, &dopts, D_NAME);
>  					break;
>  				case D_SIZE:
> -					dsize = getstr(value, &dopts, D_SIZE);
> +					dbytes = getnum(value, &dopts, D_SIZE);
>  					break;

At this point here, the size can be specified in filesystem blocks
or sectors.  We don't know what those sizes are yet - they might be
given to us later on the CLI so haven't been parsed yet.

Hence we can't convert from a string to a number yet, because the
units to do the conversion aren't defined.

Same goes for all the other 3 sizes that use strings.

> @@ -2254,10 +2255,7 @@ _("rmapbt not supported with realtime devices\n"));
>  	}
>  
>  
> -	if (dsize) {
> -		uint64_t dbytes;
> -
> -		dbytes = getnum(dsize, &dopts, D_SIZE);
> +	if (dbytes) {
>  		if (dbytes % XFS_MIN_BLOCKSIZE) {
>  			fprintf(stderr,
>  			_("illegal data length %lld, not a multiple of %d\n"),

By this time, we've validated the command line provided block/sector
sizes or have used and validated the default size. Hence we can now
convert from a string to a number as all the units we need are
defined.

IOWs, changing this code will break "size=XXXb" and "size=XXXs" CLI
size specification in unexpected ways.

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

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

* Re: [PATCH 6/6 v2] mkfs: extend opt_params with a value field
  2017-08-17 11:03           ` Dave Chinner
@ 2017-08-17 14:56             ` Jan Tulak
  2017-08-17 22:59               ` Dave Chinner
  0 siblings, 1 reply; 37+ messages in thread
From: Jan Tulak @ 2017-08-17 14:56 UTC (permalink / raw)
  To: Dave Chinner; +Cc: Darrick J. Wong, Eric Sandeen, linux-xfs

On Thu, Aug 17, 2017 at 1:03 PM, Dave Chinner <david@fromorbit.com> wrote:
> Hi folks,
>
> I'm going to put my 2c worth in here in the form of a patch.  The
> tl;dr of it all is that I think we need to reset and reflect on what
> I was originally trying to acheive with the table based option
> parsing: factoring and simplifying mkfs into an easy to understand,
> maintainable code base....
>
> And, while I remember, there's a handful of input validation bugs I
> found in the code whiel I was doing this (like missing conflict
> checks).
>
> Anyway, have a look, based on the current for-next branch.
>
>> >> [1] # mkfs.xfs -dfile,name=fsfile,size=1g,sectsize=4k -lfile,name=logfile,size=512m,sectsize=512
>> >
>> > I see -d sectsize is in the --help screen but not the manpage.  Can we
>> > fix that?
>>
>> I made it, but Dave would rather see the -d sectsize option removed.
>> Which I'm not sure about...
>> See "[PATCH] xfsprogs: add sectsize/sectlog to the man page"
>
> Slash and burn - there is so much useless, redundant crap in the CLI
> we've been holding onto for 15 years that we should just get rid of
> it. That's what I was intending to do originally with this rework
> and I still see no reason why we should be keeping stuff that just
> causes user confusion and implemention complexity.

I went through it and I admit that his shot seems to go in a much
better way than my patches; I focused on the opts structure too much I
guess. :-) So, thanks for this restart. I'm going to compare it with
my changes and check which parts of my set makes sense in this
direction as well and which do not...

And this is maybe a bit premature idea now, but should we add some way
how to tell the user "this option is deprecated, use XXX"? I think
that it is a good idea if we are removing parts of the CLI, which
might break some user scripts or workflow. It would be pretty easy to
do - with something like your *_opts_parser() functions, just a case,
print the error and return EINVAL.

Cheers,
Jan

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

* Re: [PATCH 6/6 v2] mkfs: extend opt_params with a value field
  2017-08-17 10:08         ` Jan Tulak
  2017-08-17 11:03           ` Dave Chinner
@ 2017-08-17 15:26           ` Eric Sandeen
  1 sibling, 0 replies; 37+ messages in thread
From: Eric Sandeen @ 2017-08-17 15:26 UTC (permalink / raw)
  To: Jan Tulak, Darrick J. Wong; +Cc: linux-xfs

On 8/17/17 5:08 AM, Jan Tulak wrote:
>>> But also because the above is wrong; it is possible for the filesystem data
>>> portion and log portion to have different sector sizes, if the log is external. [1]
>>> The above would seem to break that, always setting data & log sizes together.

> But in the current for-next tree mkfs does set data and log sector
> size at the same time,
> this patch is not doing anything new

Yes, you are right about this - I lost my train of thought on that one, sorry.

-Eric

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

* Re: [PATCH 6/6 v2] mkfs: extend opt_params with a value field
  2017-08-17 14:56             ` Jan Tulak
@ 2017-08-17 22:59               ` Dave Chinner
  0 siblings, 0 replies; 37+ messages in thread
From: Dave Chinner @ 2017-08-17 22:59 UTC (permalink / raw)
  To: Jan Tulak; +Cc: Darrick J. Wong, Eric Sandeen, linux-xfs

On Thu, Aug 17, 2017 at 04:56:18PM +0200, Jan Tulak wrote:
> On Thu, Aug 17, 2017 at 1:03 PM, Dave Chinner <david@fromorbit.com> wrote:
> > Hi folks,
> >
> > I'm going to put my 2c worth in here in the form of a patch.  The
> > tl;dr of it all is that I think we need to reset and reflect on what
> > I was originally trying to acheive with the table based option
> > parsing: factoring and simplifying mkfs into an easy to understand,
> > maintainable code base....
> >
> > And, while I remember, there's a handful of input validation bugs I
> > found in the code whiel I was doing this (like missing conflict
> > checks).
> >
> > Anyway, have a look, based on the current for-next branch.
> >
> >> >> [1] # mkfs.xfs -dfile,name=fsfile,size=1g,sectsize=4k -lfile,name=logfile,size=512m,sectsize=512
> >> >
> >> > I see -d sectsize is in the --help screen but not the manpage.  Can we
> >> > fix that?
> >>
> >> I made it, but Dave would rather see the -d sectsize option removed.
> >> Which I'm not sure about...
> >> See "[PATCH] xfsprogs: add sectsize/sectlog to the man page"
> >
> > Slash and burn - there is so much useless, redundant crap in the CLI
> > we've been holding onto for 15 years that we should just get rid of
> > it. That's what I was intending to do originally with this rework
> > and I still see no reason why we should be keeping stuff that just
> > causes user confusion and implemention complexity.
> 
> I went through it and I admit that his shot seems to go in a much
> better way than my patches; I focused on the opts structure too much I
> guess. :-)

That's not your fault - if anyone is to blame it's me for not
providing you with better guidance in the first place.

> So, thanks for this restart. I'm going to compare it with
> my changes and check which parts of my set makes sense in this
> direction as well and which do not...

Having slept on it, I suspect that I'll generate an "input
parameters" structure to replace the hacked up "cli geometry",
similar to what Luis first wanted to add. If it works out the way I
think it will, we'll end up with a set of key,value inputs in that
structure that we can trivially generate using a config file rather
than the CLI....

> And this is maybe a bit premature idea now, but should we add some way
> how to tell the user "this option is deprecated, use XXX"? I think
> that it is a good idea if we are removing parts of the CLI, which
> might break some user scripts or workflow. It would be pretty easy to
> do - with something like your *_opts_parser() functions, just a case,
> print the error and return EINVAL.

Depends on how we decide to do the removal. If we go with
deprecation and later removal, then I think this is a good idea.

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

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

end of thread, other threads:[~2017-08-17 23:00 UTC | newest]

Thread overview: 37+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-08-11 12:30 [PATCH 0/6 v2] mkfs: save user input into opts table Jan Tulak
2017-08-11 12:30 ` [PATCH 1/6] mkfs: Save raw user input field to the opts struct Jan Tulak
2017-08-14 22:56   ` Darrick J. Wong
2017-08-15  9:47     ` Jan Tulak
2017-08-11 12:30 ` [PATCH 2/6] mkfs: rename defaultval to flagval in opts Jan Tulak
2017-08-14 22:56   ` Darrick J. Wong
2017-08-11 12:30 ` [PATCH 3/6] mkfs: remove intermediate getstr followed by getnum Jan Tulak
2017-08-14 22:58   ` Darrick J. Wong
2017-08-11 12:30 ` [PATCH 4/6] mkfs: merge tables for opts parsing into one table Jan Tulak
2017-08-14 23:06   ` Darrick J. Wong
2017-08-15 10:05     ` Jan Tulak
2017-08-11 12:30 ` [PATCH 5/6] mkfs: move getnum within the file Jan Tulak
2017-08-14 23:07   ` Darrick J. Wong
2017-08-15 10:14     ` Jan Tulak
2017-08-15 21:09       ` Eric Sandeen
2017-08-16  9:25         ` Jan Tulak
2017-08-11 12:30 ` [PATCH 6/6] mkfs: extend opt_params with a value field Jan Tulak
2017-08-14 23:15   ` Darrick J. Wong
2017-08-15 10:42     ` Jan Tulak
2017-08-15 15:08 ` [PATCH 1/6 v2] mkfs: Save raw user input field to the opts struct Jan Tulak
2017-08-15 15:08   ` [PATCH 3/6 v2] mkfs: remove intermediate getstr followed by getnum Jan Tulak
2017-08-15 23:20     ` Eric Sandeen
2017-08-17 11:36     ` Dave Chinner
2017-08-15 15:08   ` [PATCH 4/6 v2] mkfs: merge tables for opts parsing into one table Jan Tulak
2017-08-15 15:08   ` [PATCH 5/6 v2] mkfs: move getnum within the file Jan Tulak
2017-08-15 15:08   ` [PATCH 6/6 v2] mkfs: extend opt_params with a value field Jan Tulak
2017-08-16 21:13     ` Eric Sandeen
2017-08-16 21:38       ` Darrick J. Wong
2017-08-17 10:08         ` Jan Tulak
2017-08-17 11:03           ` Dave Chinner
2017-08-17 14:56             ` Jan Tulak
2017-08-17 22:59               ` Dave Chinner
2017-08-17 15:26           ` Eric Sandeen
2017-08-15 23:07   ` [PATCH 1/6 v2] mkfs: Save raw user input field to the opts struct Eric Sandeen
2017-08-16  9:11     ` Jan Tulak
2017-08-16 14:42       ` Eric Sandeen
2017-08-16 15:38         ` Jan Tulak

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.