From: "Darrick J. Wong" <djwong@kernel.org>
To: Lukas Herbolt <lukas@herbolt.com>
Cc: sandeen@sandeen.net, aalbersh@kernel.org,
linux-xfs@vger.kernel.org, Theodore Ts'o <tytso@mit.edu>
Subject: [RFC PATCH] mkfs: allow specification of default options via configuration file
Date: Thu, 14 May 2026 08:06:53 -0700 [thread overview]
Message-ID: <20260514150653.GW9555@frogsfrogsfrogs> (raw)
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))
reply other threads:[~2026-05-14 15:06 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260514150653.GW9555@frogsfrogsfrogs \
--to=djwong@kernel.org \
--cc=aalbersh@kernel.org \
--cc=linux-xfs@vger.kernel.org \
--cc=lukas@herbolt.com \
--cc=sandeen@sandeen.net \
--cc=tytso@mit.edu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox