* [RFC PATCH] mkfs: allow specification of default options via configuration file
@ 2026-05-14 15:06 Darrick J. Wong
2026-05-19 8:43 ` Christoph Hellwig
0 siblings, 1 reply; 3+ messages in thread
From: Darrick J. Wong @ 2026-05-14 15:06 UTC (permalink / raw)
To: Lukas Herbolt; +Cc: sandeen, aalbersh, linux-xfs, Theodore Ts'o
From: Darrick J. Wong <djwong@kernel.org>
Ted asked for the ability to set default mkfs options, but to retain the
ability respecify options via a separate configuration file or cli
options. This would be useful for running fstests with the default
featureset of (say) Linux 5.15 LTS, while still allowing individual
testcases to provide their own overrides. It's certainly less messy
than what Ted does today, which is a bash script that copies the desired
config file and changes things.
Cc: tytso@mit.edu
Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
---
man/man8/mkfs.xfs.8.in | 16 ++++-
mkfs/xfs_mkfs.c | 159 ++++++++++++++++++++++++++++++++++++++++++------
2 files changed, 152 insertions(+), 23 deletions(-)
diff --git a/man/man8/mkfs.xfs.8.in b/man/man8/mkfs.xfs.8.in
index fbafc5c79e02de..a564e6c2b15210 100644
--- a/man/man8/mkfs.xfs.8.in
+++ b/man/man8/mkfs.xfs.8.in
@@ -152,10 +152,22 @@ .SH OPTIONS
.BI \-c " configuration_file_option"
This option specifies the files that mkfs configuration will be obtained from.
The valid
-.I configuration_file_option
-is:
+.I configuration_file_options
+are:
.RS 1.2i
.TP
+.BI defaults= name
+Default configuration options will be sourced from the file specified by the
+.I name
+option string.
+This option can be use either an absolute or relative path to the configuration
+file to be read.
+Sample configuration files can be found in @mkfs_cfg_dir@.
+Options specified through the default configuration file can be overridden by
+a configuration file specified via
+.B options=
+or command line arguments, in that order.
+.TP
.BI options= name
The configuration options will be sourced from the file specified by the
.I name
diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
index dd8a48c3633ef0..a3973c5aa1e3f0 100644
--- a/mkfs/xfs_mkfs.c
+++ b/mkfs/xfs_mkfs.c
@@ -62,6 +62,7 @@ enum {
enum {
C_OPTFILE = 0,
+ C_DEFOPTFILE,
C_MAX_OPTS,
};
@@ -313,6 +314,7 @@ static struct opt_params copts = {
.name = 'c',
.subopts = {
[C_OPTFILE] = "options",
+ [C_DEFOPTFILE] = "defaults",
[C_MAX_OPTS] = NULL,
},
.subopt_params = {
@@ -320,6 +322,10 @@ static struct opt_params copts = {
.conflicts = { { NULL, LAST_CONFLICT } },
.defaultval = SUBOPT_NEEDS_VAL,
},
+ { .index = C_DEFOPTFILE,
+ .conflicts = { { NULL, LAST_CONFLICT } },
+ .defaultval = SUBOPT_NEEDS_VAL,
+ },
},
};
@@ -1072,6 +1078,7 @@ struct cli_params {
int blocksize;
char *cfgfile;
+ char *defcfgfile;
char *protofile;
enum fsprop_autofsck autofsck;
@@ -1208,7 +1215,7 @@ usage( void )
{
fprintf(stderr, _("Usage: %s\n\
/* blocksize */ [-b size=num]\n\
-/* config file */ [-c options=xxx]\n\
+/* config file */ [-c defaults=xxx,options=xxx]\n\
/* metadata */ [-m crc=0|1,finobt=0|1,uuid=xxx,rmapbt=0|1,reflink=0|1,\n\
inobtcount=0|1,bigtime=0|1,autofsck=xxx,\n\
metadir=0|1]\n\
@@ -1788,6 +1795,29 @@ cfgfile_opts_parser(
case C_OPTFILE:
cli->cfgfile = getstr(value, opts, subopt);
break;
+ case C_DEFOPTFILE:
+ /* already processed by defcfgfile_opts_parser; ignored */
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int
+defcfgfile_opts_parser(
+ struct opt_params *opts,
+ int subopt,
+ const char *value,
+ struct cli_params *cli)
+{
+ switch (subopt) {
+ case C_OPTFILE:
+ /* will be processed by cfgfile_opts_parser; ignored */
+ break;
+ case C_DEFOPTFILE:
+ cli->defcfgfile = getstr(value, opts, subopt);
+ break;
default:
return -EINVAL;
}
@@ -2254,13 +2284,15 @@ sector_opts_parser(
return 0;
}
-static struct subopts {
+struct subopts {
struct opt_params *opts;
int (*parser)(struct opt_params *opts,
int subopt,
const char *value,
struct cli_params *cli);
-} subopt_tab[] = {
+};
+
+static const struct subopts subopt_tab[] = {
{ &bopts, block_opts_parser },
{ &copts, cfgfile_opts_parser },
{ &dopts, data_opts_parser },
@@ -2274,15 +2306,21 @@ static struct subopts {
{ NULL, NULL },
};
+static const struct subopts defcfg_subopt_tab[] = {
+ { &copts, defcfgfile_opts_parser },
+ { NULL, NULL },
+};
+
static void
parse_subopts(
- char opt,
- char *arg,
- struct cli_params *cli)
+ char opt,
+ char *arg,
+ const struct subopts *stab,
+ struct cli_params *cli)
{
- struct subopts *sop = &subopt_tab[0];
- char *p;
- int ret = 0;
+ const struct subopts *sop = stab;
+ char *p, *duparg;
+ int ret = 0;
while (sop->opts) {
if (sop->opts->name == opt)
@@ -2294,7 +2332,8 @@ parse_subopts(
if (!sop->opts)
return;
- p = arg;
+ /* getsubopt modifies duparg */
+ p = duparg = strdup(arg);
while (*p != '\0') {
char **subopts = (char **)sop->opts->subopts;
char *value;
@@ -2306,19 +2345,20 @@ parse_subopts(
if (ret)
unknown(opt, value);
}
+ free(duparg);
}
static bool
parse_cfgopt(
- const char *section,
- const char *name,
- const char *value,
- struct cli_params *cli)
+ const char *section,
+ const char *name,
+ const char *value,
+ struct cli_params *cli)
{
- struct subopts *sop = &subopt_tab[0];
- char **subopts;
- int ret = 0;
- int i;
+ const struct subopts *sop = &subopt_tab[0];
+ char **subopts;
+ int ret = 0;
+ int i;
while (sop->opts) {
if (sop->opts->ini_section[0] != '\0' &&
@@ -5777,6 +5817,64 @@ cfgfile_parse(
cli->cfgfile);
}
+static void
+reset_seen(
+ struct opt_params *opts)
+{
+ unsigned int i;
+
+ for (i = 0; i < MAX_SUBOPTS; i++) {
+ opts->subopt_params[i].seen = false;
+ opts->subopt_params[i].str_seen = false;
+ }
+}
+
+static void
+defcfgfile_parse(
+ struct cli_params *cli)
+{
+ int error;
+
+ if (!cli->defcfgfile)
+ return;
+
+ error = ini_parse(cli->defcfgfile, cfgfile_parse_ini, cli);
+ if (error) {
+ if (error > 0) {
+ fprintf(stderr,
+ _("%s: Unrecognised input on line %d. Aborting.\n"),
+ cli->defcfgfile, error);
+ } else if (error == -1) {
+ fprintf(stderr,
+ _("Unable to open defaults config file %s. Aborting.\n"),
+ cli->defcfgfile);
+ } else if (error == -2) {
+ fprintf(stderr,
+ _("Memory allocation failure parsing %s. Aborting.\n"),
+ cli->defcfgfile);
+ } else {
+ fprintf(stderr,
+ _("Unknown error %d opening defaults config file %s. Aborting.\n"),
+ error, cli->defcfgfile);
+ }
+ exit(1);
+ }
+ printf(_("Parameters parsed from defaults config file %s successfully\n"),
+ cli->defcfgfile);
+
+ /* Now make it look like we haven't seen any cli options. */
+ reset_seen(&bopts);
+ reset_seen(&copts);
+ reset_seen(&dopts);
+ reset_seen(&iopts);
+ reset_seen(&lopts);
+ reset_seen(&mopts);
+ reset_seen(&nopts);
+ reset_seen(&popts);
+ reset_seen(&ropts);
+ reset_seen(&sopts);
+}
+
static void
set_autofsck(
struct xfs_mount *mp,
@@ -5926,6 +6024,17 @@ check_rt_meta_prealloc(
mp->m_finobt_nores = false;
}
+static inline int
+getopt_mkfs(
+ int argc,
+ char *const argv[],
+ const struct option *longopts,
+ int *longindex)
+{
+ return getopt_long(argc, argv, "b:c:d:i:l:L:m:n:KNp:qr:s:CfV",
+ longopts, longindex);
+}
+
int
main(
int argc,
@@ -6032,8 +6141,16 @@ main(
memcpy(&cli.sb_feat, &dft.sb_feat, sizeof(cli.sb_feat));
memcpy(&cli.fsx, &dft.fsx, sizeof(cli.fsx));
- while ((c = getopt_long(argc, argv, "b:c:d:i:l:L:m:n:KNp:qr:s:CfV",
- long_options, &option_index)) != EOF) {
+ /* Load default configuration, if specified */
+ while ((c = getopt_mkfs(argc, argv, long_options, &option_index)) != EOF) {
+ if (c == 'c') {
+ parse_subopts(c, optarg, defcfg_subopt_tab, &cli);
+ }
+ }
+ defcfgfile_parse(&cli);
+ optind = 1;
+
+ while ((c = getopt_mkfs(argc, argv, long_options, &option_index)) != EOF) {
switch (c) {
case 0:
break;
@@ -6051,7 +6168,7 @@ main(
case 'p':
case 'r':
case 's':
- parse_subopts(c, optarg, &cli);
+ parse_subopts(c, optarg, subopt_tab, &cli);
break;
case 'L':
if (strlen(optarg) > sizeof(sbp->sb_fname))
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [RFC PATCH] mkfs: allow specification of default options via configuration file
2026-05-14 15:06 [RFC PATCH] mkfs: allow specification of default options via configuration file Darrick J. Wong
@ 2026-05-19 8:43 ` Christoph Hellwig
2026-05-19 14:10 ` Darrick J. Wong
0 siblings, 1 reply; 3+ messages in thread
From: Christoph Hellwig @ 2026-05-19 8:43 UTC (permalink / raw)
To: Darrick J. Wong
Cc: Lukas Herbolt, sandeen, aalbersh, linux-xfs, Theodore Ts'o
On Thu, May 14, 2026 at 08:06:53AM -0700, Darrick J. Wong wrote:
> From: Darrick J. Wong <djwong@kernel.org>
>
> Ted asked for the ability to set default mkfs options, but to retain the
> ability respecify options via a separate configuration file or cli
> options. This would be useful for running fstests with the default
> featureset of (say) Linux 5.15 LTS, while still allowing individual
> testcases to provide their own overrides. It's certainly less messy
> than what Ted does today, which is a bash script that copies the desired
> config file and changes things.
Looks reasonable, do you have a test for it as well?
> +static inline int
> +getopt_mkfs(
I don't think there's much of a point in the inline here.
> + int argc,
> + char *const argv[],
> + const struct option *longopts,
> + int *longindex)
> +{
> + return getopt_long(argc, argv, "b:c:d:i:l:L:m:n:KNp:qr:s:CfV",
> + longopts, longindex);
> +}
Why does this hardcode the short options, but requires the caller to
pass in the long options (which are the same for both callers)?
> + while ((c = getopt_mkfs(argc, argv, long_options, &option_index)) != EOF) {
Killing the long_opts would also avoid the overly long line here and in
the other call site.
> + if (c == 'c') {
> + parse_subopts(c, optarg, defcfg_subopt_tab, &cli);
> + }
Spurious braces.
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [RFC PATCH] mkfs: allow specification of default options via configuration file
2026-05-19 8:43 ` Christoph Hellwig
@ 2026-05-19 14:10 ` Darrick J. Wong
0 siblings, 0 replies; 3+ messages in thread
From: Darrick J. Wong @ 2026-05-19 14:10 UTC (permalink / raw)
To: Christoph Hellwig
Cc: Lukas Herbolt, sandeen, aalbersh, linux-xfs, Theodore Ts'o
On Tue, May 19, 2026 at 01:43:28AM -0700, Christoph Hellwig wrote:
> On Thu, May 14, 2026 at 08:06:53AM -0700, Darrick J. Wong wrote:
> > From: Darrick J. Wong <djwong@kernel.org>
> >
> > Ted asked for the ability to set default mkfs options, but to retain the
> > ability respecify options via a separate configuration file or cli
> > options. This would be useful for running fstests with the default
> > featureset of (say) Linux 5.15 LTS, while still allowing individual
> > testcases to provide their own overrides. It's certainly less messy
> > than what Ted does today, which is a bash script that copies the desired
> > config file and changes things.
>
> Looks reasonable, do you have a test for it as well?
Somewhere, yeah :)
> > +static inline int
> > +getopt_mkfs(
>
> I don't think there's much of a point in the inline here.
>
> > + int argc,
> > + char *const argv[],
> > + const struct option *longopts,
> > + int *longindex)
> > +{
> > + return getopt_long(argc, argv, "b:c:d:i:l:L:m:n:KNp:qr:s:CfV",
> > + longopts, longindex);
> > +}
>
> Why does this hardcode the short options, but requires the caller to
> pass in the long options (which are the same for both callers)?
long_options is a local variable which contains a pointer into cli,
which is another local variable in main().
I could have made a fugly macro with implicit variable access, but that
was yuck.
> > + while ((c = getopt_mkfs(argc, argv, long_options, &option_index)) != EOF) {
>
> Killing the long_opts would also avoid the overly long line here and in
> the other call site.
I could just shorten it to "lopts" or something.
> > + if (c == 'c') {
> > + parse_subopts(c, optarg, defcfg_subopt_tab, &cli);
> > + }
>
> Spurious braces.
Will fix.
--D
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-05-19 14:10 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-14 15:06 [RFC PATCH] mkfs: allow specification of default options via configuration file Darrick J. Wong
2026-05-19 8:43 ` Christoph Hellwig
2026-05-19 14:10 ` Darrick J. Wong
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox