* [PATCH 1/9] mkfs: automatically upgrade autofsck earlier
2026-09-09 6:00 [PATCHSET v3] xfsprogs: generate mkfs.xfs config files Darrick J. Wong
@ 2026-09-09 6:00 ` Darrick J. Wong
2026-09-11 15:12 ` Christoph Hellwig
2026-09-09 6:00 ` [PATCH 2/9] mkfs: print config file for a given mkfs configuration Darrick J. Wong
` (7 subsequent siblings)
8 siblings, 1 reply; 32+ messages in thread
From: Darrick J. Wong @ 2026-09-09 6:00 UTC (permalink / raw)
To: djwong, aalbersh; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Move this chunk of code earlier in mkfs.xfs because a subsequent patch
will need the final value of cli.autofsck at the point where we do the
dry run reporting stuff. Nobody changes cli.autofsck after
validate_sb_features().
Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
Reviewed-by: Andrey Albershteyn <aalbersh@kernel.org>
---
mkfs/xfs_mkfs.c | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
index 4f11c9de339c2a..56e6f892e455dc 100644
--- a/mkfs/xfs_mkfs.c
+++ b/mkfs/xfs_mkfs.c
@@ -6123,6 +6123,15 @@ main(
validate_zoned(&cfg, &cli, &dft, &zt);
validate_sb_features(&cfg, &cli);
+ /*
+ * If the filesystem has full backreferences and the user didn't
+ * express an autofsck preference, enable online repair because they
+ * might as well get some useful functionality from the extra metadata.
+ */
+ if (cli.autofsck == FSPROP_AUTOFSCK_UNSET &&
+ cli.sb_feat.rmapbt && cli.sb_feat.parent_pointers)
+ cli.autofsck = FSPROP_AUTOFSCK_REPAIR;
+
/*
* we've now completed basic validation of the features, sector and
* block sizes, so from this point onwards we use the values found in
@@ -6314,15 +6323,6 @@ main(
if (mp->m_sb.sb_agcount > 1)
rewrite_secondary_superblocks(mp);
- /*
- * If the filesystem has full backreferences and the user didn't
- * express an autofsck preference, enable online repair because they
- * might as well get some useful functionality from the extra metadata.
- */
- if (cli.autofsck == FSPROP_AUTOFSCK_UNSET &&
- cli.sb_feat.rmapbt && cli.sb_feat.parent_pointers)
- cli.autofsck = FSPROP_AUTOFSCK_REPAIR;
-
if (cli.autofsck != FSPROP_AUTOFSCK_UNSET)
set_autofsck(mp, &cli);
^ permalink raw reply related [flat|nested] 32+ messages in thread* [PATCH 2/9] mkfs: print config file for a given mkfs configuration
2026-09-09 6:00 [PATCHSET v3] xfsprogs: generate mkfs.xfs config files Darrick J. Wong
2026-09-09 6:00 ` [PATCH 1/9] mkfs: automatically upgrade autofsck earlier Darrick J. Wong
@ 2026-09-09 6:00 ` Darrick J. Wong
2026-09-11 15:14 ` Christoph Hellwig
2026-09-09 6:01 ` [PATCH 3/9] xfs_db: print configuration file for mounted filesystems Darrick J. Wong
` (6 subsequent siblings)
8 siblings, 1 reply; 32+ messages in thread
From: Darrick J. Wong @ 2026-09-09 6:00 UTC (permalink / raw)
To: djwong, aalbersh; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Add a -c makecfg= switch to mkfs to emit a mkfs.xfs configuration file
documenting the user-visible filesystem featuresets of the configured
filesystem. This can be used to emit default configuration files as we
do once a year for each LTS.
Note that geometry information is not written to the configuration file.
Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
Reviewed-by: Andrey Albershteyn <aalbersh@kernel.org>
---
libfrog/fsgeom.h | 3
libfrog/fsgeom.c | 379 ++++++++++++++++++++++++++++++++++++++++++++++++
man/man8/mkfs.xfs.8.in | 7 +
mkfs/xfs_mkfs.c | 39 +++++
4 files changed, 427 insertions(+), 1 deletion(-)
diff --git a/libfrog/fsgeom.h b/libfrog/fsgeom.h
index b851b9bbf36a58..1109dd2bcdb4cc 100644
--- a/libfrog/fsgeom.h
+++ b/libfrog/fsgeom.h
@@ -217,4 +217,7 @@ bytes_per_rtgroup(
fsgeo->blocksize;
}
+int xfrog_write_mkfs_config(const struct xfs_fsop_geom *fsgeo,
+ const struct fsxattr *fsx, int autofsck, FILE *fp);
+
#endif /* __LIBFROG_FSGEOM_H__ */
diff --git a/libfrog/fsgeom.c b/libfrog/fsgeom.c
index 571d376c6b3c28..26d0870f5d0611 100644
--- a/libfrog/fsgeom.c
+++ b/libfrog/fsgeom.c
@@ -7,6 +7,10 @@
#include "bitops.h"
#include "fsgeom.h"
#include "util.h"
+#include "list.h"
+#include "libfrog/fsproperties.h"
+#include "xfs_arch.h"
+#include "libxfs/xfs_format.h"
static inline const char *
rtdev_name(
@@ -250,3 +254,378 @@ xfrog_rtgroup_geometry(
return -errno;
return 0;
}
+
+enum {
+ M_CRC = 0,
+ M_FINOBT,
+ M_RMAPBT,
+ M_REFLINK,
+ M_INOBTCNT,
+ M_BIGTIME,
+ M_METADIR,
+ M_AUTOFSCK,
+ M_MAX_OPTS,
+};
+
+enum {
+ D_RTINHERIT = 0,
+ D_PROJINHERIT,
+ D_EXTSZINHERIT,
+ D_COWEXTSIZE,
+ D_DAXINHERIT,
+ D_MAX_OPTS,
+};
+
+enum {
+ I_SPINODES = 0,
+ I_NREXT64,
+ I_EXCHANGE,
+ I_MAX_OPTS,
+};
+
+enum {
+ N_PARENT = 0,
+ N_FTYPE,
+ N_VERSION,
+ N_MAX_OPTS,
+};
+
+enum {
+ R_EXTSIZE = 0,
+ R_MAX_OPTS,
+};
+
+struct mkfs_config_opt;
+
+struct mkfs_config_data {
+ const struct xfs_fsop_geom *fsgeo;
+ const struct fsxattr *fsx;
+ enum fsprop_autofsck autofsck;
+};
+
+typedef int (*opt_print_fn)(const struct mkfs_config_opt *opt,
+ const struct mkfs_config_data *data,
+ FILE *fp);
+
+struct mkfs_config_opt {
+ const char *name;
+ uint64_t fsgeom_flag;
+ uint64_t xflags_flag;
+ opt_print_fn print_fn;
+};
+
+struct mkfs_config_section {
+ const char *ini_section;
+ struct mkfs_config_opt subopts[16];
+};
+
+static int
+print_fsgeom(
+ const struct mkfs_config_opt *opt,
+ const struct mkfs_config_data *data,
+ FILE *fp)
+{
+ const struct xfs_fsop_geom *fsgeo = data->fsgeo;
+ int ret;
+
+ ret = fprintf(fp, "%s=%d\n", opt->name,
+ !!(fsgeo->flags & opt->fsgeom_flag));
+ if (ret <= 0)
+ return ret;
+ return 0;
+}
+
+static int
+print_xflag(
+ const struct mkfs_config_opt *opt,
+ const struct mkfs_config_data *data,
+ FILE *fp)
+{
+ const struct fsxattr *fsx = data->fsx;
+ int ret;
+
+ if (!(fsx->fsx_xflags & opt->xflags_flag))
+ return 0;
+
+ ret = fprintf(fp, "%s=%d\n", opt->name, 1);
+ if (ret <= 0)
+ return ret;
+ return 0;
+}
+
+static int
+print_projinherit(
+ const struct mkfs_config_opt *opt,
+ const struct mkfs_config_data *data,
+ FILE *fp)
+{
+ const struct fsxattr *fsx = data->fsx;
+ int ret;
+
+ if (fsx->fsx_xflags & FS_XFLAG_PROJINHERIT) {
+ ret = fprintf(fp, "%s=%u\n", opt->name, fsx->fsx_projid);
+ if (ret <= 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+print_extszinherit(
+ const struct mkfs_config_opt *opt,
+ const struct mkfs_config_data *data,
+ FILE *fp)
+{
+ const struct fsxattr *fsx = data->fsx;
+ int ret;
+
+ if (fsx->fsx_xflags & FS_XFLAG_EXTSZINHERIT) {
+ ret = fprintf(fp, "%s=%u\n", opt->name, fsx->fsx_extsize);
+ if (ret <= 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+print_cowextszinherit(
+ const struct mkfs_config_opt *opt,
+ const struct mkfs_config_data *data,
+ FILE *fp)
+{
+ const struct fsxattr *fsx = data->fsx;
+ int ret;
+
+ if (fsx->fsx_xflags & FS_XFLAG_COWEXTSIZE) {
+ ret = fprintf(fp, "%s=%u\n", opt->name, fsx->fsx_cowextsize);
+ if (ret <= 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+print_rtextsize(
+ const struct mkfs_config_opt *opt,
+ const struct mkfs_config_data *data,
+ FILE *fp)
+{
+ const struct xfs_fsop_geom *fsgeo = data->fsgeo;
+ int ret;
+
+ /* No need to emit the rt extent size if it's the minimum */
+ if (fsgeo->rtextsize > (XFS_MIN_RTEXTSIZE / fsgeo->blocksize)) {
+ ret = fprintf(fp, "%s=%u\n", opt->name,
+ fsgeo->rtextsize * fsgeo->blocksize);
+ if (ret <= 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+print_dirversion(
+ const struct mkfs_config_opt *opt,
+ const struct mkfs_config_data *data,
+ FILE *fp)
+{
+ const struct xfs_fsop_geom *fsgeo = data->fsgeo;
+ int ret;
+
+ if (fsgeo->flags & XFS_FSOP_GEOM_FLAGS_DIRV2CI)
+ ret = fprintf(fp, "%s=ci\n", opt->name);
+ else
+ ret = fprintf(fp, "%s=2\n", opt->name);
+ if (ret <= 0)
+ return ret;
+ return 0;
+}
+
+static int
+print_autofsck(
+ const struct mkfs_config_opt *opt,
+ const struct mkfs_config_data *data,
+ FILE *fp)
+{
+ int ret;
+ const char *value =
+ fsprop_autofsck_write(data->autofsck);
+
+ if (value) {
+ ret = fprintf(fp, "%s=%s\n", opt->name, value);
+ if (ret <= 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct mkfs_config_section config_sections[] = {
+ {
+ .ini_section = "metadata",
+ .subopts = {
+ [M_CRC] = {
+ .name = "crc",
+ .fsgeom_flag = XFS_FSOP_GEOM_FLAGS_V5SB,
+ },
+ [M_FINOBT] = {
+ .name = "finobt",
+ .fsgeom_flag = XFS_FSOP_GEOM_FLAGS_FINOBT,
+ },
+ [M_RMAPBT] = {
+ .name = "rmapbt",
+ .fsgeom_flag = XFS_FSOP_GEOM_FLAGS_RMAPBT,
+ },
+ [M_REFLINK] = {
+ .name = "reflink",
+ .fsgeom_flag = XFS_FSOP_GEOM_FLAGS_REFLINK,
+ },
+ [M_INOBTCNT] = {
+ .name = "inobtcount",
+ .fsgeom_flag = XFS_FSOP_GEOM_FLAGS_INOBTCNT,
+ },
+ [M_BIGTIME] = {
+ .name = "bigtime",
+ .fsgeom_flag = XFS_FSOP_GEOM_FLAGS_BIGTIME,
+ },
+ [M_METADIR] = {
+ .name = "metadir",
+ .fsgeom_flag = XFS_FSOP_GEOM_FLAGS_METADIR,
+ },
+ [M_AUTOFSCK] = {
+ .name = "autofsck",
+ .print_fn = print_autofsck,
+ },
+ [M_MAX_OPTS] = { },
+ },
+ },
+ {
+ .ini_section = "data",
+ .subopts = {
+ [D_RTINHERIT] = {
+ .name = "rtinherit",
+ .xflags_flag = FS_XFLAG_RTINHERIT,
+ },
+ [D_PROJINHERIT] = {
+ .name = "projinherit",
+ .print_fn = print_projinherit,
+ },
+ [D_EXTSZINHERIT] = {
+ .name = "extszinherit",
+ .print_fn = print_extszinherit,
+ },
+ [D_COWEXTSIZE] = {
+ .name = "cowextsize",
+ .print_fn = print_cowextszinherit,
+ },
+ [D_DAXINHERIT] = {
+ .name = "daxinherit",
+ .xflags_flag = FS_XFLAG_DAX,
+ },
+ [D_MAX_OPTS] = { },
+ },
+ },
+ {
+ .ini_section = "inode",
+ .subopts = {
+ [I_SPINODES] = {
+ .name = "sparse",
+ .fsgeom_flag = XFS_FSOP_GEOM_FLAGS_SPINODES,
+ },
+ [I_NREXT64] = {
+ .name = "nrext64",
+ .fsgeom_flag = XFS_FSOP_GEOM_FLAGS_NREXT64,
+ },
+ [I_EXCHANGE] = {
+ .name = "exchange",
+ .fsgeom_flag = XFS_FSOP_GEOM_FLAGS_EXCHANGE_RANGE,
+ },
+ [I_MAX_OPTS] = { },
+ },
+ },
+ {
+ .ini_section = "naming",
+ .subopts = {
+ [N_PARENT] = {
+ .name = "parent",
+ .fsgeom_flag = XFS_FSOP_GEOM_FLAGS_PARENT,
+ },
+ [N_FTYPE] = {
+ .name = "ftype",
+ .fsgeom_flag = XFS_FSOP_GEOM_FLAGS_FTYPE,
+ },
+ [N_VERSION] = {
+ .name = "version",
+ .print_fn = print_dirversion,
+ },
+ },
+ },
+ {
+ .ini_section = "realtime",
+ .subopts = {
+ [R_EXTSIZE] = {
+ .name = "extsize",
+ .print_fn = print_rtextsize,
+ },
+ [R_MAX_OPTS] = { },
+ },
+ },
+};
+
+/*
+ * Write a mkfs.xfs configuration file for the user-visible filesystem features
+ * enabled in the corresponding fs geometry and root directory file attribute
+ * structures.
+ *
+ * Note: The regular and COW extent size hints must be in units of fsblocks,
+ * not bytes.
+ */
+int
+xfrog_write_mkfs_config(
+ const struct xfs_fsop_geom *fsgeo,
+ const struct fsxattr *fsx,
+ int autofsck,
+ FILE *fp)
+{
+ struct mkfs_config_data d = {
+ .fsgeo = fsgeo,
+ .fsx = fsx,
+ .autofsck = autofsck,
+ };
+ const struct mkfs_config_section *section = config_sections;
+ const struct mkfs_config_opt *opt;
+ int i, j;
+ int error;
+
+ for (i = 0; i < ARRAY_SIZE(config_sections); i++, section++) {
+ if (i > 0) {
+ error = fprintf(fp, "\n");
+ if (error <= 0)
+ return error;
+ }
+
+ error = fprintf(fp, "[%s]\n", section->ini_section);
+ if (error <= 0)
+ return error;
+
+ opt = section->subopts;
+ for (j = 0;
+ j < ARRAY_SIZE(section->subopts) && opt->name;
+ j++, opt++) {
+ if (opt->print_fn)
+ error = opt->print_fn(opt, &d, fp);
+ else if (opt->xflags_flag)
+ error = print_xflag(opt, &d, fp);
+ else if (opt->fsgeom_flag)
+ error = print_fsgeom(opt, &d, fp);
+ if (error)
+ return error;
+ }
+ }
+
+ return fflush(fp);
+}
diff --git a/man/man8/mkfs.xfs.8.in b/man/man8/mkfs.xfs.8.in
index c4dee4fe07ae83..fb62d579a26a2d 100644
--- a/man/man8/mkfs.xfs.8.in
+++ b/man/man8/mkfs.xfs.8.in
@@ -156,6 +156,13 @@ .SH OPTIONS
is:
.RS 1.2i
.TP
+.BI makecfg= path
+Write a configuration file to the file specified by the
+.I path
+option string.
+This file can be re-read by mkfs.xfs for a future filesystem format attempt.
+This file will contain only user-visible features.
+.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 56e6f892e455dc..47c18ecdfa2e3d 100644
--- a/mkfs/xfs_mkfs.c
+++ b/mkfs/xfs_mkfs.c
@@ -61,6 +61,7 @@ enum {
enum {
C_OPTFILE = 0,
+ C_MAKECFG,
C_MAX_OPTS,
};
@@ -312,6 +313,7 @@ static struct opt_params copts = {
.name = 'c',
.subopts = {
[C_OPTFILE] = "options",
+ [C_MAKECFG] = "makecfg",
[C_MAX_OPTS] = NULL,
},
.subopt_params = {
@@ -319,6 +321,10 @@ static struct opt_params copts = {
.conflicts = { { NULL, LAST_CONFLICT } },
.defaultval = SUBOPT_NEEDS_VAL,
},
+ { .index = C_MAKECFG,
+ .conflicts = { { NULL, LAST_CONFLICT } },
+ .defaultval = SUBOPT_NEEDS_VAL,
+ },
},
};
@@ -1072,6 +1078,7 @@ struct cli_params {
char *cfgfile;
char *protofile;
+ char *makecfg;
enum fsprop_autofsck autofsck;
@@ -1207,7 +1214,7 @@ usage( void )
{
fprintf(stderr, _("Usage: %s\n\
/* blocksize */ [-b size=num]\n\
-/* config file */ [-c options=xxx]\n\
+/* config file */ [-c options=path,makecfg=path\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\
@@ -1787,6 +1794,9 @@ cfgfile_opts_parser(
case C_OPTFILE:
cli->cfgfile = getstr(value, opts, subopt);
break;
+ case C_MAKECFG:
+ cli->makecfg = getstr(value, opts, subopt);
+ break;
default:
return -EINVAL;
}
@@ -6105,6 +6115,10 @@ main(
*/
cfgfile_parse(&cli);
+ /* Don't create anything if we're merely generating a config file */
+ if (cli.makecfg)
+ dry_run = 1;
+
/*
* Extract as much of the valid config as we can from the CLI input
* before opening the libxfs devices.
@@ -6214,6 +6228,29 @@ main(
validate_supported(mp, &cli);
+ if (cli.makecfg) {
+ struct xfs_fsop_geom geo;
+ FILE *fp;
+
+ fp = fopen(cli.makecfg, "w+");
+ if (!fp) {
+ perror(cli.makecfg);
+ exit(1);
+ }
+
+ libxfs_fs_geometry(mp, &geo, XFS_FS_GEOM_MAX_STRUCT_VER);
+ error = xfrog_write_mkfs_config(&geo, &cli.fsx, cli.autofsck,
+ fp);
+ if (!error)
+ error = fclose(fp);
+ if (error) {
+ perror(cli.makecfg);
+ exit(1);
+ }
+
+ exit(0);
+ }
+
/* Print the intended geometry of the fs. */
if (!quiet || dry_run) {
struct xfs_fsop_geom geo;
^ permalink raw reply related [flat|nested] 32+ messages in thread* Re: [PATCH 2/9] mkfs: print config file for a given mkfs configuration
2026-09-09 6:00 ` [PATCH 2/9] mkfs: print config file for a given mkfs configuration Darrick J. Wong
@ 2026-09-11 15:14 ` Christoph Hellwig
2026-09-11 16:08 ` Darrick J. Wong
0 siblings, 1 reply; 32+ messages in thread
From: Christoph Hellwig @ 2026-09-11 15:14 UTC (permalink / raw)
To: Darrick J. Wong; +Cc: aalbersh, linux-xfs
On Tue, Sep 08, 2026 at 11:00:46PM -0700, Darrick J. Wong wrote:
> From: Darrick J. Wong <djwong@kernel.org>
>
> Add a -c makecfg= switch to mkfs to emit a mkfs.xfs configuration file
> documenting the user-visible filesystem featuresets of the configured
featuresets sounds German :) Wouldn't english spelling split this
into two words?
> filesystem. This can be used to emit default configuration files as we
> do once a year for each LTS.
>
> Note that geometry information is not written to the configuration file.
I guess this is implied by "This file will contain only user-visible
features" but maybe the man page could state this just as explіctly?
Otherwise looks good:
Reviewed-by: Christoph Hellwig <hch@lst.de>
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 2/9] mkfs: print config file for a given mkfs configuration
2026-09-11 15:14 ` Christoph Hellwig
@ 2026-09-11 16:08 ` Darrick J. Wong
0 siblings, 0 replies; 32+ messages in thread
From: Darrick J. Wong @ 2026-09-11 16:08 UTC (permalink / raw)
To: Christoph Hellwig; +Cc: aalbersh, linux-xfs
On Fri, Sep 11, 2026 at 08:14:29AM -0700, Christoph Hellwig wrote:
> On Tue, Sep 08, 2026 at 11:00:46PM -0700, Darrick J. Wong wrote:
> > From: Darrick J. Wong <djwong@kernel.org>
> >
> > Add a -c makecfg= switch to mkfs to emit a mkfs.xfs configuration file
> > documenting the user-visible filesystem featuresets of the configured
>
> featuresets sounds German :) Wouldn't english spelling split this
> into two words?
Some English speakers do, some don't. I'll make that "feature sets".
> > filesystem. This can be used to emit default configuration files as we
> > do once a year for each LTS.
> >
> > Note that geometry information is not written to the configuration file.
>
> I guess this is implied by "This file will contain only user-visible
> features" but maybe the man page could state this just as explіctly?
<nod> I'll add "Filesystem geometry information is not written to the
configuration file." to the manpage.
> Otherwise looks good:
>
> Reviewed-by: Christoph Hellwig <hch@lst.de>
Thank you!
--D
^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH 3/9] xfs_db: print configuration file for mounted filesystems
2026-09-09 6:00 [PATCHSET v3] xfsprogs: generate mkfs.xfs config files Darrick J. Wong
2026-09-09 6:00 ` [PATCH 1/9] mkfs: automatically upgrade autofsck earlier Darrick J. Wong
2026-09-09 6:00 ` [PATCH 2/9] mkfs: print config file for a given mkfs configuration Darrick J. Wong
@ 2026-09-09 6:01 ` Darrick J. Wong
2026-09-11 15:14 ` Christoph Hellwig
2026-09-09 6:01 ` [PATCH 4/9] xfs_spaceman: " Darrick J. Wong
` (5 subsequent siblings)
8 siblings, 1 reply; 32+ messages in thread
From: Darrick J. Wong @ 2026-09-09 6:01 UTC (permalink / raw)
To: djwong, aalbersh; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Teach xfs_db to emit a mkfs.xfs config file for an unmounted filesystem.
This can be used to create a new filesystem based on an existing image.
Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
Reviewed-by: Andrey Albershteyn <aalbersh@kernel.org>
---
db/info.c | 200 +++++++++++++++++++++++++++++++++++++++++++++++++++++
man/man8/xfs_db.8 | 6 ++
2 files changed, 206 insertions(+)
diff --git a/db/info.c b/db/info.c
index 9c233c9c0e6602..939b359fd26677 100644
--- a/db/info.c
+++ b/db/info.c
@@ -9,6 +9,7 @@
#include "output.h"
#include "libfrog/fsgeom.h"
#include "libfrog/logging.h"
+#include "libfrog/fsproperties.h"
static void
info_help(void)
@@ -276,10 +277,209 @@ static const struct cmdinfo rgresv_cmd = {
.help = rgresv_help,
};
+static void
+makecfg_help(void)
+{
+ dbprintf(_(
+"\n"
+" Print a mkfs.xfs configuration file for user-visible filesystem features\n"
+" of the current filesystem. Geometry information are not printed.\n"
+"\n"
+));
+
+}
+static void
+fill_fsxattr(
+ struct xfs_inode *ip,
+ struct fsxattr *fa)
+{
+ struct xfs_mount *mp = ip->i_mount;
+ struct xfs_ifork *ifp = xfs_ifork_ptr(ip, XFS_DATA_FORK);
+
+ fa->fsx_xflags = xfs_ip2xflags(ip);
+
+ if (ip->i_diflags & XFS_DIFLAG_EXTSIZE) {
+ fa->fsx_extsize = ip->i_extsize;
+ } else if (ip->i_diflags & XFS_DIFLAG_EXTSZINHERIT) {
+ /*
+ * Don't let a misaligned extent size hint on a directory
+ * escape to userspace if it won't pass the setattr checks
+ * later.
+ */
+ if ((ip->i_diflags & XFS_DIFLAG_RTINHERIT) &&
+ xfs_extlen_to_rtxmod(mp, ip->i_extsize) > 0) {
+ fa->fsx_xflags &= ~(FS_XFLAG_EXTSIZE |
+ FS_XFLAG_EXTSZINHERIT);
+ fa->fsx_extsize = 0;
+ } else {
+ fa->fsx_extsize = ip->i_extsize;
+ }
+ }
+
+ if (ip->i_diflags2 & XFS_DIFLAG2_COWEXTSIZE) {
+ /*
+ * Don't let a misaligned CoW extent size hint on a directory
+ * escape to userspace if it won't pass the setattr checks
+ * later.
+ */
+ if ((ip->i_diflags & XFS_DIFLAG_RTINHERIT) &&
+ ip->i_cowextsize % mp->m_sb.sb_rextsize > 0) {
+ fa->fsx_xflags &= ~FS_XFLAG_COWEXTSIZE;
+ fa->fsx_cowextsize = 0;
+ } else {
+ fa->fsx_cowextsize = ip->i_cowextsize;
+ }
+ }
+
+ fa->fsx_projid = ip->i_projid;
+ if (ifp && !xfs_need_iread_extents(ifp))
+ fa->fsx_nextents = xfs_iext_count(ifp);
+ else
+ fa->fsx_nextents = xfs_ifork_nextents(ifp);
+}
+
+static int
+get_autofsck(
+ struct xfs_inode *ip,
+ enum fsprop_autofsck *autofsck)
+{
+ char value[FSPROP_MAX_VALUELEN + 1];
+ struct xfs_da_args args = {
+ .dp = ip,
+ .geo = mp->m_attr_geo,
+ .whichfork = XFS_ATTR_FORK,
+ .op_flags = XFS_DA_OP_OKNOENT,
+ .attr_filter = LIBXFS_ATTR_ROOT,
+ .owner = mp->m_sb.sb_rootino,
+ .value = value,
+ .valuelen = sizeof(value),
+ };
+ char *p;
+ int error;
+
+ *autofsck = FSPROP_AUTOFSCK_UNSET;
+
+ error = fsprop_name_to_attr_name(FSPROP_AUTOFSCK_NAME, &p);
+ if (error < 0)
+ return ENOMEM;
+
+ args.namelen = error;
+ args.name = (const uint8_t *)p;
+
+ libxfs_attr_sethash(&args);
+
+ error = -libxfs_attr_get(&args);
+ if (error == ENODATA) {
+ error = 0;
+ goto out_p;
+ }
+ if (error || !args.valuelen)
+ goto out_p;
+
+ /* raw xattr value is not terminated */
+ value[args.valuelen] = 0;
+ *autofsck = fsprop_autofsck_read(value);
+
+out_p:
+ free(p);
+ return error;
+}
+
+static int
+makecfg_f(
+ int argc,
+ char **argv)
+{
+ struct xfs_fsop_geom geo;
+ struct fsxattr fsx = { };
+ struct xfs_inode *ip;
+ FILE *fp;
+ bool close_fp = false;
+ enum fsprop_autofsck autofsck;
+ int c;
+ int error;
+
+ while ((c = getopt(argc, argv, "")) != EOF) {
+ switch (c) {
+ default:
+ dbprintf(_("bad option for makecfg command\n"));
+ return 0;
+ }
+ }
+
+ if (optind != argc && optind != argc - 1) {
+ dbprintf(_("bad option for makecfg command\n"));
+ return 0;
+ }
+
+ error = -libxfs_iget(mp, NULL, mp->m_sb.sb_rootino, 0, &ip);
+ if (error) {
+ fprintf(stderr, "root: %s\n", strerror(error));
+ return 1;
+ }
+
+ error = get_autofsck(ip, &autofsck);
+ if (error) {
+ fprintf(stderr, "autofsck: %s\n", strerror(error));
+ error = 1;
+ goto out_ip;
+ }
+
+ fill_fsxattr(ip, &fsx);
+ libxfs_fs_geometry(mp, &geo, XFS_FS_GEOM_MAX_STRUCT_VER);
+
+ if (optind == argc) {
+ fp = stdout;
+ } else {
+ fp = fopen(argv[optind], "w");
+ if (!fp) {
+ perror(argv[optind]);
+ error = 1;
+ goto out_ip;
+ }
+ close_fp = true;
+ }
+
+ error = xfrog_write_mkfs_config(&geo, &fsx, autofsck, fp);
+ if (error) {
+ if (close_fp)
+ perror(argv[optind]);
+ else
+ perror("makecfg");
+ /* fall through to close fp */
+ }
+
+ if (close_fp) {
+ int err2 = fclose(fp);
+
+ if (err2) {
+ perror(argv[optind]);
+ if (!error)
+ error = err2;
+ }
+ }
+
+out_ip:
+ libxfs_irele(ip);
+ return error;
+}
+
+static const struct cmdinfo makecfg_cmd = {
+ .name = "makecfg",
+ .cfunc = makecfg_f,
+ .argmin = 0,
+ .argmax = 1,
+ .canpush = 0,
+ .args = NULL,
+ .oneline = N_("print mkfs.xfs configuration file"),
+ .help = makecfg_help,
+};
+
void
info_init(void)
{
add_command(&info_cmd);
add_command(&agresv_cmd);
add_command(&rgresv_cmd);
+ add_command(&makecfg_cmd);
}
diff --git a/man/man8/xfs_db.8 b/man/man8/xfs_db.8
index 89db535d38c9d4..6cfe9f6b06bde3 100644
--- a/man/man8/xfs_db.8
+++ b/man/man8/xfs_db.8
@@ -969,6 +969,12 @@ .SH COMMANDS
.BI "help [" command ]
Print help for one or all commands.
.TP
+.BI "makecfg [" path ]
+Write a configuration file to the given path that can be re-read by mkfs.xfs
+for a future filesystem format attempt.
+This file will contain only user-visible features.
+If no path is given, the configuration will be printed on standard output.
+.TP
.B info
Displays selected geometry information about the filesystem.
The output will have the same format that
^ permalink raw reply related [flat|nested] 32+ messages in thread* [PATCH 4/9] xfs_spaceman: print configuration file for mounted filesystems
2026-09-09 6:00 [PATCHSET v3] xfsprogs: generate mkfs.xfs config files Darrick J. Wong
` (2 preceding siblings ...)
2026-09-09 6:01 ` [PATCH 3/9] xfs_db: print configuration file for mounted filesystems Darrick J. Wong
@ 2026-09-09 6:01 ` Darrick J. Wong
2026-09-11 15:15 ` Christoph Hellwig
2026-09-09 6:01 ` [PATCH 5/9] makecfg: handle metadir quota options Darrick J. Wong
` (4 subsequent siblings)
8 siblings, 1 reply; 32+ messages in thread
From: Darrick J. Wong @ 2026-09-09 6:01 UTC (permalink / raw)
To: djwong, aalbersh; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Teach xfs_spaceman to emit a mkfs.xfs config file for a mounted
filesystem.
Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
Reviewed-by: Andrey Albershteyn <aalbersh@kernel.org>
---
man/man8/xfs_spaceman.8 | 6 ++
spaceman/info.c | 145 +++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 151 insertions(+)
diff --git a/man/man8/xfs_spaceman.8 b/man/man8/xfs_spaceman.8
index 7d2d1ff94eeb55..26ff35ab59f2ec 100644
--- a/man/man8/xfs_spaceman.8
+++ b/man/man8/xfs_spaceman.8
@@ -84,6 +84,12 @@ .SH COMMANDS
.PD
.RE
.TP
+.BI "makecfg [" path ]
+Write a configuration file to the given path that can be re-read by mkfs.xfs
+for a future filesystem format attempt.
+This file will contain only user-visible features.
+If no path is given, the configuration will be printed on standard output.
+.TP
.B info
Displays selected geometry information about the filesystem.
The opened file must be a mount point of a XFS filesystem.
diff --git a/spaceman/info.c b/spaceman/info.c
index f6234c4c67aa19..1ff8bc4fc2915f 100644
--- a/spaceman/info.c
+++ b/spaceman/info.c
@@ -8,6 +8,8 @@
#include "init.h"
#include "libfrog/paths.h"
#include "libfrog/fsgeom.h"
+#include "libfrog/fsproperties.h"
+#include "libfrog/fsprops.h"
#include "space.h"
static void
@@ -51,8 +53,151 @@ static const struct cmdinfo info_cmd = {
.help = info_help,
};
+static void
+makecfg_help(void)
+{
+ printf(_(
+"\n"
+" Print a mkfs.xfs configuration file for user-visible filesystem features\n"
+" of the current filesystem. Geometry information are not printed.\n"
+"\n"
+));
+
+}
+
+static int
+get_autofsck(
+ struct fileio *f,
+ enum fsprop_autofsck *autofsck)
+{
+ struct fsprops_handle fph = { };
+ char valuebuf[FSPROP_MAX_VALUELEN + 1] = { 0 };
+ size_t valuelen = FSPROP_MAX_VALUELEN;
+ int ret;
+
+ *autofsck = FSPROP_AUTOFSCK_UNSET;
+
+ ret = fsprops_open_handle(&f->xfd, &f->fs_path, &fph);
+ if (ret == -1 && errno == EOPNOTSUPP)
+ return 0;
+ if (ret)
+ return ret;
+
+ ret = fsprops_get(&fph, FSPROP_AUTOFSCK_NAME, valuebuf, &valuelen);
+ if (ret == -1 && errno == ENODATA) {
+ ret = 0;
+ goto out_fph;
+ }
+ if (ret)
+ goto out_fph;
+
+ *autofsck = fsprop_autofsck_read(valuebuf);
+
+out_fph:
+ fsprops_free_handle(&fph);
+ return ret;
+}
+
+static int makecfg_usage(void);
+
+static int
+makecfg_f(
+ int argc,
+ char **argv)
+{
+ struct fsxattr fsx = { };
+ FILE *fp;
+ bool close_fp = false;
+ enum fsprop_autofsck autofsck;
+ int c;
+ int ret;
+
+ while ((c = getopt(argc, argv, "")) != EOF) {
+ switch (c) {
+ default:
+ fprintf(stderr, _("bad option for makecfg command\n"));
+ return makecfg_usage();
+ }
+ }
+
+ if (optind != argc && optind != argc - 1) {
+ fprintf(stderr, _("bad option for makecfg command\n"));
+ return makecfg_usage();
+ }
+
+ if (fs_table_lookup_mount(file->name) == NULL) {
+ fprintf(stderr, _("%s: Not a XFS mount point.\n"), file->name);
+ return 1;
+ }
+
+ /* ioctl reports bytes, not fsblocks */
+ ret = ioctl(file->xfd.fd, FS_IOC_FSGETXATTR, &fsx);
+ if (ret) {
+ perror(file->name);
+ return 1;
+ }
+ fsx.fsx_extsize /= file->xfd.fsgeom.blocksize;
+ fsx.fsx_cowextsize /= file->xfd.fsgeom.blocksize;
+
+ ret = get_autofsck(file, &autofsck);
+ if (ret) {
+ perror("autofsck");
+ return 1;
+ }
+
+ if (optind == argc) {
+ fp = stdout;
+ } else {
+ fp = fopen(argv[optind], "w");
+ if (!fp) {
+ perror(argv[optind]);
+ return 1;
+ }
+ close_fp = true;
+ }
+
+ ret = xfrog_write_mkfs_config(&file->xfd.fsgeom, &fsx, autofsck, fp);
+ if (ret) {
+ if (close_fp)
+ perror(argv[optind]);
+ else
+ perror("makecfg");
+ /* fall through to close fp */
+ }
+
+ if (close_fp) {
+ int ret2 = fclose(fp);
+
+ if (ret2) {
+ perror(argv[optind]);
+ if (!ret)
+ ret = ret2;
+ }
+ }
+
+ return ret;
+}
+
+static const struct cmdinfo makecfg_cmd = {
+ .name = "makecfg",
+ .cfunc = makecfg_f,
+ .argmin = 0,
+ .argmax = 1,
+ .canpush = 0,
+ .args = NULL,
+ .flags = CMD_FLAG_ONESHOT,
+ .oneline = N_("print mkfs.xfs configuration file"),
+ .help = makecfg_help,
+};
+
+static int makecfg_usage(void)
+{
+ return command_usage(&makecfg_cmd);
+}
+
void
info_init(void)
{
add_command(&info_cmd);
+ add_command(&makecfg_cmd);
}
^ permalink raw reply related [flat|nested] 32+ messages in thread* [PATCH 5/9] makecfg: handle metadir quota options
2026-09-09 6:00 [PATCHSET v3] xfsprogs: generate mkfs.xfs config files Darrick J. Wong
` (3 preceding siblings ...)
2026-09-09 6:01 ` [PATCH 4/9] xfs_spaceman: " Darrick J. Wong
@ 2026-09-09 6:01 ` Darrick J. Wong
2026-09-09 13:15 ` Andrey Albershteyn
2026-09-11 15:48 ` Christoph Hellwig
2026-09-09 6:01 ` [PATCH 6/9] makecfg: handle old V4 options that are almost always on by default Darrick J. Wong
` (3 subsequent siblings)
8 siblings, 2 replies; 32+ messages in thread
From: Darrick J. Wong @ 2026-09-09 6:01 UTC (permalink / raw)
To: djwong, aalbersh; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
A different LOLLM pointed out that the mkfs configuration file generator
should generate config file lines for the quota accounting/enforcement
mkfs options for metadir filesystems, because those quota flags persist
across mounts. Add the necessary pieces to do that.
Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
---
libfrog/fsgeom.h | 11 ++++++-
configure.ac | 1 +
db/info.c | 3 +-
include/builddefs.in | 1 +
libfrog/fsgeom.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++-
m4/package_libcdev.m4 | 19 ++++++++++++
mkfs/xfs_mkfs.c | 4 +--
spaceman/Makefile | 4 +++
spaceman/info.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++-
9 files changed, 191 insertions(+), 7 deletions(-)
diff --git a/libfrog/fsgeom.h b/libfrog/fsgeom.h
index 1109dd2bcdb4cc..c3d865f0783e52 100644
--- a/libfrog/fsgeom.h
+++ b/libfrog/fsgeom.h
@@ -217,7 +217,16 @@ bytes_per_rtgroup(
fsgeo->blocksize;
}
+/* These should correspond to XFS_[UGP]UOTA_{ACCT,ENFD} */
+#define MAKECFG_UQUOTA_ACCT 0x0001 /* user quota accounting ON */
+#define MAKECFG_UQUOTA_ENFD 0x0002 /* user quota limits enforced */
+#define MAKECFG_GQUOTA_ACCT 0x0040 /* group quota accounting ON */
+#define MAKECFG_GQUOTA_ENFD 0x0080 /* group quota limits enforced */
+#define MAKECFG_PQUOTA_ACCT 0x0008 /* project quota accounting ON */
+#define MAKECFG_PQUOTA_ENFD 0x0200 /* project quota limits enforced */
+
int xfrog_write_mkfs_config(const struct xfs_fsop_geom *fsgeo,
- const struct fsxattr *fsx, int autofsck, FILE *fp);
+ unsigned int qflags, const struct fsxattr *fsx, int autofsck,
+ FILE *fp);
#endif /* __LIBFROG_FSGEOM_H__ */
diff --git a/configure.ac b/configure.ac
index 40ccd88aa2a950..8a2505e37c70ab 100644
--- a/configure.ac
+++ b/configure.ac
@@ -195,6 +195,7 @@ if test "$have_listmount" = "yes"; then
fi
AC_HAVE_STATMOUNT_SUPPORTED_MASK
AC_HAVE_FANOTIFY_MOUNTINFO
+AC_HAVE_QUOTACTL_FD
if test "$enable_ubsan" = "yes" || test "$enable_ubsan" = "probe"; then
AC_PACKAGE_CHECK_UBSAN
diff --git a/db/info.c b/db/info.c
index 939b359fd26677..9c081aa58208be 100644
--- a/db/info.c
+++ b/db/info.c
@@ -440,7 +440,8 @@ makecfg_f(
close_fp = true;
}
- error = xfrog_write_mkfs_config(&geo, &fsx, autofsck, fp);
+ error = xfrog_write_mkfs_config(&geo, mp->m_sb.sb_qflags, &fsx,
+ autofsck, fp);
if (error) {
if (close_fp)
perror(argv[optind]);
diff --git a/include/builddefs.in b/include/builddefs.in
index 3b52d1afd7031c..5d2e6c1b90ddbe 100644
--- a/include/builddefs.in
+++ b/include/builddefs.in
@@ -126,6 +126,7 @@ HAVE_LISTMOUNT_NS_FD = @have_listmount_ns_fd@
HAVE_STATMOUNT_SUPPORTED_MASK = @have_statmount_supported_mask@
NEED_INTERNAL_STATMOUNT = @need_internal_statmount@
HAVE_FANOTIFY_MOUNTINFO = @have_fanotify_mountinfo@
+HAVE_QUOTACTL_FD = @have_quotactl_fd@
GCCFLAGS = -funsigned-char -fno-strict-aliasing -Wall
# -Wbitwise -Wno-transparent-union -Wno-old-initializer -Wno-decl
diff --git a/libfrog/fsgeom.c b/libfrog/fsgeom.c
index 26d0870f5d0611..2172310aa102d6 100644
--- a/libfrog/fsgeom.c
+++ b/libfrog/fsgeom.c
@@ -264,6 +264,12 @@ enum {
M_BIGTIME,
M_METADIR,
M_AUTOFSCK,
+ M_UQUOTA,
+ M_GQUOTA,
+ M_PQUOTA,
+ M_UQNOENFORCE,
+ M_GQNOENFORCE,
+ M_PQNOENFORCE,
M_MAX_OPTS,
};
@@ -300,6 +306,7 @@ struct mkfs_config_opt;
struct mkfs_config_data {
const struct xfs_fsop_geom *fsgeo;
const struct fsxattr *fsx;
+ unsigned int qflags;
enum fsprop_autofsck autofsck;
};
@@ -309,9 +316,11 @@ typedef int (*opt_print_fn)(const struct mkfs_config_opt *opt,
struct mkfs_config_opt {
const char *name;
+ opt_print_fn print_fn;
uint64_t fsgeom_flag;
uint64_t xflags_flag;
- opt_print_fn print_fn;
+ unsigned int qflags_mask;
+ unsigned int qflags;
};
struct mkfs_config_section {
@@ -353,6 +362,26 @@ print_xflag(
return 0;
}
+static int
+print_metadir_qflags(
+ const struct mkfs_config_opt *opt,
+ const struct mkfs_config_data *data,
+ FILE *fp)
+{
+ int ret;
+
+ /* quota flags are only persisted on metadir filesystems */
+ if (!(data->fsgeo->flags & XFS_FSOP_GEOM_FLAGS_METADIR))
+ return 0;
+ if ((data->qflags & opt->qflags_mask) != opt->qflags)
+ return 0;
+
+ ret = fprintf(fp, "%s=1\n", opt->name);
+ if (ret <= 0)
+ return ret;
+ return 0;
+}
+
static int
print_projinherit(
const struct mkfs_config_opt *opt,
@@ -500,6 +529,51 @@ static const struct mkfs_config_section config_sections[] = {
.name = "autofsck",
.print_fn = print_autofsck,
},
+ [M_UQUOTA] = {
+ .name = "uquota",
+ .qflags = MAKECFG_UQUOTA_ACCT |
+ MAKECFG_UQUOTA_ENFD,
+ .qflags_mask = MAKECFG_UQUOTA_ACCT |
+ MAKECFG_UQUOTA_ENFD,
+ .print_fn = print_metadir_qflags,
+ },
+ [M_GQUOTA] = {
+ .name = "gquota",
+ .qflags = MAKECFG_GQUOTA_ACCT |
+ MAKECFG_GQUOTA_ENFD,
+ .qflags_mask = MAKECFG_GQUOTA_ACCT |
+ MAKECFG_GQUOTA_ENFD,
+ .print_fn = print_metadir_qflags,
+ },
+ [M_PQUOTA] = {
+ .name = "pquota",
+ .qflags = MAKECFG_PQUOTA_ACCT |
+ MAKECFG_PQUOTA_ENFD,
+ .qflags_mask = MAKECFG_PQUOTA_ACCT |
+ MAKECFG_PQUOTA_ENFD,
+ .print_fn = print_metadir_qflags,
+ },
+ [M_UQNOENFORCE] = {
+ .name = "uqnoenforce",
+ .qflags = MAKECFG_UQUOTA_ACCT,
+ .qflags_mask = MAKECFG_UQUOTA_ACCT |
+ MAKECFG_UQUOTA_ENFD,
+ .print_fn = print_metadir_qflags,
+ },
+ [M_GQNOENFORCE] = {
+ .name = "gqnoenforce",
+ .qflags = MAKECFG_GQUOTA_ACCT,
+ .qflags_mask = MAKECFG_GQUOTA_ACCT |
+ MAKECFG_GQUOTA_ENFD,
+ .print_fn = print_metadir_qflags,
+ },
+ [M_PQNOENFORCE] = {
+ .name = "pqnoenforce",
+ .qflags = MAKECFG_PQUOTA_ACCT,
+ .qflags_mask = MAKECFG_PQUOTA_ACCT |
+ MAKECFG_PQUOTA_ENFD,
+ .print_fn = print_metadir_qflags,
+ },
[M_MAX_OPTS] = { },
},
},
@@ -587,6 +661,7 @@ static const struct mkfs_config_section config_sections[] = {
int
xfrog_write_mkfs_config(
const struct xfs_fsop_geom *fsgeo,
+ unsigned int qflags,
const struct fsxattr *fsx,
int autofsck,
FILE *fp)
@@ -595,6 +670,7 @@ xfrog_write_mkfs_config(
.fsgeo = fsgeo,
.fsx = fsx,
.autofsck = autofsck,
+ .qflags = qflags,
};
const struct mkfs_config_section *section = config_sections;
const struct mkfs_config_opt *opt;
diff --git a/m4/package_libcdev.m4 b/m4/package_libcdev.m4
index 9586bc01fe0f25..5c1b6e4667d0ee 100644
--- a/m4/package_libcdev.m4
+++ b/m4/package_libcdev.m4
@@ -476,3 +476,22 @@ AC_DEFUN([AC_HAVE_FANOTIFY_MOUNTINFO],
AC_MSG_RESULT(no))
AC_SUBST(have_fanotify_mountinfo)
])
+
+#
+# Check if we have a quotactl_fd system call (5.14).
+#
+AC_DEFUN([AC_HAVE_QUOTACTL_FD],
+ [AC_MSG_CHECKING([for quotactl_fd])
+ AC_LINK_IFELSE(
+ [AC_LANG_PROGRAM([[
+#define _GNU_SOURCE
+#include <sys/syscall.h>
+#include <unistd.h>
+ ]], [[
+ return syscall(SYS_quotactl_fd);
+ ]])
+ ], have_quotactl_fd=yes
+ AC_MSG_RESULT(yes),
+ AC_MSG_RESULT(no))
+ AC_SUBST(have_quotactl_fd)
+ ])
diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
index 47c18ecdfa2e3d..38a5769188b05a 100644
--- a/mkfs/xfs_mkfs.c
+++ b/mkfs/xfs_mkfs.c
@@ -6239,8 +6239,8 @@ main(
}
libxfs_fs_geometry(mp, &geo, XFS_FS_GEOM_MAX_STRUCT_VER);
- error = xfrog_write_mkfs_config(&geo, &cli.fsx, cli.autofsck,
- fp);
+ error = xfrog_write_mkfs_config(&geo, cli.sb_feat.qflags,
+ &cli.fsx, cli.autofsck, fp);
if (!error)
error = fclose(fp);
if (error) {
diff --git a/spaceman/Makefile b/spaceman/Makefile
index 358db9edf5cb73..2e382177e9a8cb 100644
--- a/spaceman/Makefile
+++ b/spaceman/Makefile
@@ -30,6 +30,10 @@ ifeq ($(HAVE_GETFSMAP),yes)
CFILES += freesp.c
endif
+ifeq ($(HAVE_QUOTACTL_FD),yes)
+CFLAGS += -DHAVE_QUOTACTL_FD
+endif
+
default: depend $(LTCOMMAND)
include $(BUILDRULES)
diff --git a/spaceman/info.c b/spaceman/info.c
index 1ff8bc4fc2915f..b3596332ec1fb7 100644
--- a/spaceman/info.c
+++ b/spaceman/info.c
@@ -3,6 +3,7 @@
* Copyright (C) 2018 Oracle. All Rights Reserved.
* Author: Darrick J. Wong <darrick.wong@oracle.com>
*/
+#include <sys/quota.h>
#include "libxfs.h"
#include "command.h"
#include "init.h"
@@ -11,6 +12,7 @@
#include "libfrog/fsproperties.h"
#include "libfrog/fsprops.h"
#include "space.h"
+#include "include/xqm.h"
static void
info_help(void)
@@ -88,7 +90,7 @@ get_autofsck(
ret = 0;
goto out_fph;
}
- if (ret)
+ if (ret || !valuelen)
goto out_fph;
*autofsck = fsprop_autofsck_read(valuebuf);
@@ -98,6 +100,69 @@ get_autofsck(
return ret;
}
+struct qflags_xlate {
+ unsigned int qs_flag;
+ unsigned int mkcfg_qflag;
+};
+
+static const struct qflags_xlate qsflags_xlate[] = {
+ { .qs_flag = XFS_QUOTA_UDQ_ACCT, .mkcfg_qflag = MAKECFG_UQUOTA_ACCT },
+ { .qs_flag = XFS_QUOTA_UDQ_ENFD, .mkcfg_qflag = MAKECFG_UQUOTA_ENFD },
+ { .qs_flag = XFS_QUOTA_GDQ_ACCT, .mkcfg_qflag = MAKECFG_GQUOTA_ACCT },
+ { .qs_flag = XFS_QUOTA_GDQ_ENFD, .mkcfg_qflag = MAKECFG_GQUOTA_ENFD },
+ { .qs_flag = XFS_QUOTA_PDQ_ACCT, .mkcfg_qflag = MAKECFG_PQUOTA_ACCT },
+ { .qs_flag = XFS_QUOTA_PDQ_ENFD, .mkcfg_qflag = MAKECFG_PQUOTA_ENFD },
+};
+
+static inline int
+quotactl_fd(
+ int fd,
+ int op,
+ int id,
+ struct fs_quota_stat *qstat)
+{
+#ifdef HAVE_QUOTACTL_FD
+ return syscall(SYS_quotactl_fd, fd, op, id, qstat);
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+static int
+get_qflags(
+ struct fileio *f,
+ unsigned int *qflags)
+{
+ struct fs_quota_stat qstat;
+ int i;
+ int ret;
+
+ *qflags = 0;
+
+ /* XGETQSTAT returns qflags for all quota types, not just user */
+ ret = quotactl_fd(f->xfd.fd, QCMD(Q_XGETQSTAT, USRQUOTA), 0, &qstat);
+ if (ret == -1 && errno == ENOSYS)
+ ret = quotactl(QCMD(Q_XGETQSTAT, USRQUOTA), f->fs_path.fs_name,
+ 0, (void *)&qstat);
+ if (ret) {
+ /*
+ * ENOSYS means quota is not enabled or compiled in; ENODEV
+ * means that we couldn't find the filesystem in mtab (aka
+ * the filesystem has been moved).
+ */
+ if (errno == ENOSYS || errno == ENODEV)
+ return 0;
+ return ret;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(qsflags_xlate); i++)
+ if (qstat.qs_flags & qsflags_xlate[i].qs_flag)
+ *qflags |= qsflags_xlate[i].mkcfg_qflag;
+
+ return 0;
+}
+
static int makecfg_usage(void);
static int
@@ -109,6 +174,7 @@ makecfg_f(
FILE *fp;
bool close_fp = false;
enum fsprop_autofsck autofsck;
+ unsigned int qflags;
int c;
int ret;
@@ -145,6 +211,12 @@ makecfg_f(
return 1;
}
+ ret = get_qflags(file, &qflags);
+ if (ret) {
+ perror("quotactl");
+ return 1;
+ }
+
if (optind == argc) {
fp = stdout;
} else {
@@ -156,7 +228,8 @@ makecfg_f(
close_fp = true;
}
- ret = xfrog_write_mkfs_config(&file->xfd.fsgeom, &fsx, autofsck, fp);
+ ret = xfrog_write_mkfs_config(&file->xfd.fsgeom, qflags, &fsx,
+ autofsck, fp);
if (ret) {
if (close_fp)
perror(argv[optind]);
^ permalink raw reply related [flat|nested] 32+ messages in thread* Re: [PATCH 5/9] makecfg: handle metadir quota options
2026-09-09 6:01 ` [PATCH 5/9] makecfg: handle metadir quota options Darrick J. Wong
@ 2026-09-09 13:15 ` Andrey Albershteyn
2026-09-11 15:48 ` Christoph Hellwig
1 sibling, 0 replies; 32+ messages in thread
From: Andrey Albershteyn @ 2026-09-09 13:15 UTC (permalink / raw)
To: Darrick J. Wong; +Cc: linux-xfs
On 2026-09-08 23:01:33, Darrick J. Wong wrote:
> From: Darrick J. Wong <djwong@kernel.org>
>
> A different LOLLM pointed out that the mkfs configuration file generator
> should generate config file lines for the quota accounting/enforcement
> mkfs options for metadir filesystems, because those quota flags persist
> across mounts. Add the necessary pieces to do that.
>
> Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
Looks good to me
Reviewed-by: Andrey Albershteyn <aalbersh@kernel.org>
--
- Andrey
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 5/9] makecfg: handle metadir quota options
2026-09-09 6:01 ` [PATCH 5/9] makecfg: handle metadir quota options Darrick J. Wong
2026-09-09 13:15 ` Andrey Albershteyn
@ 2026-09-11 15:48 ` Christoph Hellwig
2026-09-11 17:58 ` Darrick J. Wong
1 sibling, 1 reply; 32+ messages in thread
From: Christoph Hellwig @ 2026-09-11 15:48 UTC (permalink / raw)
To: Darrick J. Wong; +Cc: aalbersh, linux-xfs
On Tue, Sep 08, 2026 at 11:01:33PM -0700, Darrick J. Wong wrote:
>
> +/* These should correspond to XFS_[UGP]UOTA_{ACCT,ENFD} */
CAn we reuse those? If not at least add the missing Q in QUOTA here :)
> diff --git a/configure.ac b/configure.ac
> index 40ccd88aa2a950..8a2505e37c70ab 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -195,6 +195,7 @@ if test "$have_listmount" = "yes"; then
> fi
> AC_HAVE_STATMOUNT_SUPPORTED_MASK
> AC_HAVE_FANOTIFY_MOUNTINFO
> +AC_HAVE_QUOTACTL_FD
Shouldn't the AC_HAVE_QUOTACTL_FD go into a separate patch, including
a generic helper? I assume most other uqotactl users would prefer
that as well when available.
Otherwise this looks good from a quick look.
^ permalink raw reply [flat|nested] 32+ messages in thread* Re: [PATCH 5/9] makecfg: handle metadir quota options
2026-09-11 15:48 ` Christoph Hellwig
@ 2026-09-11 17:58 ` Darrick J. Wong
0 siblings, 0 replies; 32+ messages in thread
From: Darrick J. Wong @ 2026-09-11 17:58 UTC (permalink / raw)
To: Christoph Hellwig; +Cc: aalbersh, linux-xfs
On Fri, Sep 11, 2026 at 08:48:36AM -0700, Christoph Hellwig wrote:
> On Tue, Sep 08, 2026 at 11:01:33PM -0700, Darrick J. Wong wrote:
> >
> > +/* These should correspond to XFS_[UGP]UOTA_{ACCT,ENFD} */
>
> CAn we reuse those? If not at least add the missing Q in QUOTA here :)
Oh! Yes, we can just reuse them since xfs_log_format.h is in
/usr/include/xfs/. Well that simplifies things a lot.
> > diff --git a/configure.ac b/configure.ac
> > index 40ccd88aa2a950..8a2505e37c70ab 100644
> > --- a/configure.ac
> > +++ b/configure.ac
> > @@ -195,6 +195,7 @@ if test "$have_listmount" = "yes"; then
> > fi
> > AC_HAVE_STATMOUNT_SUPPORTED_MASK
> > AC_HAVE_FANOTIFY_MOUNTINFO
> > +AC_HAVE_QUOTACTL_FD
>
> Shouldn't the AC_HAVE_QUOTACTL_FD go into a separate patch, including
> a generic helper? I assume most other uqotactl users would prefer
> that as well when available.
Yes. I could hoist xfsquotactl from quota/linux.c into libfrog, and
then adapt it to use quotactl_fd if available:
int
xfsquotactl(
int mnt_fd,
const char *device,
enum xfs_quota_cmd xcommand,
uint xtype,
uint id,
void *addr)
{
const int op = QCMD(xcommand_to_qcommand(xcommand),
xtype_to_qtype(xtype));
int ret = -1;
errno = ENOSYS;
#ifdef HAVE_QUOTACTL_FD
if (mnt_fd >= 0)
ret = syscall(SYS_quotactl_fd, mnt_fd, op, id, addr);
#endif
if (ret != -1 || errno != ENOSYS)
return ret;
return quotactl(op, device, id, addr);
}
This will require some amount of refactoring in xfs_quota, since it
doesn't currently try to open() the filesystem mountpoint. OTOH now it
will no longer fail if a sysadmin does an lvrename while it's running.
However, doing all that got intense, so I'm splitting all that out into
a separate hoist/cleanup/adapt series. For now, the get_qflags function
in spaceman will look like this:
/* GETQSTAT returns qflags for all quota types, not just user */
ret = quotactl(QCMD(Q_XGETQSTAT, USRQUOTA), f->fs_path.fs_name, 0,
(void *)&qstat);
until the new series ports it to xfsquotactl.
> Otherwise this looks good from a quick look.
--D
^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH 6/9] makecfg: handle old V4 options that are almost always on by default
2026-09-09 6:00 [PATCHSET v3] xfsprogs: generate mkfs.xfs config files Darrick J. Wong
` (4 preceding siblings ...)
2026-09-09 6:01 ` [PATCH 5/9] makecfg: handle metadir quota options Darrick J. Wong
@ 2026-09-09 6:01 ` Darrick J. Wong
2026-09-09 13:15 ` Andrey Albershteyn
2026-09-11 15:49 ` Christoph Hellwig
2026-09-09 6:02 ` [PATCH 7/9] makecfg: add a few more file related options Darrick J. Wong
` (2 subsequent siblings)
8 siblings, 2 replies; 32+ messages in thread
From: Darrick J. Wong @ 2026-09-09 6:01 UTC (permalink / raw)
To: djwong, aalbersh; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
The same alternate LOLLM also observed that there are a couple of V4
options that are always enabled on a V5 filesystem. Since we support V4
for another 4 years, add these two options but only for the weird case
where someone wants to turn them off.
Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
---
libfrog/fsgeom.c | 39 +++++++++++++++++++++++++++++++++++++++
1 file changed, 39 insertions(+)
diff --git a/libfrog/fsgeom.c b/libfrog/fsgeom.c
index 2172310aa102d6..5f2d8dc428fee5 100644
--- a/libfrog/fsgeom.c
+++ b/libfrog/fsgeom.c
@@ -286,6 +286,7 @@ enum {
I_SPINODES = 0,
I_NREXT64,
I_EXCHANGE,
+ I_PROJID32BIT,
I_MAX_OPTS,
};
@@ -301,6 +302,11 @@ enum {
R_MAX_OPTS,
};
+enum {
+ L_LAZYSBCNTR,
+ L_MAX_OPTS,
+};
+
struct mkfs_config_opt;
struct mkfs_config_data {
@@ -344,6 +350,24 @@ print_fsgeom(
return 0;
}
+static int
+print_fsgeom_only_if_missing(
+ const struct mkfs_config_opt *opt,
+ const struct mkfs_config_data *data,
+ FILE *fp)
+{
+ const struct xfs_fsop_geom *fsgeo = data->fsgeo;
+ int ret;
+
+ if (fsgeo->flags & opt->fsgeom_flag)
+ return 0;
+
+ ret = fprintf(fp, "%s=0\n", opt->name);
+ if (ret <= 0)
+ return ret;
+ return 0;
+}
+
static int
print_xflag(
const struct mkfs_config_opt *opt,
@@ -618,9 +642,24 @@ static const struct mkfs_config_section config_sections[] = {
.name = "exchange",
.fsgeom_flag = XFS_FSOP_GEOM_FLAGS_EXCHANGE_RANGE,
},
+ [I_PROJID32BIT] = {
+ .name = "projid32bit",
+ .fsgeom_flag = XFS_FSOP_GEOM_FLAGS_PROJID32,
+ .print_fn = print_fsgeom_only_if_missing,
+ },
[I_MAX_OPTS] = { },
},
},
+ {
+ .ini_section = "log",
+ .subopts = {
+ [L_LAZYSBCNTR] = {
+ .name = "lazy-count",
+ .fsgeom_flag = XFS_FSOP_GEOM_FLAGS_LAZYSB,
+ .print_fn = print_fsgeom_only_if_missing,
+ },
+ },
+ },
{
.ini_section = "naming",
.subopts = {
^ permalink raw reply related [flat|nested] 32+ messages in thread* Re: [PATCH 6/9] makecfg: handle old V4 options that are almost always on by default
2026-09-09 6:01 ` [PATCH 6/9] makecfg: handle old V4 options that are almost always on by default Darrick J. Wong
@ 2026-09-09 13:15 ` Andrey Albershteyn
2026-09-11 15:49 ` Christoph Hellwig
1 sibling, 0 replies; 32+ messages in thread
From: Andrey Albershteyn @ 2026-09-09 13:15 UTC (permalink / raw)
To: Darrick J. Wong; +Cc: linux-xfs
On 2026-09-08 23:01:48, Darrick J. Wong wrote:
> From: Darrick J. Wong <djwong@kernel.org>
>
> The same alternate LOLLM also observed that there are a couple of V4
> options that are always enabled on a V5 filesystem. Since we support V4
> for another 4 years, add these two options but only for the weird case
> where someone wants to turn them off.
>
> Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
Looks good to me
Reviewed-by: Andrey Albershteyn <aalbersh@kernel.org>
--
- Andrey
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 6/9] makecfg: handle old V4 options that are almost always on by default
2026-09-09 6:01 ` [PATCH 6/9] makecfg: handle old V4 options that are almost always on by default Darrick J. Wong
2026-09-09 13:15 ` Andrey Albershteyn
@ 2026-09-11 15:49 ` Christoph Hellwig
2026-09-11 16:03 ` Darrick J. Wong
1 sibling, 1 reply; 32+ messages in thread
From: Christoph Hellwig @ 2026-09-11 15:49 UTC (permalink / raw)
To: Darrick J. Wong; +Cc: aalbersh, linux-xfs
Looks good, but I'd really expect this to just go into the original
patch?
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 6/9] makecfg: handle old V4 options that are almost always on by default
2026-09-11 15:49 ` Christoph Hellwig
@ 2026-09-11 16:03 ` Darrick J. Wong
0 siblings, 0 replies; 32+ messages in thread
From: Darrick J. Wong @ 2026-09-11 16:03 UTC (permalink / raw)
To: Christoph Hellwig; +Cc: aalbersh, linux-xfs
On Fri, Sep 11, 2026 at 08:49:10AM -0700, Christoph Hellwig wrote:
> Looks good, but I'd really expect this to just go into the original
> patch?
Andrey had already reviewed the original patch, so I put all the new
bits into separate patches so that (a) if Andrey pulled the patches into
for-next then I wouldn't have to separate out the changes, and (b) if he
decided to re-read the series, he could focus on the obvious new stuff.
Longer term I'm going to merge all three of these back into the main
patch since Andrey did actually review all the new stuff.
--D
^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH 7/9] makecfg: add a few more file related options
2026-09-09 6:00 [PATCHSET v3] xfsprogs: generate mkfs.xfs config files Darrick J. Wong
` (5 preceding siblings ...)
2026-09-09 6:01 ` [PATCH 6/9] makecfg: handle old V4 options that are almost always on by default Darrick J. Wong
@ 2026-09-09 6:02 ` Darrick J. Wong
2026-09-09 13:16 ` Andrey Albershteyn
2026-09-11 15:49 ` Christoph Hellwig
2026-09-09 6:02 ` [PATCH 8/9] xfs_admin: print configuration file for mounted filesystems Darrick J. Wong
2026-09-09 6:02 ` [PATCH 9/9] mkfs: allow specification of default options via configuration file Darrick J. Wong
8 siblings, 2 replies; 32+ messages in thread
From: Darrick J. Wong @ 2026-09-09 6:02 UTC (permalink / raw)
To: djwong, aalbersh; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Add a few more configuration options for directory and inode related
options that might cause user-observable behavior changes.
Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
---
libfrog/fsgeom.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 100 insertions(+)
diff --git a/libfrog/fsgeom.c b/libfrog/fsgeom.c
index 5f2d8dc428fee5..efb61935a07073 100644
--- a/libfrog/fsgeom.c
+++ b/libfrog/fsgeom.c
@@ -11,6 +11,7 @@
#include "libfrog/fsproperties.h"
#include "xfs_arch.h"
#include "libxfs/xfs_format.h"
+#include "xfs_multidisk.h"
static inline const char *
rtdev_name(
@@ -287,6 +288,8 @@ enum {
I_NREXT64,
I_EXCHANGE,
I_PROJID32BIT,
+ I_MAXPCT,
+ I_SIZE,
I_MAX_OPTS,
};
@@ -294,6 +297,7 @@ enum {
N_PARENT = 0,
N_FTYPE,
N_VERSION,
+ N_SIZE,
N_MAX_OPTS,
};
@@ -498,6 +502,90 @@ print_dirversion(
return 0;
}
+static int
+print_dirsize(
+ const struct mkfs_config_opt *opt,
+ const struct mkfs_config_data *data,
+ FILE *fp)
+{
+ const struct xfs_fsop_geom *fsgeo = data->fsgeo;
+ int ret;
+
+ /* No need to emit the directory block size if it's the minimum */
+ if (fsgeo->dirblocksize > (1U << XFS_MIN_REC_DIRSIZE)) {
+ ret = fprintf(fp, "%s=%u\n", opt->name, fsgeo->dirblocksize);
+ if (ret <= 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static inline uint64_t terablocks(unsigned int nr, unsigned int blocksize)
+{
+ return (nr * (1ULL << 40)) / blocksize;
+}
+
+static inline unsigned int default_imaxpct(const struct xfs_fsop_geom *fsgeo)
+{
+ /*
+ * This returns the % of the disk space that is used for
+ * inodes, it changes relatively to the FS size:
+ * - over 50 TB, use 1%,
+ * - 1TB - 50 TB, use 5%,
+ * - under 1 TB, use XFS_DFL_IMAXIMUM_PCT (25%).
+ */
+
+ if (fsgeo->datablocks < terablocks(1, fsgeo->blocksize))
+ return XFS_DFL_IMAXIMUM_PCT;
+ if (fsgeo->datablocks < terablocks(50, fsgeo->blocksize))
+ return 5;
+ return 1;
+}
+
+static int
+print_imaxpct(
+ const struct mkfs_config_opt *opt,
+ const struct mkfs_config_data *data,
+ FILE *fp)
+{
+ const struct xfs_fsop_geom *fsgeo = data->fsgeo;
+ int ret;
+
+ if (fsgeo->imaxpct != default_imaxpct(fsgeo)) {
+ ret = fprintf(fp, "%s=%u\n", opt->name, fsgeo->imaxpct);
+ if (ret <= 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static inline unsigned int default_inodesize(const struct xfs_fsop_geom *fsgeo)
+{
+ if (fsgeo->flags & XFS_FSOP_GEOM_FLAGS_V5SB)
+ return 1U << XFS_DINODE_DFL_CRC_LOG;
+ return 1U << XFS_DINODE_DFL_LOG;
+}
+
+static int
+print_inodesize(
+ const struct mkfs_config_opt *opt,
+ const struct mkfs_config_data *data,
+ FILE *fp)
+{
+ const struct xfs_fsop_geom *fsgeo = data->fsgeo;
+ int ret;
+
+ if (fsgeo->inodesize != default_inodesize(fsgeo)) {
+ ret = fprintf(fp, "%s=%u\n", opt->name, fsgeo->inodesize);
+ if (ret <= 0)
+ return ret;
+ }
+
+ return 0;
+}
+
static int
print_autofsck(
const struct mkfs_config_opt *opt,
@@ -647,6 +735,14 @@ static const struct mkfs_config_section config_sections[] = {
.fsgeom_flag = XFS_FSOP_GEOM_FLAGS_PROJID32,
.print_fn = print_fsgeom_only_if_missing,
},
+ [I_MAXPCT] = {
+ .name = "maxpct",
+ .print_fn = print_imaxpct,
+ },
+ [I_SIZE] = {
+ .name = "size",
+ .print_fn = print_inodesize,
+ },
[I_MAX_OPTS] = { },
},
},
@@ -675,6 +771,10 @@ static const struct mkfs_config_section config_sections[] = {
.name = "version",
.print_fn = print_dirversion,
},
+ [N_SIZE] = {
+ .name = "size",
+ .print_fn = print_dirsize,
+ },
},
},
{
^ permalink raw reply related [flat|nested] 32+ messages in thread* Re: [PATCH 7/9] makecfg: add a few more file related options
2026-09-09 6:02 ` [PATCH 7/9] makecfg: add a few more file related options Darrick J. Wong
@ 2026-09-09 13:16 ` Andrey Albershteyn
2026-09-11 15:49 ` Christoph Hellwig
1 sibling, 0 replies; 32+ messages in thread
From: Andrey Albershteyn @ 2026-09-09 13:16 UTC (permalink / raw)
To: Darrick J. Wong; +Cc: linux-xfs
On 2026-09-08 23:02:04, Darrick J. Wong wrote:
> From: Darrick J. Wong <djwong@kernel.org>
>
> Add a few more configuration options for directory and inode related
> options that might cause user-observable behavior changes.
>
> Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
Looks good to me
Reviewed-by: Andrey Albershteyn <aalbersh@kernel.org>
--
- Andrey
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 7/9] makecfg: add a few more file related options
2026-09-09 6:02 ` [PATCH 7/9] makecfg: add a few more file related options Darrick J. Wong
2026-09-09 13:16 ` Andrey Albershteyn
@ 2026-09-11 15:49 ` Christoph Hellwig
2026-09-11 16:04 ` Darrick J. Wong
1 sibling, 1 reply; 32+ messages in thread
From: Christoph Hellwig @ 2026-09-11 15:49 UTC (permalink / raw)
To: Darrick J. Wong; +Cc: aalbersh, linux-xfs
On Tue, Sep 08, 2026 at 11:02:04PM -0700, Darrick J. Wong wrote:
> From: Darrick J. Wong <djwong@kernel.org>
>
> Add a few more configuration options for directory and inode related
> options that might cause user-observable behavior changes.
Why not add those to the original patch? What makes them different?
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 7/9] makecfg: add a few more file related options
2026-09-11 15:49 ` Christoph Hellwig
@ 2026-09-11 16:04 ` Darrick J. Wong
0 siblings, 0 replies; 32+ messages in thread
From: Darrick J. Wong @ 2026-09-11 16:04 UTC (permalink / raw)
To: Christoph Hellwig; +Cc: aalbersh, linux-xfs
On Fri, Sep 11, 2026 at 08:49:40AM -0700, Christoph Hellwig wrote:
> On Tue, Sep 08, 2026 at 11:02:04PM -0700, Darrick J. Wong wrote:
> > From: Darrick J. Wong <djwong@kernel.org>
> >
> > Add a few more configuration options for directory and inode related
> > options that might cause user-observable behavior changes.
>
> Why not add those to the original patch? What makes them different?
Same answer as for patch 6.
--D
^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH 8/9] xfs_admin: print configuration file for mounted filesystems
2026-09-09 6:00 [PATCHSET v3] xfsprogs: generate mkfs.xfs config files Darrick J. Wong
` (6 preceding siblings ...)
2026-09-09 6:02 ` [PATCH 7/9] makecfg: add a few more file related options Darrick J. Wong
@ 2026-09-09 6:02 ` Darrick J. Wong
2026-09-11 15:50 ` Christoph Hellwig
2026-09-09 6:02 ` [PATCH 9/9] mkfs: allow specification of default options via configuration file Darrick J. Wong
8 siblings, 1 reply; 32+ messages in thread
From: Darrick J. Wong @ 2026-09-09 6:02 UTC (permalink / raw)
To: djwong, aalbersh; +Cc: linux-xfs
From: Darrick J. Wong <djwong@kernel.org>
Teach xfs_admin to emit a mkfs.xfs config file for a mounted or
unmounted filesystem.
Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
Reviewed-by: Andrey Albershteyn <aalbersh@kernel.org>
---
db/xfs_admin.sh | 15 +++++++++++++--
man/man8/xfs_admin.8 | 7 +++++++
2 files changed, 20 insertions(+), 2 deletions(-)
diff --git a/db/xfs_admin.sh b/db/xfs_admin.sh
index 52a658ba4a540f..13a876ad8d1377 100755
--- a/db/xfs_admin.sh
+++ b/db/xfs_admin.sh
@@ -11,16 +11,20 @@ DB_OPTS=""
DB_DEV_OPTS=""
REPAIR_OPTS=""
IO_OPTS=""
+SPACEMAN_OPTS=""
REPAIR_DEV_OPTS=""
LOG_OPTS=""
-USAGE="Usage: xfs_admin [-efjlpuV] [-c 0|1] [-L label] [-O v5_feature] [-r rtdev] [-U uuid] device [logdev]"
+USAGE="Usage: xfs_admin [-efjlpuV] [-C cfgfile] [-c 0|1] [-L label] [-O v5_feature] [-r rtdev] [-U uuid] device [logdev]"
-while getopts "c:efjlL:O:pr:uU:V" c
+while getopts "C:c:efjlL:O:pr:uU:V" c
do
case $c in
c) REPAIR_OPTS=$REPAIR_OPTS" -c lazycount="$OPTARG
require_offline=1
;;
+ C) DB_OPTS=$DB_OPTS" -c 'makecfg "$OPTARG"'"
+ SPACEMAN_OPTS=$SPACEMAN_OPTS" -c 'makecfg "$OPTARG"'"
+ ;;
e) DB_OPTS=$DB_OPTS" -c 'version extflg'"
require_offline=1
;;
@@ -72,6 +76,13 @@ case $# in
exit 2
fi
+ if [ -n "$SPACEMAN_OPTS" ]; then
+ eval xfs_spaceman -p xfs_admin $SPACEMAN_OPTS "$mntpt"
+ res=$?
+ test $res -ne 0 && exit $res
+ test -n "$IO_OPTS" || exit $res
+ fi
+
if [ -n "$IO_OPTS" ]; then
eval xfs_io -p xfs_admin $IO_OPTS "$mntpt"
exit $?
diff --git a/man/man8/xfs_admin.8 b/man/man8/xfs_admin.8
index 63f8ee90307b30..d2652c0598f551 100644
--- a/man/man8/xfs_admin.8
+++ b/man/man8/xfs_admin.8
@@ -8,6 +8,8 @@ .SH SYNOPSIS
] [
.BI \-O " featurelist"
] [
+.BR "\-C " cfgfile
+] [
.BR "\-c 0" | 1
] [
.B \-L
@@ -85,6 +87,11 @@ .SH OPTIONS
.B \-u
Print the current filesystem UUID (Universally Unique IDentifier).
.TP
+.BI "\-C " path
+Write a configuration file to the given path that can be re-read by mkfs.xfs
+for a future filesystem format attempt.
+This file will contain only user-visible features.
+.TP
.BR "\-c 0" | 1
Enable (1) or disable (0) lazy-counters in the filesystem.
.IP
^ permalink raw reply related [flat|nested] 32+ messages in thread* [PATCH 9/9] mkfs: allow specification of default options via configuration file
2026-09-09 6:00 [PATCHSET v3] xfsprogs: generate mkfs.xfs config files Darrick J. Wong
` (7 preceding siblings ...)
2026-09-09 6:02 ` [PATCH 8/9] xfs_admin: print configuration file for mounted filesystems Darrick J. Wong
@ 2026-09-09 6:02 ` Darrick J. Wong
2026-09-10 11:23 ` Andrey Albershteyn
2026-09-11 4:43 ` [PATCH v3.1 " Darrick J. Wong
8 siblings, 2 replies; 32+ messages in thread
From: Darrick J. Wong @ 2026-09-09 6:02 UTC (permalink / raw)
To: djwong, aalbersh; +Cc: hch, tytso, linux-xfs
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
Cc: hch@infradead.org
Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
---
man/man8/mkfs.xfs.8.in | 16 ++++-
mkfs/xfs_mkfs.c | 158 ++++++++++++++++++++++++++++++++++++++++++------
2 files changed, 151 insertions(+), 23 deletions(-)
diff --git a/man/man8/mkfs.xfs.8.in b/man/man8/mkfs.xfs.8.in
index fb62d579a26a2d..d915e72330304b 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 makecfg= path
Write a configuration file to the file specified by the
.I path
diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
index 38a5769188b05a..334367b81555ec 100644
--- a/mkfs/xfs_mkfs.c
+++ b/mkfs/xfs_mkfs.c
@@ -62,6 +62,7 @@ enum {
enum {
C_OPTFILE = 0,
C_MAKECFG,
+ C_DEFOPTFILE,
C_MAX_OPTS,
};
@@ -314,6 +315,7 @@ static struct opt_params copts = {
.subopts = {
[C_OPTFILE] = "options",
[C_MAKECFG] = "makecfg",
+ [C_DEFOPTFILE] = "defaults",
[C_MAX_OPTS] = NULL,
},
.subopt_params = {
@@ -325,6 +327,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,
+ },
},
};
@@ -1077,6 +1083,7 @@ struct cli_params {
int blocksize;
char *cfgfile;
+ char *defcfgfile;
char *protofile;
char *makecfg;
@@ -1214,7 +1221,7 @@ usage( void )
{
fprintf(stderr, _("Usage: %s\n\
/* blocksize */ [-b size=num]\n\
-/* config file */ [-c options=path,makecfg=path\n\
+/* config file */ [-c options=path,makecfg=path,defaults=path\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\
@@ -1797,6 +1804,30 @@ cfgfile_opts_parser(
case C_MAKECFG:
cli->makecfg = 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:
+ case C_MAKECFG:
+ /* will be processed by cfgfile_opts_parser; ignored */
+ break;
+ case C_DEFOPTFILE:
+ cli->defcfgfile = getstr(value, opts, subopt);
+ break;
default:
return -EINVAL;
}
@@ -2263,13 +2294,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 },
@@ -2283,15 +2316,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)
@@ -2303,7 +2342,14 @@ parse_subopts(
if (!sop->opts)
return;
- p = arg;
+ /* getsubopt modifies duparg */
+ duparg = strdup(arg);
+ if (!duparg) {
+ perror("allocating memory");
+ exit(1);
+ }
+
+ p = duparg;
while (*p != '\0') {
char **subopts = (char **)sop->opts->subopts;
char *value;
@@ -2315,19 +2361,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' &&
@@ -5803,6 +5850,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,
@@ -6058,8 +6163,19 @@ 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) {
+#define MKFS_GETOPT_STRING "b:c:d:i:l:L:m:n:KNp:qr:s:CfV"
+ /* Load default configuration, if specified */
+ while ((c = getopt_long(argc, argv, MKFS_GETOPT_STRING,
+ long_options, &option_index)) != EOF) {
+ if (c == 'c')
+ parse_subopts(c, optarg, defcfg_subopt_tab, &cli);
+ }
+ defcfgfile_parse(&cli);
+ optind = 1;
+
+ /* Do the real option parsing */
+ while ((c = getopt_long(argc, argv, MKFS_GETOPT_STRING,
+ long_options, &option_index)) != EOF) {
switch (c) {
case 0:
break;
@@ -6077,7 +6193,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] 32+ messages in thread* Re: [PATCH 9/9] mkfs: allow specification of default options via configuration file
2026-09-09 6:02 ` [PATCH 9/9] mkfs: allow specification of default options via configuration file Darrick J. Wong
@ 2026-09-10 11:23 ` Andrey Albershteyn
2026-09-10 15:17 ` Darrick J. Wong
2026-09-11 4:43 ` [PATCH v3.1 " Darrick J. Wong
1 sibling, 1 reply; 32+ messages in thread
From: Andrey Albershteyn @ 2026-09-10 11:23 UTC (permalink / raw)
To: Darrick J. Wong; +Cc: hch, tytso, linux-xfs
On 2026-09-08 23:02:35, 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.
>
> Cc: tytso@mit.edu
> Cc: hch@infradead.org
> Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
> ---
> man/man8/mkfs.xfs.8.in | 16 ++++-
> mkfs/xfs_mkfs.c | 158 ++++++++++++++++++++++++++++++++++++++++++------
> 2 files changed, 151 insertions(+), 23 deletions(-)
>
>
> diff --git a/man/man8/mkfs.xfs.8.in b/man/man8/mkfs.xfs.8.in
> index fb62d579a26a2d..d915e72330304b 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@.
Shouldn't this also mention makecfg?
Otherwise, looks good to me
Reviewed-by: Andrey Albershteyn <aalbersh@kernel.org>
--
- Andrey
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 9/9] mkfs: allow specification of default options via configuration file
2026-09-10 11:23 ` Andrey Albershteyn
@ 2026-09-10 15:17 ` Darrick J. Wong
2026-09-10 15:37 ` Andrey Albershteyn
0 siblings, 1 reply; 32+ messages in thread
From: Darrick J. Wong @ 2026-09-10 15:17 UTC (permalink / raw)
To: Andrey Albershteyn; +Cc: hch, tytso, linux-xfs
On Thu, Sep 10, 2026 at 01:23:09PM +0200, Andrey Albershteyn wrote:
> On 2026-09-08 23:02:35, 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.
> >
> > Cc: tytso@mit.edu
> > Cc: hch@infradead.org
> > Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
> > ---
> > man/man8/mkfs.xfs.8.in | 16 ++++-
> > mkfs/xfs_mkfs.c | 158 ++++++++++++++++++++++++++++++++++++++++++------
> > 2 files changed, 151 insertions(+), 23 deletions(-)
> >
> >
> > diff --git a/man/man8/mkfs.xfs.8.in b/man/man8/mkfs.xfs.8.in
> > index fb62d579a26a2d..d915e72330304b 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@.
>
> Shouldn't this also mention makecfg?
Err, what do you mean? The patch adding makecfg to mkfs has its own
manpage update:
https://lore.kernel.org/linux-xfs/178892910566.4047311.11716167302378334931.stgit@frogsfrogsfrogs/
diff --git a/man/man8/mkfs.xfs.8.in b/man/man8/mkfs.xfs.8.in
index c4dee4fe07ae83..fb62d579a26a2d 100644
--- a/man/man8/mkfs.xfs.8.in
+++ b/man/man8/mkfs.xfs.8.in
@@ -156,6 +156,13 @@ .SH OPTIONS
is:
.RS 1.2i
.TP
+.BI makecfg= path
+Write a configuration file to the file specified by the
+.I path
+option string.
+This file can be re-read by mkfs.xfs for a future filesystem format attempt.
+This file will contain only user-visible features.
+.TP
.BI options= name
The configuration options will be sourced from the file specified by the
.I name
Though perhaps it should mention that if you specify makecfg=foo, it
will create foo in the current directory, not @mkfs_cfg_dir@. That's
inconsistent with options= and defaults= but I don't think very many
people will want "no path separators at all" to mean "write it to
/usr/lib/xfsprogs/mkfs".
<confused>
> Otherwise, looks good to me
> Reviewed-by: Andrey Albershteyn <aalbersh@kernel.org>
Thanks!
--D
^ permalink raw reply related [flat|nested] 32+ messages in thread
* Re: [PATCH 9/9] mkfs: allow specification of default options via configuration file
2026-09-10 15:17 ` Darrick J. Wong
@ 2026-09-10 15:37 ` Andrey Albershteyn
2026-09-10 16:06 ` Darrick J. Wong
0 siblings, 1 reply; 32+ messages in thread
From: Andrey Albershteyn @ 2026-09-10 15:37 UTC (permalink / raw)
To: Darrick J. Wong; +Cc: hch, tytso, linux-xfs
On 2026-09-10 08:17:05, Darrick J. Wong wrote:
> On Thu, Sep 10, 2026 at 01:23:09PM +0200, Andrey Albershteyn wrote:
> > On 2026-09-08 23:02:35, 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.
> > >
> > > Cc: tytso@mit.edu
> > > Cc: hch@infradead.org
> > > Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
> > > ---
> > > man/man8/mkfs.xfs.8.in | 16 ++++-
> > > mkfs/xfs_mkfs.c | 158 ++++++++++++++++++++++++++++++++++++++++++------
> > > 2 files changed, 151 insertions(+), 23 deletions(-)
> > >
> > >
> > > diff --git a/man/man8/mkfs.xfs.8.in b/man/man8/mkfs.xfs.8.in
> > > index fb62d579a26a2d..d915e72330304b 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@.
> >
> > Shouldn't this also mention makecfg?
>
> Err, what do you mean? The patch adding makecfg to mkfs has its own
> manpage update:
I mean that there're sample configs or you can create one with
makecfg. Just a convenient reference to let users know about
possibility
--
- Andrey
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 9/9] mkfs: allow specification of default options via configuration file
2026-09-10 15:37 ` Andrey Albershteyn
@ 2026-09-10 16:06 ` Darrick J. Wong
2026-09-10 16:38 ` Andrey Albershteyn
0 siblings, 1 reply; 32+ messages in thread
From: Darrick J. Wong @ 2026-09-10 16:06 UTC (permalink / raw)
To: Andrey Albershteyn; +Cc: hch, tytso, linux-xfs
On Thu, Sep 10, 2026 at 05:37:38PM +0200, Andrey Albershteyn wrote:
> On 2026-09-10 08:17:05, Darrick J. Wong wrote:
> > On Thu, Sep 10, 2026 at 01:23:09PM +0200, Andrey Albershteyn wrote:
> > > On 2026-09-08 23:02:35, 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.
> > > >
> > > > Cc: tytso@mit.edu
> > > > Cc: hch@infradead.org
> > > > Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
> > > > ---
> > > > man/man8/mkfs.xfs.8.in | 16 ++++-
> > > > mkfs/xfs_mkfs.c | 158 ++++++++++++++++++++++++++++++++++++++++++------
> > > > 2 files changed, 151 insertions(+), 23 deletions(-)
> > > >
> > > >
> > > > diff --git a/man/man8/mkfs.xfs.8.in b/man/man8/mkfs.xfs.8.in
> > > > index fb62d579a26a2d..d915e72330304b 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@.
> > >
> > > Shouldn't this also mention makecfg?
> >
> > Err, what do you mean? The patch adding makecfg to mkfs has its own
> > manpage update:
>
> I mean that there're sample configs or you can create one with
> makecfg. Just a convenient reference to let users know about
> possibility
Oh. Yes. I've rewritten this section to read:
"Default configuration options will be sourced from the file specified
by the name option string. This option can be use either an absolute or
relative path to the configuration file to be read. Options speci‐ fied
through the default configuration file can be overridden by a
configuration file specified via options= or by command line arguments,
in that order.
"Sample configuration files can be found in @mkfs_cfg_dir@. This option
also accepts configuration files generated by the makecfg suboption
below, or by the makecfg subcommand of xfs_db and xfs_spaceman."
How does that sound?
--D
> --
> - Andrey
>
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 9/9] mkfs: allow specification of default options via configuration file
2026-09-10 16:06 ` Darrick J. Wong
@ 2026-09-10 16:38 ` Andrey Albershteyn
0 siblings, 0 replies; 32+ messages in thread
From: Andrey Albershteyn @ 2026-09-10 16:38 UTC (permalink / raw)
To: Darrick J. Wong; +Cc: hch, tytso, linux-xfs
On 2026-09-10 09:06:55, Darrick J. Wong wrote:
> On Thu, Sep 10, 2026 at 05:37:38PM +0200, Andrey Albershteyn wrote:
> > On 2026-09-10 08:17:05, Darrick J. Wong wrote:
> > > On Thu, Sep 10, 2026 at 01:23:09PM +0200, Andrey Albershteyn wrote:
> > > > On 2026-09-08 23:02:35, 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.
> > > > >
> > > > > Cc: tytso@mit.edu
> > > > > Cc: hch@infradead.org
> > > > > Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
> > > > > ---
> > > > > man/man8/mkfs.xfs.8.in | 16 ++++-
> > > > > mkfs/xfs_mkfs.c | 158 ++++++++++++++++++++++++++++++++++++++++++------
> > > > > 2 files changed, 151 insertions(+), 23 deletions(-)
> > > > >
> > > > >
> > > > > diff --git a/man/man8/mkfs.xfs.8.in b/man/man8/mkfs.xfs.8.in
> > > > > index fb62d579a26a2d..d915e72330304b 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@.
> > > >
> > > > Shouldn't this also mention makecfg?
> > >
> > > Err, what do you mean? The patch adding makecfg to mkfs has its own
> > > manpage update:
> >
> > I mean that there're sample configs or you can create one with
> > makecfg. Just a convenient reference to let users know about
> > possibility
>
> Oh. Yes. I've rewritten this section to read:
>
> "Default configuration options will be sourced from the file specified
> by the name option string. This option can be use either an absolute or
> relative path to the configuration file to be read. Options speci‐ fied
> through the default configuration file can be overridden by a
> configuration file specified via options= or by command line arguments,
> in that order.
>
> "Sample configuration files can be found in @mkfs_cfg_dir@. This option
> also accepts configuration files generated by the makecfg suboption
> below, or by the makecfg subcommand of xfs_db and xfs_spaceman."
>
> How does that sound?
sounds good :)
--
- Andrey
^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v3.1 9/9] mkfs: allow specification of default options via configuration file
2026-09-09 6:02 ` [PATCH 9/9] mkfs: allow specification of default options via configuration file Darrick J. Wong
2026-09-10 11:23 ` Andrey Albershteyn
@ 2026-09-11 4:43 ` Darrick J. Wong
2026-09-11 15:51 ` Christoph Hellwig
1 sibling, 1 reply; 32+ messages in thread
From: Darrick J. Wong @ 2026-09-11 4:43 UTC (permalink / raw)
To: aalbersh; +Cc: hch, tytso, linux-xfs
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
Cc: hch@infradead.org
Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
Reviewed-by: Andrey Albershteyn <aalbersh@kernel.org>
---
v3.1: say more in the manpage update about makecfg vs. default
---
man/man8/mkfs.xfs.8.in | 25 +++++++-
mkfs/xfs_mkfs.c | 158 ++++++++++++++++++++++++++++++++++++++++++------
2 files changed, 160 insertions(+), 23 deletions(-)
diff --git a/man/man8/mkfs.xfs.8.in b/man/man8/mkfs.xfs.8.in
index fb62d579a26a2d..006ec2874033f7 100644
--- a/man/man8/mkfs.xfs.8.in
+++ b/man/man8/mkfs.xfs.8.in
@@ -152,10 +152,31 @@ .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= path
+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.
+Options specified through the default configuration file can be overridden by
+a configuration file specified via
+.B options=
+or by command line arguments, in that order.
+
+Sample configuration files can be found in @mkfs_cfg_dir@.
+This option also accepts configuration files generated by the
+.B makecfg
+suboption below, or by the
+.B makecfg
+subcommand of
+.B xfs_db
+and
+.BR xfs_spaceman .
+.TP
.BI makecfg= path
Write a configuration file to the file specified by the
.I path
diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
index 38a5769188b05a..334367b81555ec 100644
--- a/mkfs/xfs_mkfs.c
+++ b/mkfs/xfs_mkfs.c
@@ -62,6 +62,7 @@ enum {
enum {
C_OPTFILE = 0,
C_MAKECFG,
+ C_DEFOPTFILE,
C_MAX_OPTS,
};
@@ -314,6 +315,7 @@ static struct opt_params copts = {
.subopts = {
[C_OPTFILE] = "options",
[C_MAKECFG] = "makecfg",
+ [C_DEFOPTFILE] = "defaults",
[C_MAX_OPTS] = NULL,
},
.subopt_params = {
@@ -325,6 +327,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,
+ },
},
};
@@ -1077,6 +1083,7 @@ struct cli_params {
int blocksize;
char *cfgfile;
+ char *defcfgfile;
char *protofile;
char *makecfg;
@@ -1214,7 +1221,7 @@ usage( void )
{
fprintf(stderr, _("Usage: %s\n\
/* blocksize */ [-b size=num]\n\
-/* config file */ [-c options=path,makecfg=path\n\
+/* config file */ [-c options=path,makecfg=path,defaults=path\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\
@@ -1797,6 +1804,30 @@ cfgfile_opts_parser(
case C_MAKECFG:
cli->makecfg = 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:
+ case C_MAKECFG:
+ /* will be processed by cfgfile_opts_parser; ignored */
+ break;
+ case C_DEFOPTFILE:
+ cli->defcfgfile = getstr(value, opts, subopt);
+ break;
default:
return -EINVAL;
}
@@ -2263,13 +2294,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 },
@@ -2283,15 +2316,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)
@@ -2303,7 +2342,14 @@ parse_subopts(
if (!sop->opts)
return;
- p = arg;
+ /* getsubopt modifies duparg */
+ duparg = strdup(arg);
+ if (!duparg) {
+ perror("allocating memory");
+ exit(1);
+ }
+
+ p = duparg;
while (*p != '\0') {
char **subopts = (char **)sop->opts->subopts;
char *value;
@@ -2315,19 +2361,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' &&
@@ -5803,6 +5850,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,
@@ -6058,8 +6163,19 @@ 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) {
+#define MKFS_GETOPT_STRING "b:c:d:i:l:L:m:n:KNp:qr:s:CfV"
+ /* Load default configuration, if specified */
+ while ((c = getopt_long(argc, argv, MKFS_GETOPT_STRING,
+ long_options, &option_index)) != EOF) {
+ if (c == 'c')
+ parse_subopts(c, optarg, defcfg_subopt_tab, &cli);
+ }
+ defcfgfile_parse(&cli);
+ optind = 1;
+
+ /* Do the real option parsing */
+ while ((c = getopt_long(argc, argv, MKFS_GETOPT_STRING,
+ long_options, &option_index)) != EOF) {
switch (c) {
case 0:
break;
@@ -6077,7 +6193,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] 32+ messages in thread