]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
mkfs: stop allowing tiny filesystems
authorDarrick J. Wong <djwong@kernel.org>
Fri, 11 Mar 2022 02:07:21 +0000 (18:07 -0800)
committerDarrick J. Wong <djwong@kernel.org>
Thu, 17 Mar 2022 21:40:26 +0000 (14:40 -0700)
Refuse to format a filesystem that are "too small", because these
configurations are known to have performance and redundancy problems
that are not present on the volume sizes that XFS is best at handling.

Specifically, this means that we won't allow logs smaller than 64MB, we
won't allow single-AG filesystems, and we won't allow volumes smaller
than 300MB.  There are two exceptions: the first is an undocumented CLI
option that can be used for crafting debug filesystems.

The second exception is that if fstests is detected, because there are a
lot of fstests that use tiny filesystems to perform targeted regression
and functional testing in a controlled environment.  Fixing the ~40 or
so tests to run more slowly with larger filesystems isn't worth the risk
of breaking the tests.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
mkfs/xfs_mkfs.c

index 84dbb799f3d2627893d2b98c6e8d8c05dbe3d730..239d529c5cc522f3865778d99dc88c25ca47ad18 100644 (file)
@@ -838,6 +838,7 @@ struct cli_params {
        int64_t logagno;
        int     loginternal;
        int     lsunit;
+       int     has_warranty;
 
        /* parameters where 0 is not a valid value */
        int64_t agcount;
@@ -2463,6 +2464,68 @@ _("illegal CoW extent size hint %lld, must be less than %u.\n"),
        }
 }
 
+/* Complain if this filesystem is not a supported configuration. */
+static void
+validate_warranty(
+       struct xfs_mount        *mp,
+       struct cli_params       *cli)
+{
+       /* Undocumented option to enable unsupported tiny filesystems. */
+       if (!cli->has_warranty) {
+               printf(
+ _("Filesystems formatted with --yes-i-know-what-i-am-doing are not supported!!\n"));
+               return;
+       }
+
+       /*
+        * fstests has a large number of tests that create tiny filesystems to
+        * perform specific regression and resource depletion tests in a
+        * controlled environment.  Avoid breaking fstests by allowing
+        * unsupported configurations if TEST_DIR, TEST_DEV, and QA_CHECK_FS
+        * are all set.
+        */
+       if (getenv("TEST_DIR") && getenv("TEST_DEV") && getenv("QA_CHECK_FS"))
+               return;
+
+       /*
+        * We don't support filesystems smaller than 300MB anymore.  Tiny
+        * filesystems have never been XFS' design target.  This limit has been
+        * carefully calculated to prevent formatting with a log smaller than
+        * the "realistic" size.
+        *
+        * If the realistic log size is 64MB, there are four AGs, and the log
+        * AG should be at least 1/8 free after formatting, this gives us:
+        *
+        * 64MB * (8 / 7) * 4 = 293MB
+        */
+       if (mp->m_sb.sb_dblocks < MEGABYTES(300, mp->m_sb.sb_blocklog)) {
+               fprintf(stderr,
+ _("Filesystem must be larger than 300MB.\n"));
+               usage();
+       }
+
+       /*
+        * For best performance, we don't allow unrealistically small logs.
+        * See the comment for XFS_MIN_REALISTIC_LOG_BLOCKS.
+        */
+       if (mp->m_sb.sb_logblocks <
+                       XFS_MIN_REALISTIC_LOG_BLOCKS(mp->m_sb.sb_blocklog)) {
+               fprintf(stderr,
+ _("Log size must be at least 64MB.\n"));
+               usage();
+       }
+
+       /*
+        * Filesystems should not have fewer than two AGs, because we need to
+        * have redundant superblocks.
+        */
+       if (mp->m_sb.sb_agcount < 2) {
+               fprintf(stderr,
+ _("Filesystem must have redundant superblocks!\n"));
+               usage();
+       }
+}
+
 /*
  * Validate the configured stripe geometry, or is none is specified, pull
  * the configuration from the underlying device.
@@ -3892,9 +3955,21 @@ main(
        struct cli_params       cli = {
                .xi = &xi,
                .loginternal = 1,
+               .has_warranty   = 1,
        };
        struct mkfs_params      cfg = {};
 
+       struct option           long_options[] = {
+       {
+               .name           = "yes-i-know-what-i-am-doing",
+               .has_arg        = no_argument,
+               .flag           = &cli.has_warranty,
+               .val            = 0,
+       },
+       {NULL, 0, NULL, 0 },
+       };
+       int                     option_index = 0;
+
        /* build time defaults */
        struct mkfs_default_params      dft = {
                .source = _("package build definitions"),
@@ -3953,8 +4028,11 @@ main(
        memcpy(&cli.sb_feat, &dft.sb_feat, sizeof(cli.sb_feat));
        memcpy(&cli.fsx, &dft.fsx, sizeof(cli.fsx));
 
-       while ((c = getopt(argc, argv, "b:c:d:i:l:L:m:n:KNp:qr:s:CfV")) != EOF) {
+       while ((c = getopt_long(argc, argv, "b:c:d:i:l:L:m:n:KNp:qr:s:CfV",
+                                       long_options, &option_index)) != EOF) {
                switch (c) {
+               case 0:
+                       break;
                case 'C':
                case 'f':
                        force_overwrite = 1;
@@ -4092,6 +4170,8 @@ main(
        validate_extsize_hint(mp, &cli);
        validate_cowextsize_hint(mp, &cli);
 
+       validate_warranty(mp, &cli);
+
        /* Print the intended geometry of the fs. */
        if (!quiet || dry_run) {
                struct xfs_fsop_geom    geo;