* [RFC PATCH] mkfs: allow specification of default options via configuration file
@ 2026-05-14 15:06 Darrick J. Wong
0 siblings, 0 replies; only message 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] only message in thread
only message in thread, other threads:[~2026-05-14 15:06 UTC | newest]
Thread overview: (only message) (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
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox