]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blobdiff - mkfs/xfs_mkfs.c
xfs_scrub: remove moveon from progress report helpers
[thirdparty/xfsprogs-dev.git] / mkfs / xfs_mkfs.c
index c4de836076a0ac42eb203baeb867bac7863d6742..18338a61476913a443f1f43f025a484925ce0e49 100644 (file)
@@ -1,27 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Copyright (c) 2000-2005 Silicon Graphics, Inc.
  * All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write the Free Software Foundation,
- * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
-#include "libfrog.h"
+#include "libfrog/util.h"
 #include "libxfs.h"
 #include <ctype.h>
 #include "xfs_multidisk.h"
 #include "libxcmd.h"
-
-
+#include "libfrog/fsgeom.h"
+#include "libfrog/topology.h"
 
 #define TERABYTES(count, blog) ((uint64_t)(count) << (40 - (blog)))
 #define GIGABYTES(count, blog) ((uint64_t)(count) << (30 - (blog)))
  * XXX: The configured block and sector sizes are defined as global variables so
  * that they don't need to be passed to getnum/cvtnum().
  */
-unsigned int           blocksize;
-unsigned int           sectorsize;
+static unsigned int            blocksize;
+static unsigned int            sectorsize;
+
+/*
+ * Enums for each CLI parameter type are declared first so we can calculate the
+ * maximum array size needed to hold them automatically.
+ */
+enum {
+       B_SIZE = 0,
+       B_MAX_OPTS,
+};
+
+enum {
+       D_AGCOUNT = 0,
+       D_FILE,
+       D_NAME,
+       D_SIZE,
+       D_SUNIT,
+       D_SWIDTH,
+       D_AGSIZE,
+       D_SU,
+       D_SW,
+       D_SECTSIZE,
+       D_NOALIGN,
+       D_RTINHERIT,
+       D_PROJINHERIT,
+       D_EXTSZINHERIT,
+       D_COWEXTSIZE,
+       D_MAX_OPTS,
+};
+
+enum {
+       I_ALIGN = 0,
+       I_MAXPCT,
+       I_PERBLOCK,
+       I_SIZE,
+       I_ATTR,
+       I_PROJID32BIT,
+       I_SPINODES,
+       I_MAX_OPTS,
+};
+
+enum {
+       L_AGNUM = 0,
+       L_INTERNAL,
+       L_SIZE,
+       L_VERSION,
+       L_SUNIT,
+       L_SU,
+       L_DEV,
+       L_SECTSIZE,
+       L_FILE,
+       L_NAME,
+       L_LAZYSBCNTR,
+       L_MAX_OPTS,
+};
+
+enum {
+       N_SIZE = 0,
+       N_VERSION,
+       N_FTYPE,
+       N_MAX_OPTS,
+};
+
+enum {
+       R_EXTSIZE = 0,
+       R_SIZE,
+       R_DEV,
+       R_FILE,
+       R_NAME,
+       R_NOALIGN,
+       R_MAX_OPTS,
+};
+
+enum {
+       S_SIZE = 0,
+       S_SECTSIZE,
+       S_MAX_OPTS,
+};
+
+enum {
+       M_CRC = 0,
+       M_FINOBT,
+       M_UUID,
+       M_RMAPBT,
+       M_REFLINK,
+       M_MAX_OPTS,
+};
+
+/* Just define the max options array size manually right now */
+#define MAX_SUBOPTS    D_MAX_OPTS
 
-#define MAX_SUBOPTS    17
 #define SUBOPT_NEEDS_VAL       (-1LL)
 #define MAX_CONFLICTS  8
 #define LAST_CONFLICT  (-1)
@@ -125,35 +201,33 @@ struct opt_params {
                bool            str_seen;
                bool            convert;
                bool            is_power_2;
-               int             conflicts[MAX_CONFLICTS];
+               struct _conflict {
+                       struct opt_params       *opts;
+                       int                     subopt;
+               }               conflicts[MAX_CONFLICTS];
                long long       minval;
                long long       maxval;
                long long       defaultval;
        }               subopt_params[MAX_SUBOPTS];
 };
 
-struct opt_params bopts = {
+/*
+ * The two dimensional conflict array requires some initialisations to know
+ * about tables that haven't yet been defined. Work around this ordering
+ * issue with extern definitions here.
+ */
+static struct opt_params sopts;
+
+static struct opt_params bopts = {
        .name = 'b',
        .subopts = {
-#define        B_LOG           0
-               "log",
-#define        B_SIZE          1
-               "size",
-               NULL
+               [B_SIZE] = "size",
        },
        .subopt_params = {
-               { .index = B_LOG,
-                 .conflicts = { B_SIZE,
-                                LAST_CONFLICT },
-                 .minval = XFS_MIN_BLOCKSIZE_LOG,
-                 .maxval = XFS_MAX_BLOCKSIZE_LOG,
-                 .defaultval = SUBOPT_NEEDS_VAL,
-               },
                { .index = B_SIZE,
                  .convert = true,
                  .is_power_2 = true,
-                 .conflicts = { B_LOG,
-                                LAST_CONFLICT },
+                 .conflicts = { { NULL, LAST_CONFLICT } },
                  .minval = XFS_MIN_BLOCKSIZE,
                  .maxval = XFS_MAX_BLOCKSIZE,
                  .defaultval = SUBOPT_NEEDS_VAL,
@@ -161,123 +235,99 @@ struct opt_params bopts = {
        },
 };
 
-struct opt_params dopts = {
+static struct opt_params dopts = {
        .name = 'd',
        .subopts = {
-#define        D_AGCOUNT       0
-               "agcount",
-#define        D_FILE          1
-               "file",
-#define        D_NAME          2
-               "name",
-#define        D_SIZE          3
-               "size",
-#define D_SUNIT                4
-               "sunit",
-#define D_SWIDTH       5
-               "swidth",
-#define D_AGSIZE       6
-               "agsize",
-#define D_SU           7
-               "su",
-#define D_SW           8
-               "sw",
-#define D_SECTLOG      9
-               "sectlog",
-#define D_SECTSIZE     10
-               "sectsize",
-#define D_NOALIGN      11
-               "noalign",
-#define D_RTINHERIT    12
-               "rtinherit",
-#define D_PROJINHERIT  13
-               "projinherit",
-#define D_EXTSZINHERIT 14
-               "extszinherit",
-#define D_COWEXTSIZE   15
-               "cowextsize",
-               NULL
+               [D_AGCOUNT] = "agcount",
+               [D_FILE] = "file",
+               [D_NAME] = "name",
+               [D_SIZE] = "size",
+               [D_SUNIT] = "sunit",
+               [D_SWIDTH] = "swidth",
+               [D_AGSIZE] = "agsize",
+               [D_SU] = "su",
+               [D_SW] = "sw",
+               [D_SECTSIZE] = "sectsize",
+               [D_NOALIGN] = "noalign",
+               [D_RTINHERIT] = "rtinherit",
+               [D_PROJINHERIT] = "projinherit",
+               [D_EXTSZINHERIT] = "extszinherit",
+               [D_COWEXTSIZE] = "cowextsize",
        },
        .subopt_params = {
                { .index = D_AGCOUNT,
-                 .conflicts = { D_AGSIZE,
-                                LAST_CONFLICT },
+                 .conflicts = { { &dopts, D_AGSIZE },
+                                { NULL, LAST_CONFLICT } },
                  .minval = 1,
                  .maxval = XFS_MAX_AGNUMBER,
                  .defaultval = SUBOPT_NEEDS_VAL,
                },
                { .index = D_FILE,
-                 .conflicts = { LAST_CONFLICT },
+                 .conflicts = { { NULL, LAST_CONFLICT } },
                  .minval = 0,
                  .maxval = 1,
                  .defaultval = 1,
                },
                { .index = D_NAME,
-                 .conflicts = { LAST_CONFLICT },
+                 .conflicts = { { NULL, LAST_CONFLICT } },
                  .defaultval = SUBOPT_NEEDS_VAL,
                },
                { .index = D_SIZE,
-                 .conflicts = { LAST_CONFLICT },
+                 .conflicts = { { NULL, LAST_CONFLICT } },
                  .convert = true,
                  .minval = XFS_AG_MIN_BYTES,
                  .maxval = LLONG_MAX,
                  .defaultval = SUBOPT_NEEDS_VAL,
                },
                { .index = D_SUNIT,
-                 .conflicts = { D_NOALIGN,
-                                D_SU,
-                                D_SW,
-                                LAST_CONFLICT },
+                 .conflicts = { { &dopts, D_NOALIGN },
+                                { &dopts, D_SU },
+                                { &dopts, D_SW },
+                                { NULL, LAST_CONFLICT } },
                  .minval = 0,
                  .maxval = UINT_MAX,
                  .defaultval = SUBOPT_NEEDS_VAL,
                },
                { .index = D_SWIDTH,
-                 .conflicts = { D_NOALIGN,
-                                D_SU,
-                                D_SW,
-                                LAST_CONFLICT },
+                 .conflicts = { { &dopts, D_NOALIGN },
+                                { &dopts, D_SU },
+                                { &dopts, D_SW },
+                                { NULL, LAST_CONFLICT } },
                  .minval = 0,
                  .maxval = UINT_MAX,
                  .defaultval = SUBOPT_NEEDS_VAL,
                },
                { .index = D_AGSIZE,
-                 .conflicts = { D_AGCOUNT,
-                                LAST_CONFLICT },
+                 .conflicts = { { &dopts, D_AGCOUNT },
+                                { NULL, LAST_CONFLICT } },
                  .convert = true,
                  .minval = XFS_AG_MIN_BYTES,
                  .maxval = XFS_AG_MAX_BYTES,
                  .defaultval = SUBOPT_NEEDS_VAL,
                },
                { .index = D_SU,
-                 .conflicts = { D_NOALIGN,
-                                D_SUNIT,
-                                D_SWIDTH,
-                                LAST_CONFLICT },
+                 .conflicts = { { &dopts, D_NOALIGN },
+                                { &dopts, D_SUNIT },
+                                { &dopts, D_SWIDTH },
+                                { NULL, LAST_CONFLICT } },
                  .convert = true,
                  .minval = 0,
                  .maxval = UINT_MAX,
                  .defaultval = SUBOPT_NEEDS_VAL,
                },
                { .index = D_SW,
-                 .conflicts = { D_NOALIGN,
-                                D_SUNIT,
-                                D_SWIDTH,
-                                LAST_CONFLICT },
+                 .conflicts = { { &dopts, D_NOALIGN },
+                                { &dopts, D_SUNIT },
+                                { &dopts, D_SWIDTH },
+                                { NULL, LAST_CONFLICT } },
                  .minval = 0,
                  .maxval = UINT_MAX,
                  .defaultval = SUBOPT_NEEDS_VAL,
                },
-               { .index = D_SECTLOG,
-                 .conflicts = { D_SECTSIZE,
-                                LAST_CONFLICT },
-                 .minval = XFS_MIN_SECTORSIZE_LOG,
-                 .maxval = XFS_MAX_SECTORSIZE_LOG,
-                 .defaultval = SUBOPT_NEEDS_VAL,
-               },
                { .index = D_SECTSIZE,
-                 .conflicts = { D_SECTLOG,
-                                LAST_CONFLICT },
+                 .conflicts = { { &sopts, S_SIZE },
+                                { &sopts, S_SECTSIZE },
+                                { NULL, LAST_CONFLICT } },
                  .convert = true,
                  .is_power_2 = true,
                  .minval = XFS_MIN_SECTORSIZE,
@@ -285,35 +335,35 @@ struct opt_params dopts = {
                  .defaultval = SUBOPT_NEEDS_VAL,
                },
                { .index = D_NOALIGN,
-                 .conflicts = { D_SU,
-                                D_SW,
-                                D_SUNIT,
-                                D_SWIDTH,
-                                LAST_CONFLICT },
+                 .conflicts = { { &dopts, D_SU },
+                                { &dopts, D_SW },
+                                { &dopts, D_SUNIT },
+                                { &dopts, D_SWIDTH },
+                                { NULL, LAST_CONFLICT } },
                  .minval = 0,
                  .maxval = 1,
                  .defaultval = 1,
                },
                { .index = D_RTINHERIT,
-                 .conflicts = { LAST_CONFLICT },
+                 .conflicts = { { NULL, LAST_CONFLICT } },
                  .minval = 1,
                  .maxval = 1,
                  .defaultval = 1,
                },
                { .index = D_PROJINHERIT,
-                 .conflicts = { LAST_CONFLICT },
+                 .conflicts = { { NULL, LAST_CONFLICT } },
                  .minval = 0,
                  .maxval = UINT_MAX,
                  .defaultval = SUBOPT_NEEDS_VAL,
                },
                { .index = D_EXTSZINHERIT,
-                 .conflicts = { LAST_CONFLICT },
+                 .conflicts = { { NULL, LAST_CONFLICT } },
                  .minval = 0,
                  .maxval = UINT_MAX,
                  .defaultval = SUBOPT_NEEDS_VAL,
                },
                { .index = D_COWEXTSIZE,
-                 .conflicts = { LAST_CONFLICT },
+                 .conflicts = { { NULL, LAST_CONFLICT } },
                  .minval = 0,
                  .maxval = UINT_MAX,
                  .defaultval = SUBOPT_NEEDS_VAL,
@@ -322,80 +372,60 @@ struct opt_params dopts = {
 };
 
 
-struct opt_params iopts = {
+static struct opt_params iopts = {
        .name = 'i',
        .subopts = {
-#define        I_ALIGN         0
-               "align",
-#define        I_LOG           1
-               "log",
-#define        I_MAXPCT        2
-               "maxpct",
-#define        I_PERBLOCK      3
-               "perblock",
-#define        I_SIZE          4
-               "size",
-#define        I_ATTR          5
-               "attr",
-#define        I_PROJID32BIT   6
-               "projid32bit",
-#define I_SPINODES     7
-               "sparse",
-               NULL
+               [I_ALIGN] = "align",
+               [I_MAXPCT] = "maxpct",
+               [I_PERBLOCK] = "perblock",
+               [I_SIZE] = "size",
+               [I_ATTR] = "attr",
+               [I_PROJID32BIT] = "projid32bit",
+               [I_SPINODES] = "sparse",
        },
        .subopt_params = {
                { .index = I_ALIGN,
-                 .conflicts = { LAST_CONFLICT },
+                 .conflicts = { { NULL, LAST_CONFLICT } },
                  .minval = 0,
                  .maxval = 1,
                  .defaultval = 1,
                },
-               { .index = I_LOG,
-                 .conflicts = { I_PERBLOCK,
-                                I_SIZE,
-                                LAST_CONFLICT },
-                 .minval = XFS_DINODE_MIN_LOG,
-                 .maxval = XFS_DINODE_MAX_LOG,
-                 .defaultval = SUBOPT_NEEDS_VAL,
-               },
                { .index = I_MAXPCT,
-                 .conflicts = { LAST_CONFLICT },
+                 .conflicts = { { NULL, LAST_CONFLICT } },
                  .minval = 0,
                  .maxval = 100,
                  .defaultval = SUBOPT_NEEDS_VAL,
                },
                { .index = I_PERBLOCK,
-                 .conflicts = { I_LOG,
-                                I_SIZE,
-                                LAST_CONFLICT },
+                 .conflicts = { { &iopts, I_SIZE },
+                                { NULL, LAST_CONFLICT } },
                  .is_power_2 = true,
                  .minval = XFS_MIN_INODE_PERBLOCK,
                  .maxval = XFS_MAX_BLOCKSIZE / XFS_DINODE_MIN_SIZE,
                  .defaultval = SUBOPT_NEEDS_VAL,
                },
                { .index = I_SIZE,
-                 .conflicts = { I_PERBLOCK,
-                                I_LOG,
-                                LAST_CONFLICT },
+                 .conflicts = { { &iopts, I_PERBLOCK },
+                                { NULL, LAST_CONFLICT } },
                  .is_power_2 = true,
                  .minval = XFS_DINODE_MIN_SIZE,
                  .maxval = XFS_DINODE_MAX_SIZE,
                  .defaultval = SUBOPT_NEEDS_VAL,
                },
                { .index = I_ATTR,
-                 .conflicts = { LAST_CONFLICT },
+                 .conflicts = { { NULL, LAST_CONFLICT } },
                  .minval = 0,
                  .maxval = 2,
                  .defaultval = SUBOPT_NEEDS_VAL,
                },
                { .index = I_PROJID32BIT,
-                 .conflicts = { LAST_CONFLICT },
+                 .conflicts = { { NULL, LAST_CONFLICT } },
                  .minval = 0,
                  .maxval = 1,
                  .defaultval = 1,
                },
                { .index = I_SPINODES,
-                 .conflicts = { LAST_CONFLICT },
+                 .conflicts = { { NULL, LAST_CONFLICT } },
                  .minval = 0,
                  .maxval = 1,
                  .defaultval = 1,
@@ -403,99 +433,76 @@ struct opt_params iopts = {
        },
 };
 
-struct opt_params lopts = {
+static struct opt_params lopts = {
        .name = 'l',
        .subopts = {
-#define        L_AGNUM         0
-               "agnum",
-#define        L_INTERNAL      1
-               "internal",
-#define        L_SIZE          2
-               "size",
-#define L_VERSION      3
-               "version",
-#define L_SUNIT                4
-               "sunit",
-#define L_SU           5
-               "su",
-#define L_DEV          6
-               "logdev",
-#define        L_SECTLOG       7
-               "sectlog",
-#define        L_SECTSIZE      8
-               "sectsize",
-#define        L_FILE          9
-               "file",
-#define        L_NAME          10
-               "name",
-#define        L_LAZYSBCNTR    11
-               "lazy-count",
-               NULL
+               [L_AGNUM] = "agnum",
+               [L_INTERNAL] = "internal",
+               [L_SIZE] = "size",
+               [L_VERSION] = "version",
+               [L_SUNIT] = "sunit",
+               [L_SU] = "su",
+               [L_DEV] = "logdev",
+               [L_SECTSIZE] = "sectsize",
+               [L_FILE] = "file",
+               [L_NAME] = "name",
+               [L_LAZYSBCNTR] = "lazy-count",
        },
        .subopt_params = {
                { .index = L_AGNUM,
-                 .conflicts = { L_DEV,
-                                LAST_CONFLICT },
+                 .conflicts = { { &lopts, L_DEV },
+                                { NULL, LAST_CONFLICT } },
                  .minval = 0,
                  .maxval = UINT_MAX,
                  .defaultval = SUBOPT_NEEDS_VAL,
                },
                { .index = L_INTERNAL,
-                 .conflicts = { L_FILE,
-                                L_DEV,
-                                L_SECTLOG,
-                                L_SECTSIZE,
-                                LAST_CONFLICT },
+                 .conflicts = { { &lopts, L_FILE },
+                                { &lopts, L_DEV },
+                                { &lopts, L_SECTSIZE },
+                                { NULL, LAST_CONFLICT } },
                  .minval = 0,
                  .maxval = 1,
                  .defaultval = 1,
                },
                { .index = L_SIZE,
-                 .conflicts = { LAST_CONFLICT },
+                 .conflicts = { { NULL, LAST_CONFLICT } },
                  .convert = true,
                  .minval = 2 * 1024 * 1024LL,  /* XXX: XFS_MIN_LOG_BYTES */
                  .maxval = XFS_MAX_LOG_BYTES,
                  .defaultval = SUBOPT_NEEDS_VAL,
                },
                { .index = L_VERSION,
-                 .conflicts = { LAST_CONFLICT },
+                 .conflicts = { { NULL, LAST_CONFLICT } },
                  .minval = 1,
                  .maxval = 2,
                  .defaultval = SUBOPT_NEEDS_VAL,
                },
                { .index = L_SUNIT,
-                 .conflicts = { L_SU,
-                                LAST_CONFLICT },
+                 .conflicts = { { &lopts, L_SU },
+                                { NULL, LAST_CONFLICT } },
                  .minval = 1,
                  .maxval = BTOBB(XLOG_MAX_RECORD_BSIZE),
                  .defaultval = SUBOPT_NEEDS_VAL,
                },
                { .index = L_SU,
-                 .conflicts = { L_SUNIT,
-                                LAST_CONFLICT },
+                 .conflicts = { { &lopts, L_SUNIT },
+                                { NULL, LAST_CONFLICT } },
                  .convert = true,
                  .minval = BBTOB(1),
                  .maxval = XLOG_MAX_RECORD_BSIZE,
                  .defaultval = SUBOPT_NEEDS_VAL,
                },
                { .index = L_DEV,
-                 .conflicts = { L_AGNUM,
-                                L_INTERNAL,
-                                LAST_CONFLICT },
-                 .defaultval = SUBOPT_NEEDS_VAL,
-               },
-               { .index = L_SECTLOG,
-                 .conflicts = { L_SECTSIZE,
-                                L_INTERNAL,
-                                LAST_CONFLICT },
-                 .minval = XFS_MIN_SECTORSIZE_LOG,
-                 .maxval = XFS_MAX_SECTORSIZE_LOG,
+                 .conflicts = { { &lopts, L_AGNUM },
+                                { &lopts, L_NAME },
+                                { &lopts, L_INTERNAL },
+                                { NULL, LAST_CONFLICT } },
                  .defaultval = SUBOPT_NEEDS_VAL,
                },
                { .index = L_SECTSIZE,
-                 .conflicts = { L_SECTLOG,
-                                L_INTERNAL,
-                                LAST_CONFLICT },
+                 .conflicts = { { &lopts, L_INTERNAL },
+                                { NULL, LAST_CONFLICT } },
                  .convert = true,
                  .is_power_2 = true,
                  .minval = XFS_MIN_SECTORSIZE,
@@ -503,20 +510,21 @@ struct opt_params lopts = {
                  .defaultval = SUBOPT_NEEDS_VAL,
                },
                { .index = L_FILE,
-                 .conflicts = { L_INTERNAL,
-                                LAST_CONFLICT },
+                 .conflicts = { { &lopts, L_INTERNAL },
+                                { NULL, LAST_CONFLICT } },
                  .minval = 0,
                  .maxval = 1,
                  .defaultval = 1,
                },
                { .index = L_NAME,
-                 .conflicts = { L_AGNUM,
-                                L_INTERNAL,
-                                LAST_CONFLICT },
+                 .conflicts = { { &lopts, L_AGNUM },
+                                { &lopts, L_DEV },
+                                { &lopts, L_INTERNAL },
+                                { NULL, LAST_CONFLICT } },
                  .defaultval = SUBOPT_NEEDS_VAL,
                },
                { .index = L_LAZYSBCNTR,
-                 .conflicts = { LAST_CONFLICT },
+                 .conflicts = { { NULL, LAST_CONFLICT } },
                  .minval = 0,
                  .maxval = 1,
                  .defaultval = 1,
@@ -524,30 +532,16 @@ struct opt_params lopts = {
        },
 };
 
-struct opt_params nopts = {
+static struct opt_params nopts = {
        .name = 'n',
        .subopts = {
-#define        N_LOG           0
-               "log",
-#define        N_SIZE          1
-               "size",
-#define        N_VERSION       2
-               "version",
-#define        N_FTYPE         3
-               "ftype",
-       NULL,
+               [N_SIZE] = "size",
+               [N_VERSION] = "version",
+               [N_FTYPE] = "ftype",
        },
        .subopt_params = {
-               { .index = N_LOG,
-                 .conflicts = { N_SIZE,
-                                LAST_CONFLICT },
-                 .minval = XFS_MIN_REC_DIRSIZE,
-                 .maxval = XFS_MAX_BLOCKSIZE_LOG,
-                 .defaultval = SUBOPT_NEEDS_VAL,
-               },
                { .index = N_SIZE,
-                 .conflicts = { N_LOG,
-                                LAST_CONFLICT },
+                 .conflicts = { { NULL, LAST_CONFLICT } },
                  .convert = true,
                  .is_power_2 = true,
                  .minval = 1 << XFS_MIN_REC_DIRSIZE,
@@ -555,13 +549,13 @@ struct opt_params nopts = {
                  .defaultval = SUBOPT_NEEDS_VAL,
                },
                { .index = N_VERSION,
-                 .conflicts = { LAST_CONFLICT },
+                 .conflicts = { { NULL, LAST_CONFLICT } },
                  .minval = 2,
                  .maxval = 2,
                  .defaultval = SUBOPT_NEEDS_VAL,
                },
                { .index = N_FTYPE,
-                 .conflicts = { LAST_CONFLICT },
+                 .conflicts = { { NULL, LAST_CONFLICT } },
                  .minval = 0,
                  .maxval = 1,
                  .defaultval = 1,
@@ -569,95 +563,67 @@ struct opt_params nopts = {
        },
 };
 
-struct opt_params ropts = {
+static struct opt_params ropts = {
        .name = 'r',
        .subopts = {
-#define        R_EXTSIZE       0
-               "extsize",
-#define        R_SIZE          1
-               "size",
-#define        R_DEV           2
-               "rtdev",
-#define        R_FILE          3
-               "file",
-#define        R_NAME          4
-               "name",
-#define R_NOALIGN      5
-               "noalign",
-               NULL
+               [R_EXTSIZE] = "extsize",
+               [R_SIZE] = "size",
+               [R_DEV] = "rtdev",
+               [R_FILE] = "file",
+               [R_NAME] = "name",
+               [R_NOALIGN] = "noalign",
        },
        .subopt_params = {
                { .index = R_EXTSIZE,
-                 .conflicts = { LAST_CONFLICT },
+                 .conflicts = { { NULL, LAST_CONFLICT } },
                  .convert = true,
                  .minval = XFS_MIN_RTEXTSIZE,
                  .maxval = XFS_MAX_RTEXTSIZE,
                  .defaultval = SUBOPT_NEEDS_VAL,
                },
                { .index = R_SIZE,
-                 .conflicts = { LAST_CONFLICT },
+                 .conflicts = { { NULL, LAST_CONFLICT } },
                  .convert = true,
                  .minval = 0,
                  .maxval = LLONG_MAX,
                  .defaultval = SUBOPT_NEEDS_VAL,
                },
                { .index = R_DEV,
-                 .conflicts = { LAST_CONFLICT },
+                 .conflicts = { { &ropts, R_NAME },
+                                { NULL, LAST_CONFLICT } },
                  .defaultval = SUBOPT_NEEDS_VAL,
                },
                { .index = R_FILE,
                  .minval = 0,
                  .maxval = 1,
                  .defaultval = 1,
-                 .conflicts = { LAST_CONFLICT },
+                 .conflicts = { { NULL, LAST_CONFLICT } },
                },
                { .index = R_NAME,
-                 .conflicts = { LAST_CONFLICT },
+                 .conflicts = { { &ropts, R_DEV },
+                                { NULL, LAST_CONFLICT } },
                  .defaultval = SUBOPT_NEEDS_VAL,
                },
                { .index = R_NOALIGN,
                  .minval = 0,
                  .maxval = 1,
                  .defaultval = 1,
-                 .conflicts = { LAST_CONFLICT },
+                 .conflicts = { { NULL, LAST_CONFLICT } },
                },
        },
 };
 
-struct opt_params sopts = {
+static struct opt_params sopts = {
        .name = 's',
        .subopts = {
-#define        S_LOG           0
-               "log",
-#define        S_SECTLOG       1
-               "sectlog",
-#define        S_SIZE          2
-               "size",
-#define        S_SECTSIZE      3
-               "sectsize",
-               NULL
+               [S_SIZE] = "size",
+               [S_SECTSIZE] = "sectsize",
        },
        .subopt_params = {
-               { .index = S_LOG,
-                 .conflicts = { S_SIZE,
-                                S_SECTSIZE,
-                                LAST_CONFLICT },
-                 .minval = XFS_MIN_SECTORSIZE_LOG,
-                 .maxval = XFS_MAX_SECTORSIZE_LOG,
-                 .defaultval = SUBOPT_NEEDS_VAL,
-               },
-               { .index = S_SECTLOG,
-                 .conflicts = { S_SIZE,
-                                S_SECTSIZE,
-                                LAST_CONFLICT },
-                 .minval = XFS_MIN_SECTORSIZE_LOG,
-                 .maxval = XFS_MAX_SECTORSIZE_LOG,
-                 .defaultval = SUBOPT_NEEDS_VAL,
-               },
                { .index = S_SIZE,
-                 .conflicts = { S_LOG,
-                                S_SECTLOG,
-                                LAST_CONFLICT },
+                 .conflicts = { { &sopts, S_SECTSIZE },
+                                { &dopts, D_SECTSIZE },
+                                { NULL, LAST_CONFLICT } },
                  .convert = true,
                  .is_power_2 = true,
                  .minval = XFS_MIN_SECTORSIZE,
@@ -665,9 +631,9 @@ struct opt_params sopts = {
                  .defaultval = SUBOPT_NEEDS_VAL,
                },
                { .index = S_SECTSIZE,
-                 .conflicts = { S_LOG,
-                                S_SECTLOG,
-                                LAST_CONFLICT },
+                 .conflicts = { { &sopts, S_SIZE },
+                                { &dopts, D_SECTSIZE },
+                                { NULL, LAST_CONFLICT } },
                  .convert = true,
                  .is_power_2 = true,
                  .minval = XFS_MIN_SECTORSIZE,
@@ -677,46 +643,40 @@ struct opt_params sopts = {
        },
 };
 
-struct opt_params mopts = {
+static struct opt_params mopts = {
        .name = 'm',
        .subopts = {
-#define        M_CRC           0
-               "crc",
-#define M_FINOBT       1
-               "finobt",
-#define M_UUID         2
-               "uuid",
-#define M_RMAPBT       3
-               "rmapbt",
-#define M_REFLINK      4
-               "reflink",
-               NULL
+               [M_CRC] = "crc",
+               [M_FINOBT] = "finobt",
+               [M_UUID] = "uuid",
+               [M_RMAPBT] = "rmapbt",
+               [M_REFLINK] = "reflink",
        },
        .subopt_params = {
                { .index = M_CRC,
-                 .conflicts = { LAST_CONFLICT },
+                 .conflicts = { { NULL, LAST_CONFLICT } },
                  .minval = 0,
                  .maxval = 1,
                  .defaultval = 1,
                },
                { .index = M_FINOBT,
-                 .conflicts = { LAST_CONFLICT },
+                 .conflicts = { { NULL, LAST_CONFLICT } },
                  .minval = 0,
                  .maxval = 1,
                  .defaultval = 1,
                },
                { .index = M_UUID,
-                 .conflicts = { LAST_CONFLICT },
+                 .conflicts = { { NULL, LAST_CONFLICT } },
                  .defaultval = SUBOPT_NEEDS_VAL,
                },
                { .index = M_RMAPBT,
-                 .conflicts = { LAST_CONFLICT },
+                 .conflicts = { { NULL, LAST_CONFLICT } },
                  .minval = 0,
                  .maxval = 1,
                  .defaultval = 1,
                },
                { .index = M_REFLINK,
-                 .conflicts = { LAST_CONFLICT },
+                 .conflicts = { { NULL, LAST_CONFLICT } },
                  .minval = 0,
                  .maxval = 1,
                  .defaultval = 1,
@@ -799,7 +759,6 @@ struct cli_params {
 
        /* parameters where 0 is not a valid value */
        int64_t agcount;
-       int     dirblocklog;
        int     inodesize;
        int     inopblock;
        int     imaxpct;
@@ -893,25 +852,24 @@ static void __attribute__((noreturn))
 usage( void )
 {
        fprintf(stderr, _("Usage: %s\n\
-/* blocksize */                [-b log=n|size=num]\n\
+/* blocksize */                [-b size=num]\n\
 /* metadata */         [-m crc=0|1,finobt=0|1,uuid=xxx,rmapbt=0|1,reflink=0|1]\n\
 /* data subvol */      [-d agcount=n,agsize=n,file,name=xxx,size=num,\n\
                            (sunit=value,swidth=value|su=num,sw=num|noalign),\n\
-                           sectlog=n|sectsize=num\n\
+                           sectsize=num\n\
 /* force overwrite */  [-f]\n\
-/* inode size */       [-i log=n|perblock=n|size=num,maxpct=n,attr=0|1|2,\n\
+/* inode size */       [-i perblock=n|size=num,maxpct=n,attr=0|1|2,\n\
                            projid32bit=0|1,sparse=0|1]\n\
 /* no discard */       [-K]\n\
 /* log subvol */       [-l agnum=n,internal,size=num,logdev=xxx,version=n\n\
-                           sunit=value|su=num,sectlog=n|sectsize=num,\n\
-                           lazy-count=0|1]\n\
+                           sunit=value|su=num,sectsize=num,lazy-count=0|1]\n\
 /* label */            [-L label (maximum 12 characters)]\n\
-/* naming */           [-n log=n|size=num,version=2|ci,ftype=0|1]\n\
+/* naming */           [-n size=num,version=2|ci,ftype=0|1]\n\
 /* no-op info only */  [-N]\n\
 /* prototype file */   [-p fname]\n\
 /* quiet */            [-q]\n\
 /* realtime subvol */  [-r extsize=num,size=num,rtdev=xxx]\n\
-/* sectorsize */       [-s log=n|size=num]\n\
+/* sectorsize */       [-s size=num]\n\
 /* version */          [-V]\n\
                        devicename\n\
 <devicename> is required unless -d name=xxx is given.\n\
@@ -924,13 +882,14 @@ usage( void )
 
 static void
 conflict(
-       char            opt,
-       const char      *tab[],
-       int             oldidx,
-       int             newidx)
+       struct opt_params       *opts,
+       int                     option,
+       struct opt_params       *con_opts,
+       int                     conflict)
 {
        fprintf(stderr, _("Cannot specify both -%c %s and -%c %s\n"),
-               opt, tab[oldidx], opt, tab[newidx]);
+                       con_opts->name, con_opts->subopts[conflict],
+                       opts->name, opts->subopts[option]);
        usage();
 }
 
@@ -940,7 +899,7 @@ illegal(
        const char      *value,
        const char      *opt)
 {
-       fprintf(stderr, _("Illegal value %s for -%s option\n"), value, opt);
+       fprintf(stderr, _("Invalid value %s for -%s option\n"), value, opt);
        usage();
 }
 
@@ -1053,7 +1012,6 @@ check_device_type(
        bool            no_size,
        bool            no_name,
        int             *create,
-       bool            force_overwrite,
        const char      *optname)
 {
        struct stat statbuf;
@@ -1084,13 +1042,6 @@ check_device_type(
                return;
        }
 
-       if (!force_overwrite && check_overwrite(name)) {
-               fprintf(stderr,
-       _("%s: Use the -f option to force overwrite.\n"),
-                       progname);
-               exit(1);
-       }
-
        /*
         * We only want to completely truncate and recreate an existing file if
         * we were specifically told it was a file. Set the create flag only in
@@ -1120,6 +1071,20 @@ check_device_type(
        usage();
 }
 
+static void
+validate_overwrite(
+       const char      *name,
+       bool            force_overwrite)
+{
+       if (!force_overwrite && check_overwrite(name)) {
+               fprintf(stderr,
+       _("%s: Use the -f option to force overwrite.\n"),
+                       progname);
+               exit(1);
+       }
+
+}
+
 static void
 validate_ag_geometry(
        int             blocklog,
@@ -1296,9 +1261,9 @@ illegal_option(
        const char              *reason)
 {
        fprintf(stderr,
-               _("Illegal value %s for -%c %s option. %s\n"),
+               _("Invalid value %s for -%c %s option. %s\n"),
                value, opts->name, opts->subopts[index],
-               reason ? reason : "");
+               reason);
        usage();
 }
 
@@ -1341,14 +1306,13 @@ check_opt(
 
        /* check for conflicts with the option */
        for (i = 0; i < MAX_CONFLICTS; i++) {
-               int conflict_opt = sp->conflicts[i];
+               struct _conflict *con = &sp->conflicts[i];
 
-               if (conflict_opt == LAST_CONFLICT)
+               if (con->subopt == LAST_CONFLICT)
                        break;
-               if (opts->subopt_params[conflict_opt].seen ||
-                   opts->subopt_params[conflict_opt].str_seen)
-                       conflict(opts->name, opts->subopts,
-                                conflict_opt, index);
+               if (con->opts->subopt_params[con->subopt].seen ||
+                   con->opts->subopt_params[con->subopt].str_seen)
+                       conflict(opts, index, con->opts, con->subopt);
        }
 }
 
@@ -1390,18 +1354,20 @@ getnum(
 
                c = strtoll(str, &str_end, 0);
                if (c == 0 && str_end == str)
-                       illegal_option(str, opts, index, NULL);
+                       illegal_option(str, opts, index,
+                                       _("Value not recognized as number."));
                if (*str_end != '\0')
-                       illegal_option(str, opts, index, NULL);
+                       illegal_option(str, opts, index,
+                                       _("Unit suffixes are not allowed."));
        }
 
        /* Validity check the result. */
        if (c < sp->minval)
-               illegal_option(str, opts, index, _("value is too small"));
+               illegal_option(str, opts, index, _("Value is too small."));
        else if (c > sp->maxval)
-               illegal_option(str, opts, index, _("value is too large"));
+               illegal_option(str, opts, index, _("Value is too large."));
        if (sp->is_power_2 && !ispow2(c))
-               illegal_option(str, opts, index, _("value must be a power of 2"));
+               illegal_option(str, opts, index, _("Value must be a power of 2."));
        return c;
 }
 
@@ -1432,15 +1398,9 @@ block_opts_parser(
        char                    *value,
        struct cli_params       *cli)
 {
-       int                     blocklog;
-
        switch (subopt) {
-       case B_LOG:
-               blocklog = getnum(value, opts, B_LOG);
-               cli->blocksize = 1 << blocklog;
-               break;
        case B_SIZE:
-               cli->blocksize = getnum(value, opts, B_SIZE);
+               cli->blocksize = getnum(value, opts, subopt);
                break;
        default:
                return -EINVAL;
@@ -1455,64 +1415,54 @@ data_opts_parser(
        char                    *value,
        struct cli_params       *cli)
 {
-       int                     sectorlog;
-
        switch (subopt) {
        case D_AGCOUNT:
-               cli->agcount = getnum(value, opts, D_AGCOUNT);
+               cli->agcount = getnum(value, opts, subopt);
                break;
        case D_AGSIZE:
-               cli->agsize = getstr(value, opts, D_AGSIZE);
+               cli->agsize = getstr(value, opts, subopt);
                break;
        case D_FILE:
-               cli->xi->disfile = getnum(value, opts, D_FILE);
+               cli->xi->disfile = getnum(value, opts, subopt);
                break;
        case D_NAME:
-               cli->xi->dname = getstr(value, opts, D_NAME);
+               cli->xi->dname = getstr(value, opts, subopt);
                break;
        case D_SIZE:
-               cli->dsize = getstr(value, opts, D_SIZE);
+               cli->dsize = getstr(value, opts, subopt);
                break;
        case D_SUNIT:
-               cli->dsunit = getnum(value, opts, D_SUNIT);
+               cli->dsunit = getnum(value, opts, subopt);
                break;
        case D_SWIDTH:
-               cli->dswidth = getnum(value, opts, D_SWIDTH);
+               cli->dswidth = getnum(value, opts, subopt);
                break;
        case D_SU:
-               cli->dsu = getstr(value, opts, D_SU);
+               cli->dsu = getstr(value, opts, subopt);
                break;
        case D_SW:
-               cli->dsw = getnum(value, opts, D_SW);
+               cli->dsw = getnum(value, opts, subopt);
                break;
        case D_NOALIGN:
-               cli->sb_feat.nodalign = getnum(value, opts, D_NOALIGN);
-               break;
-       case D_SECTLOG:
-               if (cli->sectorsize)
-                       conflict('d', opts->subopts, D_SECTSIZE, D_SECTLOG);
-               sectorlog = getnum(value, opts, D_SECTLOG);
-               cli->sectorsize = 1 << sectorlog;
+               cli->sb_feat.nodalign = getnum(value, opts, subopt);
                break;
        case D_SECTSIZE:
-               if (cli->sectorsize)
-                       conflict('d', opts->subopts, D_SECTSIZE, D_SECTLOG);
-               cli->sectorsize = getnum(value, opts, D_SECTSIZE);
+               cli->sectorsize = getnum(value, opts, subopt);
                break;
        case D_RTINHERIT:
-               if (getnum(value, opts, D_RTINHERIT))
-                       cli->fsx.fsx_xflags |= XFS_DIFLAG_RTINHERIT;
+               if (getnum(value, opts, subopt))
+                       cli->fsx.fsx_xflags |= FS_XFLAG_RTINHERIT;
                break;
        case D_PROJINHERIT:
-               cli->fsx.fsx_projid = getnum(value, opts, D_PROJINHERIT);
-               cli->fsx.fsx_xflags |= XFS_DIFLAG_PROJINHERIT;
+               cli->fsx.fsx_projid = getnum(value, opts, subopt);
+               cli->fsx.fsx_xflags |= FS_XFLAG_PROJINHERIT;
                break;
        case D_EXTSZINHERIT:
-               cli->fsx.fsx_extsize = getnum(value, opts, D_EXTSZINHERIT);
-               cli->fsx.fsx_xflags |= XFS_DIFLAG_EXTSZINHERIT;
+               cli->fsx.fsx_extsize = getnum(value, opts, subopt);
+               cli->fsx.fsx_xflags |= FS_XFLAG_EXTSZINHERIT;
                break;
        case D_COWEXTSIZE:
-               cli->fsx.fsx_cowextsize = getnum(value, opts, D_COWEXTSIZE);
+               cli->fsx.fsx_cowextsize = getnum(value, opts, subopt);
                cli->fsx.fsx_xflags |= FS_XFLAG_COWEXTSIZE;
                break;
        default:
@@ -1528,33 +1478,27 @@ inode_opts_parser(
        char                    *value,
        struct cli_params       *cli)
 {
-       int                     inodelog;
-
        switch (subopt) {
        case I_ALIGN:
-               cli->sb_feat.inode_align = getnum(value, opts, I_ALIGN);
-               break;
-       case I_LOG:
-               inodelog = getnum(value, opts, I_LOG);
-               cli->inodesize = 1 << inodelog;
+               cli->sb_feat.inode_align = getnum(value, opts, subopt);
                break;
        case I_MAXPCT:
-               cli->imaxpct = getnum(value, opts, I_MAXPCT);
+               cli->imaxpct = getnum(value, opts, subopt);
                break;
        case I_PERBLOCK:
-               cli->inopblock = getnum(value, opts, I_PERBLOCK);
+               cli->inopblock = getnum(value, opts, subopt);
                break;
        case I_SIZE:
-               cli->inodesize = getnum(value, opts, I_SIZE);
+               cli->inodesize = getnum(value, opts, subopt);
                break;
        case I_ATTR:
-               cli->sb_feat.attr_version = getnum(value, opts, I_ATTR);
+               cli->sb_feat.attr_version = getnum(value, opts, subopt);
                break;
        case I_PROJID32BIT:
-               cli->sb_feat.projid32bit = getnum(value, opts, I_PROJID32BIT);
+               cli->sb_feat.projid32bit = getnum(value, opts, subopt);
                break;
        case I_SPINODES:
-               cli->sb_feat.spinodes = getnum(value, opts, I_SPINODES);
+               cli->sb_feat.spinodes = getnum(value, opts, subopt);
                break;
        default:
                return -EINVAL;
@@ -1569,44 +1513,38 @@ log_opts_parser(
        char                    *value,
        struct cli_params       *cli)
 {
-       int                     lsectorlog;
-
        switch (subopt) {
        case L_AGNUM:
-               cli->logagno = getnum(value, opts, L_AGNUM);
+               cli->logagno = getnum(value, opts, subopt);
                break;
        case L_FILE:
-               cli->xi->lisfile = getnum(value, opts, L_FILE);
+               cli->xi->lisfile = getnum(value, opts, subopt);
                break;
        case L_INTERNAL:
-               cli->loginternal = getnum(value, opts, L_INTERNAL);
+               cli->loginternal = getnum(value, opts, subopt);
                break;
        case L_SU:
-               cli->lsu = getstr(value, opts, L_SU);
+               cli->lsu = getstr(value, opts, subopt);
                break;
        case L_SUNIT:
-               cli->lsunit = getnum(value, opts, L_SUNIT);
+               cli->lsunit = getnum(value, opts, subopt);
                break;
        case L_NAME:
        case L_DEV:
-               cli->xi->logname = getstr(value, opts, L_NAME);
+               cli->xi->logname = getstr(value, opts, subopt);
                cli->loginternal = 0;
                break;
        case L_VERSION:
-               cli->sb_feat.log_version = getnum(value, opts, L_VERSION);
+               cli->sb_feat.log_version = getnum(value, opts, subopt);
                break;
        case L_SIZE:
-               cli->logsize = getstr(value, opts, L_SIZE);
-               break;
-       case L_SECTLOG:
-               lsectorlog = getnum(value, opts, L_SECTLOG);
-               cli->lsectorsize = 1 << lsectorlog;
+               cli->logsize = getstr(value, opts, subopt);
                break;
        case L_SECTSIZE:
-               cli->lsectorsize = getnum(value, opts, L_SECTSIZE);
+               cli->lsectorsize = getnum(value, opts, subopt);
                break;
        case L_LAZYSBCNTR:
-               cli->sb_feat.lazy_sb_counters = getnum(value, opts, L_LAZYSBCNTR);
+               cli->sb_feat.lazy_sb_counters = getnum(value, opts, subopt);
                break;
        default:
                return -EINVAL;
@@ -1623,24 +1561,24 @@ meta_opts_parser(
 {
        switch (subopt) {
        case M_CRC:
-               cli->sb_feat.crcs_enabled = getnum(value, opts, M_CRC);
+               cli->sb_feat.crcs_enabled = getnum(value, opts, subopt);
                if (cli->sb_feat.crcs_enabled)
                        cli->sb_feat.dirftype = true;
                break;
        case M_FINOBT:
-               cli->sb_feat.finobt = getnum(value, opts, M_FINOBT);
+               cli->sb_feat.finobt = getnum(value, opts, subopt);
                break;
        case M_UUID:
                if (!value || *value == '\0')
-                       reqval('m', opts->subopts, M_UUID);
+                       reqval('m', opts->subopts, subopt);
                if (platform_uuid_parse(value, &cli->uuid))
                        illegal(value, "m uuid");
                break;
        case M_RMAPBT:
-               cli->sb_feat.rmapbt = getnum(value, opts, M_RMAPBT);
+               cli->sb_feat.rmapbt = getnum(value, opts, subopt);
                break;
        case M_REFLINK:
-               cli->sb_feat.reflink = getnum(value, opts, M_REFLINK);
+               cli->sb_feat.reflink = getnum(value, opts, subopt);
                break;
        default:
                return -EINVAL;
@@ -1656,23 +1594,20 @@ naming_opts_parser(
        struct cli_params       *cli)
 {
        switch (subopt) {
-       case N_LOG:
-               cli->dirblocklog = getnum(value, opts, N_LOG);
-               break;
        case N_SIZE:
-               cli->dirblocksize = getstr(value, opts, N_SIZE);
+               cli->dirblocksize = getstr(value, opts, subopt);
                break;
        case N_VERSION:
-               value = getstr(value, &nopts, N_VERSION);
+               value = getstr(value, &nopts, subopt);
                if (!strcasecmp(value, "ci")) {
                        /* ASCII CI mode */
                        cli->sb_feat.nci = true;
                } else {
-                       cli->sb_feat.dir_version = getnum(value, opts, N_VERSION);
+                       cli->sb_feat.dir_version = getnum(value, opts, subopt);
                }
                break;
        case N_FTYPE:
-               cli->sb_feat.dirftype = getnum(value, opts, N_FTYPE);
+               cli->sb_feat.dirftype = getnum(value, opts, subopt);
                break;
        default:
                return -EINVAL;
@@ -1689,20 +1624,20 @@ rtdev_opts_parser(
 {
        switch (subopt) {
        case R_EXTSIZE:
-               cli->rtextsize = getstr(value, opts, R_EXTSIZE);
+               cli->rtextsize = getstr(value, opts, subopt);
                break;
        case R_FILE:
-               cli->xi->risfile = getnum(value, opts, R_FILE);
+               cli->xi->risfile = getnum(value, opts, subopt);
                break;
        case R_NAME:
        case R_DEV:
-               cli->xi->rtname = getstr(value, opts, R_NAME);
+               cli->xi->rtname = getstr(value, opts, subopt);
                break;
        case R_SIZE:
-               cli->rtsize = getstr(value, opts, R_SIZE);
+               cli->rtsize = getstr(value, opts, subopt);
                break;
        case R_NOALIGN:
-               cli->sb_feat.nortalign = getnum(value, opts, R_NOALIGN);
+               cli->sb_feat.nortalign = getnum(value, opts, subopt);
                break;
        default:
                return -EINVAL;
@@ -1717,22 +1652,10 @@ sector_opts_parser(
        char                    *value,
        struct cli_params       *cli)
 {
-       int                     sectorlog;
-
        switch (subopt) {
-       case S_LOG:
-       case S_SECTLOG:
-               if (cli->sectorsize)
-                       conflict('s', opts->subopts, S_SECTSIZE, S_SECTLOG);
-               sectorlog = getnum(value, opts, S_SECTLOG);
-               cli->sectorsize = 1 << sectorlog;
-               cli->lsectorsize = cli->sectorsize;
-               break;
        case S_SIZE:
        case S_SECTSIZE:
-               if (cli->sectorsize)
-                       conflict('s', opts->subopts, S_SECTLOG, S_SECTSIZE);
-               cli->sectorsize = getnum(value, opts, S_SECTSIZE);
+               cli->sectorsize = getnum(value, opts, subopt);
                cli->lsectorsize = cli->sectorsize;
                break;
        default:
@@ -1741,10 +1664,13 @@ sector_opts_parser(
        return 0;
 }
 
-struct subopts {
+static struct subopts {
        char            opt;
        struct opt_params *opts;
-       int             (*parser)();
+       int             (*parser)(struct opt_params     *opts,
+                                 int                   subopt,
+                                 char                  *value,
+                                 struct cli_params     *cli);
 } subopt_tab[] = {
        { 'b', &bopts, block_opts_parser },
        { 'd', &dopts, data_opts_parser },
@@ -1814,18 +1740,15 @@ validate_sectorsize(
         * files or block devices and set the control parameters correctly.
         */
        check_device_type(dfile, &cli->xi->disfile, !cli->dsize, !dfile,
-                         dry_run ? NULL : &cli->xi->dcreat,
-                         force_overwrite, "d");
+                         dry_run ? NULL : &cli->xi->dcreat, "d");
        if (!cli->loginternal)
                check_device_type(cli->xi->logname, &cli->xi->lisfile,
                                  !cli->logsize, !cli->xi->logname,
-                                 dry_run ? NULL : &cli->xi->lcreat,
-                                 force_overwrite, "l");
+                                 dry_run ? NULL : &cli->xi->lcreat, "l");
        if (cli->xi->rtname)
                check_device_type(cli->xi->rtname, &cli->xi->risfile,
                                  !cli->rtsize, !cli->xi->rtname,
-                                 dry_run ? NULL : &cli->xi->rcreat,
-                                 force_overwrite, "r");
+                                 dry_run ? NULL : &cli->xi->rcreat, "r");
 
        /*
         * Explicitly disable direct IO for image files so we don't error out on
@@ -2010,28 +1933,28 @@ _("Minimum inode size for CRCs is %d bytes\n"),
                /* inodes always aligned */
                if (!cli->sb_feat.inode_align) {
                        fprintf(stderr,
-_("Inodes always aligned for CRC enabled filesytems\n"));
+_("Inodes always aligned for CRC enabled filesystems\n"));
                        usage();
                }
 
                /* lazy sb counters always on */
                if (!cli->sb_feat.lazy_sb_counters) {
                        fprintf(stderr,
-_("Lazy superblock counted always enabled for CRC enabled filesytems\n"));
+_("Lazy superblock counters always enabled for CRC enabled filesystems\n"));
                        usage();
                }
 
                /* version 2 logs always on */
                if (cli->sb_feat.log_version != 2) {
                        fprintf(stderr,
-_("V2 logs always enabled for CRC enabled filesytems\n"));
+_("V2 logs always enabled for CRC enabled filesystems\n"));
                        usage();
                }
 
                /* attr2 always on */
                if (cli->sb_feat.attr_version != 2) {
                        fprintf(stderr,
-_("V2 attribute format always enabled on CRC enabled filesytems\n"));
+_("V2 attribute format always enabled on CRC enabled filesystems\n"));
                        usage();
                }
 
@@ -2039,26 +1962,26 @@ _("V2 attribute format always enabled on CRC enabled filesytems\n"));
                /* attr2 always on */
                if (!cli->sb_feat.projid32bit) {
                        fprintf(stderr,
-_("32 bit Project IDs always enabled on CRC enabled filesytems\n"));
+_("32 bit Project IDs always enabled on CRC enabled filesystems\n"));
                        usage();
                }
 
                /* ftype always on */
                if (!cli->sb_feat.dirftype) {
                        fprintf(stderr,
-_("Directory ftype field always enabled on CRC enabled filesytems\n"));
+_("Directory ftype field always enabled on CRC enabled filesystems\n"));
                        usage();
                }
 
-       } else {
+       } else {        /* !crcs_enabled */
                /*
-                * The kernel doesn't currently support crc=0,finobt=1
-                * filesystems. If crcs are not enabled and the user has not
-                * explicitly turned finobt on, then silently turn it off to
-                * avoid an unnecessary warning.
+                * The kernel doesn't support crc=0,finobt=1 filesystems.
+                * If crcs are not enabled and the user has not explicitly
+                * turned finobt on, then silently turn it off to avoid an
+                * unnecessary warning.
                 * If the user explicitly tried to use crc=0,finobt=1,
                 * then issue an error.
-                * The same is also for sparse inodes.
+                * The same is also true for sparse inodes and reflink.
                 */
                if (cli->sb_feat.finobt && cli_opt_set(&mopts, M_FINOBT)) {
                        fprintf(stderr,
@@ -2067,7 +1990,7 @@ _("finobt not supported without CRC support\n"));
                }
                cli->sb_feat.finobt = false;
 
-               if (cli->sb_feat.spinodes) {
+               if (cli->sb_feat.spinodes && cli_opt_set(&iopts, I_SPINODES)) {
                        fprintf(stderr,
 _("sparse inodes not supported without CRC support\n"));
                        usage();
@@ -2081,7 +2004,7 @@ _("rmapbt not supported without CRC support\n"));
                }
                cli->sb_feat.rmapbt = false;
 
-               if (cli->sb_feat.reflink) {
+               if (cli->sb_feat.reflink && cli_opt_set(&mopts, M_REFLINK)) {
                        fprintf(stderr,
 _("reflink not supported without CRC support\n"));
                        usage();
@@ -2096,6 +2019,13 @@ _("cowextsize not supported without reflink support\n"));
                usage();
        }
 
+       if (cli->sb_feat.reflink && cli->xi->rtname) {
+               fprintf(stderr,
+_("reflink not supported with realtime devices\n"));
+               usage();
+               cli->sb_feat.reflink = false;
+       }
+
        if (cli->sb_feat.rmapbt && cli->xi->rtname) {
                fprintf(stderr,
 _("rmapbt not supported with realtime devices\n"));
@@ -2119,8 +2049,6 @@ validate_dirblocksize(
 
        if (cli->dirblocksize)
                cfg->dirblocksize = getnum(cli->dirblocksize, &nopts, N_SIZE);
-       if (cli->dirblocklog)
-               cfg->dirblocksize = 1 << cli->dirblocklog;
 
        if (cfg->dirblocksize) {
                if (cfg->dirblocksize < cfg->blocksize ||
@@ -2175,7 +2103,7 @@ validate_inodesize(
                int     maxsz;
 
                fprintf(stderr, _("illegal inode size %d\n"), cfg->inodesize);
-               maxsz = MIN(cfg->blocksize / XFS_MIN_INODE_PERBLOCK,
+               maxsz = min(cfg->blocksize / XFS_MIN_INODE_PERBLOCK,
                            XFS_DINODE_MAX_SIZE);
                if (XFS_DINODE_MIN_SIZE == maxsz)
                        fprintf(stderr,
@@ -2274,6 +2202,85 @@ validate_rtextsize(
        ASSERT(cfg->rtextblocks);
 }
 
+/* Validate the incoming extsize hint. */
+static void
+validate_extsize_hint(
+       struct xfs_mount        *mp,
+       struct cli_params       *cli)
+{
+       xfs_failaddr_t          fa;
+       uint16_t                flags = 0;
+
+       /*
+        * First we validate the extent size inherit hint on a directory so
+        * that we know that we'll be propagating a correct hint and flag to
+        * new files on the data device.
+        */
+       if (cli->fsx.fsx_xflags & FS_XFLAG_EXTSZINHERIT)
+               flags |= XFS_DIFLAG_EXTSZINHERIT;
+
+       fa = libxfs_inode_validate_extsize(mp, cli->fsx.fsx_extsize, S_IFDIR,
+                       flags);
+       if (fa) {
+               fprintf(stderr,
+_("illegal extent size hint %lld, must be less than %u.\n"),
+                               (long long)cli->fsx.fsx_extsize,
+                               min(MAXEXTLEN, mp->m_sb.sb_agblocks / 2));
+               usage();
+       }
+
+       /*
+        * Now we do it again with a realtime file so that we know the hint and
+        * flag that get passed on to realtime files will be correct.
+        */
+       if (mp->m_sb.sb_rextsize == 0)
+               return;
+
+       flags = XFS_DIFLAG_REALTIME;
+       if (cli->fsx.fsx_xflags & FS_XFLAG_EXTSZINHERIT)
+               flags |= XFS_DIFLAG_EXTSIZE;
+
+       fa = libxfs_inode_validate_extsize(mp, cli->fsx.fsx_extsize, S_IFREG,
+                       flags);
+
+       if (fa) {
+               fprintf(stderr,
+_("illegal extent size hint %lld, must be less than %u and a multiple of %u.\n"),
+                               (long long)cli->fsx.fsx_extsize,
+                               min(MAXEXTLEN, mp->m_sb.sb_agblocks / 2),
+                               mp->m_sb.sb_rextsize);
+               usage();
+       }
+}
+
+/* Validate the incoming CoW extsize hint. */
+static void
+validate_cowextsize_hint(
+       struct xfs_mount        *mp,
+       struct cli_params       *cli)
+{
+       xfs_failaddr_t          fa;
+       uint64_t                flags2 = 0;
+
+       /*
+        * Validate the copy on write extent size inherit hint on a directory
+        * so that we know that we'll be propagating a correct hint and flag to
+        * new files on the data device.
+        */
+       if (cli->fsx.fsx_xflags & FS_XFLAG_COWEXTSIZE)
+               flags2 |= XFS_DIFLAG2_COWEXTSIZE;
+
+       fa = libxfs_inode_validate_cowextsize(mp, cli->fsx.fsx_cowextsize,
+                       S_IFDIR, 0, flags2);
+       if (fa) {
+               fprintf(stderr,
+_("illegal CoW extent size hint %lld, must be less than %u.\n"),
+                               (long long)cli->fsx.fsx_cowextsize,
+                               min(MAXEXTLEN, mp->m_sb.sb_agblocks / 2));
+               usage();
+       }
+}
+
 /*
  * Validate the configured stripe geometry, or is none is specified, pull
  * the configuration from the underlying device.
@@ -2286,6 +2293,7 @@ calc_stripe_factors(
        struct cli_params       *cli,
        struct fs_topology      *ft)
 {
+       long long int   big_dswidth;
        int             dsunit = 0;
        int             dswidth = 0;
        int             lsunit = 0;
@@ -2305,7 +2313,7 @@ calc_stripe_factors(
                dsw = cli->dsw;
 
        /* data sunit/swidth options */
-       if ((dsunit && !dswidth) || (!dsunit && dswidth)) {
+       if (cli_opt_set(&dopts, D_SUNIT) != cli_opt_set(&dopts, D_SWIDTH)) {
                fprintf(stderr,
 _("both data sunit and data swidth options must be specified\n"));
                usage();
@@ -2313,7 +2321,7 @@ _("both data sunit and data swidth options must be specified\n"));
 
        /* convert dsu/dsw to dsunit/dswidth and use them from now on */
        if (dsu || dsw) {
-               if ((dsu && !dsw) || (!dsu && dsw)) {
+               if (cli_opt_set(&dopts, D_SU) != cli_opt_set(&dopts, D_SW)) {
                        fprintf(stderr,
 _("both data su and data sw options must be specified\n"));
                        usage();
@@ -2326,10 +2334,18 @@ _("data su must be a multiple of the sector size (%d)\n"), cfg->sectorsize);
                }
 
                dsunit  = (int)BTOBBT(dsu);
-               dswidth = dsunit * dsw;
+               big_dswidth = (long long int)dsunit * dsw;
+               if (big_dswidth > INT_MAX) {
+                       fprintf(stderr,
+_("data stripe width (%lld) is too large of a multiple of the data stripe unit (%d)\n"),
+                               big_dswidth, dsunit);
+                       usage();
+               }
+               dswidth = big_dswidth;
        }
 
-       if (dsunit && (dswidth % dsunit != 0)) {
+       if ((dsunit && !dswidth) || (!dsunit && dswidth) ||
+           (dsunit && (dswidth % dsunit != 0))) {
                fprintf(stderr,
 _("data stripe width (%d) must be a multiple of the data stripe unit (%d)\n"),
                        dswidth, dsunit);
@@ -2350,11 +2366,20 @@ _("data stripe width (%d) must be a multiple of the data stripe unit (%d)\n"),
 
        /* if no stripe config set, use the device default */
        if (!dsunit) {
-               dsunit = ft->dsunit;
-               dswidth = ft->dswidth;
-               use_dev = true;
+               /* Ignore nonsense from device.  XXX add more validation */
+               if (ft->dsunit && ft->dswidth == 0) {
+                       fprintf(stderr,
+_("%s: Volume reports stripe unit of %d bytes and stripe width of 0, ignoring.\n"),
+                               progname, BBTOB(ft->dsunit));
+                       ft->dsunit = 0;
+                       ft->dswidth = 0;
+               } else {
+                       dsunit = ft->dsunit;
+                       dswidth = ft->dswidth;
+                       use_dev = true;
+               }
        } else {
-               /* check and warn is alignment is sub-optimal */
+               /* check and warn if user-specified alignment is sub-optimal */
                if (ft->dsunit && ft->dsunit != dsunit) {
                        fprintf(stderr,
 _("%s: Specified data stripe unit %d is not the same as the volume stripe unit %d\n"),
@@ -2449,8 +2474,7 @@ _("log stripe unit (%d bytes) is too large (maximum is 256KiB)\n"
 static void
 open_devices(
        struct mkfs_params      *cfg,
-       struct libxfs_xinit     *xi,
-       bool                    discard)
+       struct libxfs_xinit     *xi)
 {
        uint64_t                sector_mask;
 
@@ -2475,14 +2499,19 @@ open_devices(
         * So, we reduce the size (in basic blocks) to a perfect
         * multiple of the sector size, or 1024, whichever is larger.
         */
-       sector_mask = (uint64_t)-1 << (MAX(cfg->sectorlog, 10) - BBSHIFT);
+       sector_mask = (uint64_t)-1 << (max(cfg->sectorlog, 10) - BBSHIFT);
        xi->dsize &= sector_mask;
        xi->rtsize &= sector_mask;
-       xi->logBBsize &= (uint64_t)-1 << (MAX(cfg->lsectorlog, 10) - BBSHIFT);
-
+       xi->logBBsize &= (uint64_t)-1 << (max(cfg->lsectorlog, 10) - BBSHIFT);
+}
 
-       if (!discard)
-               return;
+static void
+discard_devices(
+       struct libxfs_xinit     *xi)
+{
+       /*
+        * This function has to be called after libxfs has been initialized.
+        */
 
        if (!xi->disfile)
                discard_blocks(xi->ddev, xi->dsize);
@@ -3004,15 +3033,27 @@ align_internal_log(
        struct xfs_mount        *mp,
        int                     sunit)
 {
+       uint64_t                logend;
+
        /* round up log start if necessary */
        if ((cfg->logstart % sunit) != 0)
                cfg->logstart = ((cfg->logstart + (sunit - 1)) / sunit) * sunit;
 
+       /* If our log start overlaps the next AG's metadata, fail. */
+       if (XFS_FSB_TO_AGBNO(mp, cfg->logstart) <= XFS_AGFL_BLOCK(mp)) {
+                       fprintf(stderr,
+_("Due to stripe alignment, the internal log start (%lld) cannot be aligned\n"
+  "within an allocation group.\n"),
+                       (long long) cfg->logstart);
+               usage();
+       }
+
        /* round up/down the log size now */
        align_log_size(cfg, sunit);
 
-       /* check the aligned log still fits in an AG. */
-       if (cfg->logblocks > cfg->agsize - XFS_FSB_TO_AGBNO(mp, cfg->logstart)) {
+       /* check the aligned log still starts and ends in the same AG. */
+       logend = cfg->logstart + cfg->logblocks - 1;
+       if (XFS_FSB_TO_AGNO(mp, cfg->logstart) != XFS_FSB_TO_AGNO(mp, logend)) {
                fprintf(stderr,
 _("Due to stripe alignment, the internal log size (%lld) is too large.\n"
   "Must fit within an allocation group.\n"),
@@ -3021,7 +3062,7 @@ _("Due to stripe alignment, the internal log size (%lld) is too large.\n"
        }
 }
 
-void
+static void
 validate_log_size(uint64_t logblocks, int blocklog, int min_logblocks)
 {
        if (logblocks < min_logblocks) {
@@ -3050,24 +3091,24 @@ calculate_log_size(
        struct cli_params       *cli,
        struct xfs_mount        *mp)
 {
-       struct sb_feat_args     *fp = &cfg->sb_feat;
        struct xfs_sb           *sbp = &mp->m_sb;
        int                     min_logblocks;
+       struct xfs_mount        mount;
 
-       min_logblocks = max_trans_res(sbp->sb_agblocks, fp->crcs_enabled,
-                                     fp->dir_version, cfg->sectorlog,
-                                     cfg->blocklog, cfg->inodelog,
-                                     cfg->dirblocklog, fp->log_version,
-                                     cfg->lsunit, fp->finobt, fp->rmapbt,
-                                     fp->reflink, fp->inode_align);
+       /* we need a temporary mount to calculate the minimum log size. */
+       memset(&mount, 0, sizeof(mount));
+       mount.m_sb = *sbp;
+       libxfs_mount(&mount, &mp->m_sb, 0, 0, 0, 0);
+       min_logblocks = libxfs_log_calc_minimum_size(&mount);
+       libxfs_umount(&mount);
 
        ASSERT(min_logblocks);
-       min_logblocks = MAX(XFS_MIN_LOG_BLOCKS, min_logblocks);
+       min_logblocks = max(XFS_MIN_LOG_BLOCKS, min_logblocks);
 
        /* if we have lots of blocks, check against XFS_MIN_LOG_BYTES, too */
        if (!cli->logsize &&
            cfg->dblocks >= (1024*1024*1024) >> cfg->blocklog)
-               min_logblocks = MAX(min_logblocks,
+               min_logblocks = max(min_logblocks,
                                    XFS_MIN_LOG_BYTES >> cfg->blocklog);
 
        /*
@@ -3103,7 +3144,7 @@ _("external log device %lld too small, must be at least %lld blocks\n"),
                         * XFS_MIN_LOG_BYTES for filesystems smaller than 16G if
                         * at all possible, ramping up to 128MB at 256GB.
                         */
-                       cfg->logblocks = MIN(XFS_MIN_LOG_BYTES >> cfg->blocklog,
+                       cfg->logblocks = min(XFS_MIN_LOG_BYTES >> cfg->blocklog,
                                        min_logblocks * XFS_DFL_LOG_FACTOR);
                } else {
                        /*
@@ -3117,7 +3158,7 @@ _("external log device %lld too small, must be at least %lld blocks\n"),
                }
 
                /* Ensure the chosen size meets minimum log size requirements */
-               cfg->logblocks = MAX(min_logblocks, cfg->logblocks);
+               cfg->logblocks = max(min_logblocks, cfg->logblocks);
 
                /*
                 * Make sure the log fits wholly within an AG
@@ -3129,11 +3170,11 @@ _("external log device %lld too small, must be at least %lld blocks\n"),
                 * opened to decide what is the valid maximum size of a log in
                 * an AG.
                 */
-               cfg->logblocks = MIN(cfg->logblocks,
+               cfg->logblocks = min(cfg->logblocks,
                                     libxfs_alloc_ag_max_usable(mp) - 1);
 
                /* and now clamp the size to the maximum supported size */
-               cfg->logblocks = MIN(cfg->logblocks, XFS_MAX_LOG_BLOCKS);
+               cfg->logblocks = min(cfg->logblocks, XFS_MAX_LOG_BLOCKS);
                if ((cfg->logblocks << cfg->blocklog) > XFS_MAX_LOG_BYTES)
                        cfg->logblocks = XFS_MAX_LOG_BYTES >> cfg->blocklog;
 
@@ -3174,62 +3215,60 @@ _("log ag number %lld too large, must be less than %lld\n"),
 }
 
 /*
- * Set up mount and superblock with the minimum parameters required for
+ * Set up superblock with the minimum parameters required for
  * the libxfs macros needed by the log sizing code to run successfully.
+ * This includes a minimum log size calculation, so we need everything
+ * that goes into that calculation to be setup here including feature
+ * flags.
  */
 static void
-initialise_mount(
+start_superblock_setup(
        struct mkfs_params      *cfg,
        struct xfs_mount        *mp,
        struct xfs_sb           *sbp)
 {
-       sbp->sb_blocklog = (uint8_t)cfg->blocklog;
+       sbp->sb_magicnum = XFS_SB_MAGIC;
+       sbp->sb_sectsize = (uint16_t)cfg->sectorsize;
        sbp->sb_sectlog = (uint8_t)cfg->sectorlog;
-       sbp->sb_agblklog = (uint8_t)log2_roundup(cfg->agsize);
+       sbp->sb_blocksize = cfg->blocksize;
+       sbp->sb_blocklog = (uint8_t)cfg->blocklog;
+
        sbp->sb_agblocks = (xfs_agblock_t)cfg->agsize;
+       sbp->sb_agblklog = (uint8_t)log2_roundup(cfg->agsize);
        sbp->sb_agcount = (xfs_agnumber_t)cfg->agcount;
-       mp->m_blkbb_log = sbp->sb_blocklog - BBSHIFT;
-       mp->m_sectbb_log = sbp->sb_sectlog - BBSHIFT;
+
+       sbp->sb_inodesize = (uint16_t)cfg->inodesize;
+       sbp->sb_inodelog = (uint8_t)cfg->inodelog;
+       sbp->sb_inopblock = (uint16_t)(cfg->blocksize / cfg->inodesize);
+       sbp->sb_inopblog = (uint8_t)(cfg->blocklog - cfg->inodelog);
+
+       sbp->sb_dirblklog = cfg->dirblocklog - cfg->blocklog;
+
+       sb_set_features(cfg, sbp);
 
        /*
-        * sb_versionnum, finobt and rmapbt flags must be set before we use
-        * libxfs_prealloc_blocks().
+        * log stripe unit is stored in bytes on disk and cannot be zero
+        * for v2 logs.
         */
-       sb_set_features(cfg, sbp);
+       if (cfg->sb_feat.log_version == 2) {
+               if (cfg->lsunit)
+                       sbp->sb_logsunit = XFS_FSB_TO_B(mp, cfg->lsunit);
+               else
+                       sbp->sb_logsunit = 1;
+       } else
+               sbp->sb_logsunit = 0;
+
 }
 
 static void
-print_mkfs_cfg(
+initialise_mount(
        struct mkfs_params      *cfg,
-       char                    *dfile,
-       char                    *logfile,
-       char                    *rtfile)
+       struct xfs_mount        *mp,
+       struct xfs_sb           *sbp)
 {
-       struct sb_feat_args     *fp = &cfg->sb_feat;
-
-       printf(_(
-"meta-data=%-22s isize=%-6d agcount=%lld, agsize=%lld blks\n"
-"         =%-22s sectsz=%-5u attr=%u, projid32bit=%u\n"
-"         =%-22s crc=%-8u finobt=%u, sparse=%u, rmapbt=%u, reflink=%u\n"
-"data     =%-22s bsize=%-6u blocks=%llu, imaxpct=%u\n"
-"         =%-22s sunit=%-6u swidth=%u blks\n"
-"naming   =version %-14u bsize=%-6u ascii-ci=%d ftype=%d\n"
-"log      =%-22s bsize=%-6d blocks=%lld, version=%d\n"
-"         =%-22s sectsz=%-5u sunit=%d blks, lazy-count=%d\n"
-"realtime =%-22s extsz=%-6d blocks=%lld, rtextents=%lld\n"),
-               dfile, cfg->inodesize, (long long)cfg->agcount,
-                       (long long)cfg->agsize,
-               "", cfg->sectorsize, fp->attr_version, fp->projid32bit,
-               "", fp->crcs_enabled, fp->finobt, fp->spinodes, fp->rmapbt,
-                       fp->reflink,
-               "", cfg->blocksize, (long long)cfg->dblocks, cfg->imaxpct,
-               "", cfg->dsunit, cfg->dswidth,
-               fp->dir_version, cfg->dirblocksize, fp->nci, fp->dirftype,
-               logfile, cfg->blocksize, (long long)cfg->logblocks,
-                       fp->log_version,
-               "", cfg->lsectorsize, cfg->lsunit, fp->lazy_sb_counters,
-               rtfile, (int)cfg->rtextblocks << cfg->blocklog,
-                       (long long)cfg->rtblocks, (long long)cfg->rtextents);
+       /* Minimum needed for libxfs_prealloc_blocks() */
+       mp->m_blkbb_log = sbp->sb_blocklog - BBSHIFT;
+       mp->m_sectbb_log = sbp->sb_sectlog - BBSHIFT;
 }
 
 /*
@@ -3238,16 +3277,23 @@ print_mkfs_cfg(
  * copy, so no need to care about endian swapping here.
  */
 static void
-setup_superblock(
+finish_superblock_setup(
        struct mkfs_params      *cfg,
        struct xfs_mount        *mp,
        struct xfs_sb           *sbp)
 {
-       if (cfg->label)
-               strncpy(sbp->sb_fname, cfg->label, sizeof(sbp->sb_fname));
+       if (cfg->label) {
+               size_t          label_len;
+
+               /*
+                * Labels are null terminated unless the string fits exactly
+                * in the label field, so assume sb_fname is zeroed and then
+                * do a memcpy because the destination isn't a normal C string.
+                */
+               label_len = min(sizeof(sbp->sb_fname), strlen(cfg->label));
+               memcpy(sbp->sb_fname, cfg->label, label_len);
+       }
 
-       sbp->sb_magicnum = XFS_SB_MAGIC;
-       sbp->sb_blocksize = cfg->blocksize;
        sbp->sb_dblocks = cfg->dblocks;
        sbp->sb_rblocks = cfg->rtblocks;
        sbp->sb_rextents = cfg->rtextents;
@@ -3260,12 +3306,6 @@ setup_superblock(
        sbp->sb_agcount = (xfs_agnumber_t)cfg->agcount;
        sbp->sb_rbmblocks = cfg->rtbmblocks;
        sbp->sb_logblocks = (xfs_extlen_t)cfg->logblocks;
-       sbp->sb_sectsize = (uint16_t)cfg->sectorsize;
-       sbp->sb_inodesize = (uint16_t)cfg->inodesize;
-       sbp->sb_inopblock = (uint16_t)(cfg->blocksize / cfg->inodesize);
-       sbp->sb_sectlog = (uint8_t)cfg->sectorlog;
-       sbp->sb_inodelog = (uint8_t)cfg->inodelog;
-       sbp->sb_inopblog = (uint8_t)(cfg->blocklog - cfg->inodelog);
        sbp->sb_rextslog = (uint8_t)(cfg->rtextents ?
                        libxfs_highbit32((unsigned int)cfg->rtextents) : 0);
        sbp->sb_inprogress = 1; /* mkfs is in progress */
@@ -3280,19 +3320,6 @@ setup_superblock(
        sbp->sb_qflags = 0;
        sbp->sb_unit = cfg->dsunit;
        sbp->sb_width = cfg->dswidth;
-       sbp->sb_dirblklog = cfg->dirblocklog - cfg->blocklog;
-
-       /*
-        * log stripe unit is stored in bytes on disk and cannot be zero
-        * for v2 logs.
-        */
-       if (cfg->sb_feat.log_version == 2) {
-               if (cfg->lsunit)
-                       sbp->sb_logsunit = XFS_FSB_TO_B(mp, cfg->lsunit);
-               else
-                       sbp->sb_logsunit = 1;
-       } else
-               sbp->sb_logsunit = 0;
 
 }
 
@@ -3346,7 +3373,7 @@ prepare_devices(
         */
        buf = libxfs_getbuf(mp->m_ddev_targp, (xi->dsize - whack_blks),
                            whack_blks);
-       memset(XFS_BUF_PTR(buf), 0, WHACK_SIZE);
+       memset(buf->b_addr, 0, WHACK_SIZE);
        libxfs_writebuf(buf, LIBXFS_EXIT_ON_FAILURE);
        libxfs_purgebuf(buf);
 
@@ -3357,15 +3384,15 @@ prepare_devices(
         * ext[2,3] and reiserfs (64k) - and hopefully all else.
         */
        buf = libxfs_getbuf(mp->m_ddev_targp, 0, whack_blks);
-       memset(XFS_BUF_PTR(buf), 0, WHACK_SIZE);
+       memset(buf->b_addr, 0, WHACK_SIZE);
        libxfs_writebuf(buf, LIBXFS_EXIT_ON_FAILURE);
        libxfs_purgebuf(buf);
 
        /* OK, now write the superblock... */
        buf = libxfs_getbuf(mp->m_ddev_targp, XFS_SB_DADDR, XFS_FSS_TO_BB(mp, 1));
        buf->b_ops = &xfs_sb_buf_ops;
-       memset(XFS_BUF_PTR(buf), 0, cfg->sectorsize);
-       libxfs_sb_to_disk((void *)XFS_BUF_PTR(buf), sbp);
+       memset(buf->b_addr, 0, cfg->sectorsize);
+       libxfs_sb_to_disk(buf->b_addr, sbp);
        libxfs_writebuf(buf, LIBXFS_EXIT_ON_FAILURE);
        libxfs_purgebuf(buf);
 
@@ -3385,7 +3412,7 @@ prepare_devices(
                buf = libxfs_getbuf(mp->m_rtdev_targp,
                                    XFS_FSB_TO_BB(mp, cfg->rtblocks - 1LL),
                                    BTOBB(cfg->blocksize));
-               memset(XFS_BUF_PTR(buf), 0, cfg->blocksize);
+               memset(buf->b_addr, 0, cfg->blocksize);
                libxfs_writebuf(buf, LIBXFS_EXIT_ON_FAILURE);
                libxfs_purgebuf(buf);
        }
@@ -3403,349 +3430,30 @@ initialise_ag_headers(
        struct xfs_mount        *mp,
        struct xfs_sb           *sbp,
        xfs_agnumber_t          agno,
-       int                     *worst_freelist)
+       int                     *worst_freelist,
+       struct list_head        *buffer_list)
 {
+       struct aghdr_init_data  id = {
+               .agno           = agno,
+               .agsize         = cfg->agsize,
+       };
        struct xfs_perag        *pag = libxfs_perag_get(mp, agno);
-       struct xfs_agfl         *agfl;
-       struct xfs_agf          *agf;
-       struct xfs_agi          *agi;
-       struct xfs_buf          *buf;
-       struct xfs_btree_block  *block;
-       struct xfs_alloc_rec    *arec;
-       struct xfs_alloc_rec    *nrec;
-       int                     bucket;
-       uint64_t                agsize = cfg->agsize;
-       xfs_agblock_t           agblocks;
-       bool                    is_log_ag = false;
-       int                     c;
+       int                     error;
 
-       if (cfg->loginternal && agno == cfg->logagno)
-               is_log_ag = true;
-
-       /*
-        * Superblock.
-        */
-       buf = libxfs_getbuf(mp->m_ddev_targp,
-                       XFS_AG_DADDR(mp, agno, XFS_SB_DADDR),
-                       XFS_FSS_TO_BB(mp, 1));
-       buf->b_ops = &xfs_sb_buf_ops;
-       memset(XFS_BUF_PTR(buf), 0, cfg->sectorsize);
-       libxfs_sb_to_disk((void *)XFS_BUF_PTR(buf), sbp);
-       libxfs_writebuf(buf, LIBXFS_EXIT_ON_FAILURE);
-
-       /*
-        * AG header block: freespace
-        */
-       buf = libxfs_getbuf(mp->m_ddev_targp,
-                       XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR(mp)),
-                       XFS_FSS_TO_BB(mp, 1));
-       buf->b_ops = &xfs_agf_buf_ops;
-       agf = XFS_BUF_TO_AGF(buf);
-       memset(agf, 0, cfg->sectorsize);
        if (agno == cfg->agcount - 1)
-               agsize = cfg->dblocks - (xfs_rfsblock_t)(agno * agsize);
-       agf->agf_magicnum = cpu_to_be32(XFS_AGF_MAGIC);
-       agf->agf_versionnum = cpu_to_be32(XFS_AGF_VERSION);
-       agf->agf_seqno = cpu_to_be32(agno);
-       agf->agf_length = cpu_to_be32(agsize);
-       agf->agf_roots[XFS_BTNUM_BNOi] = cpu_to_be32(XFS_BNO_BLOCK(mp));
-       agf->agf_roots[XFS_BTNUM_CNTi] = cpu_to_be32(XFS_CNT_BLOCK(mp));
-       agf->agf_levels[XFS_BTNUM_BNOi] = cpu_to_be32(1);
-       agf->agf_levels[XFS_BTNUM_CNTi] = cpu_to_be32(1);
-       pag->pagf_levels[XFS_BTNUM_BNOi] = 1;
-       pag->pagf_levels[XFS_BTNUM_CNTi] = 1;
-
-       if (xfs_sb_version_hasrmapbt(sbp)) {
-               agf->agf_roots[XFS_BTNUM_RMAPi] = cpu_to_be32(XFS_RMAP_BLOCK(mp));
-               agf->agf_levels[XFS_BTNUM_RMAPi] = cpu_to_be32(1);
-               agf->agf_rmap_blocks = cpu_to_be32(1);
-       }
+               id.agsize = cfg->dblocks - (xfs_rfsblock_t)(agno * cfg->agsize);
 
-       if (xfs_sb_version_hasreflink(sbp)) {
-               agf->agf_refcount_root = cpu_to_be32(libxfs_refc_block(mp));
-               agf->agf_refcount_level = cpu_to_be32(1);
-               agf->agf_refcount_blocks = cpu_to_be32(1);
+       INIT_LIST_HEAD(&id.buffer_list);
+       error = -libxfs_ag_init_headers(mp, &id);
+       if (error) {
+               fprintf(stderr, _("AG header init failed, error %d\n"), error);
+               exit(1);
        }
 
-       agf->agf_flfirst = 0;
-       agf->agf_fllast = cpu_to_be32(XFS_AGFL_SIZE(mp) - 1);
-       agf->agf_flcount = 0;
-       agblocks = (xfs_agblock_t)(agsize - libxfs_prealloc_blocks(mp));
-       agf->agf_freeblks = cpu_to_be32(agblocks);
-       agf->agf_longest = cpu_to_be32(agblocks);
-
-       if (xfs_sb_version_hascrc(sbp))
-               platform_uuid_copy(&agf->agf_uuid, &sbp->sb_uuid);
+       list_splice_tail_init(&id.buffer_list, buffer_list);
 
-       if (is_log_ag) {
-               be32_add_cpu(&agf->agf_freeblks, -(int64_t)cfg->logblocks);
-               agf->agf_longest = cpu_to_be32(agsize -
-                       XFS_FSB_TO_AGBNO(mp, cfg->logstart) - cfg->logblocks);
-       }
        if (libxfs_alloc_min_freelist(mp, pag) > *worst_freelist)
                *worst_freelist = libxfs_alloc_min_freelist(mp, pag);
-       libxfs_writebuf(buf, LIBXFS_EXIT_ON_FAILURE);
-
-       /*
-        * AG freelist header block
-        */
-       buf = libxfs_getbuf(mp->m_ddev_targp,
-                       XFS_AG_DADDR(mp, agno, XFS_AGFL_DADDR(mp)),
-                       XFS_FSS_TO_BB(mp, 1));
-       buf->b_ops = &xfs_agfl_buf_ops;
-       agfl = XFS_BUF_TO_AGFL(buf);
-       /* setting to 0xff results in initialisation to NULLAGBLOCK */
-       memset(agfl, 0xff, cfg->sectorsize);
-       if (xfs_sb_version_hascrc(sbp)) {
-               agfl->agfl_magicnum = cpu_to_be32(XFS_AGFL_MAGIC);
-               agfl->agfl_seqno = cpu_to_be32(agno);
-               platform_uuid_copy(&agfl->agfl_uuid, &sbp->sb_uuid);
-               for (bucket = 0; bucket < XFS_AGFL_SIZE(mp); bucket++)
-                       agfl->agfl_bno[bucket] = cpu_to_be32(NULLAGBLOCK);
-       }
-
-       libxfs_writebuf(buf, LIBXFS_EXIT_ON_FAILURE);
-
-       /*
-        * AG header block: inodes
-        */
-       buf = libxfs_getbuf(mp->m_ddev_targp,
-                       XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp)),
-                       XFS_FSS_TO_BB(mp, 1));
-       agi = XFS_BUF_TO_AGI(buf);
-       buf->b_ops = &xfs_agi_buf_ops;
-       memset(agi, 0, cfg->sectorsize);
-       agi->agi_magicnum = cpu_to_be32(XFS_AGI_MAGIC);
-       agi->agi_versionnum = cpu_to_be32(XFS_AGI_VERSION);
-       agi->agi_seqno = cpu_to_be32(agno);
-       agi->agi_length = cpu_to_be32(agsize);
-       agi->agi_count = 0;
-       agi->agi_root = cpu_to_be32(XFS_IBT_BLOCK(mp));
-       agi->agi_level = cpu_to_be32(1);
-       if (xfs_sb_version_hasfinobt(sbp)) {
-               agi->agi_free_root = cpu_to_be32(XFS_FIBT_BLOCK(mp));
-               agi->agi_free_level = cpu_to_be32(1);
-       }
-       agi->agi_freecount = 0;
-       agi->agi_newino = cpu_to_be32(NULLAGINO);
-       agi->agi_dirino = cpu_to_be32(NULLAGINO);
-       if (xfs_sb_version_hascrc(sbp))
-               platform_uuid_copy(&agi->agi_uuid, &sbp->sb_uuid);
-       for (c = 0; c < XFS_AGI_UNLINKED_BUCKETS; c++)
-               agi->agi_unlinked[c] = cpu_to_be32(NULLAGINO);
-       libxfs_writebuf(buf, LIBXFS_EXIT_ON_FAILURE);
-
-       /*
-        * BNO btree root block
-        */
-       buf = libxfs_getbuf(mp->m_ddev_targp,
-                       XFS_AGB_TO_DADDR(mp, agno, XFS_BNO_BLOCK(mp)),
-                       BTOBB(cfg->blocksize));
-       buf->b_ops = &xfs_allocbt_buf_ops;
-       block = XFS_BUF_TO_BLOCK(buf);
-       memset(block, 0, cfg->blocksize);
-       libxfs_btree_init_block(mp, buf, XFS_BTNUM_BNO, 0, 1, agno, 0);
-
-       arec = XFS_ALLOC_REC_ADDR(mp, block, 1);
-       arec->ar_startblock = cpu_to_be32(libxfs_prealloc_blocks(mp));
-       if (is_log_ag) {
-               xfs_agblock_t   start = XFS_FSB_TO_AGBNO(mp, cfg->logstart);
-
-               ASSERT(start >= libxfs_prealloc_blocks(mp));
-               if (start != libxfs_prealloc_blocks(mp)) {
-                       /*
-                        * Modify first record to pad stripe align of log
-                        */
-                       arec->ar_blockcount = cpu_to_be32(start -
-                                               libxfs_prealloc_blocks(mp));
-                       nrec = arec + 1;
-                       /*
-                        * Insert second record at start of internal log
-                        * which then gets trimmed.
-                        */
-                       nrec->ar_startblock = cpu_to_be32(
-                                       be32_to_cpu(arec->ar_startblock) +
-                                       be32_to_cpu(arec->ar_blockcount));
-                       arec = nrec;
-                       be16_add_cpu(&block->bb_numrecs, 1);
-               }
-               /*
-                * Change record start to after the internal log
-                */
-               be32_add_cpu(&arec->ar_startblock, cfg->logblocks);
-       }
-       /*
-        * Calculate the record block count and check for the case where
-        * the log might have consumed all available space in the AG. If
-        * so, reset the record count to 0 to avoid exposure of an invalid
-        * record start block.
-        */
-       arec->ar_blockcount = cpu_to_be32(agsize -
-                                         be32_to_cpu(arec->ar_startblock));
-       if (!arec->ar_blockcount)
-               block->bb_numrecs = 0;
-
-       libxfs_writebuf(buf, LIBXFS_EXIT_ON_FAILURE);
-
-       /*
-        * CNT btree root block
-        */
-       buf = libxfs_getbuf(mp->m_ddev_targp,
-                       XFS_AGB_TO_DADDR(mp, agno, XFS_CNT_BLOCK(mp)),
-                       BTOBB(cfg->blocksize));
-       buf->b_ops = &xfs_allocbt_buf_ops;
-       block = XFS_BUF_TO_BLOCK(buf);
-       memset(block, 0, cfg->blocksize);
-       libxfs_btree_init_block(mp, buf, XFS_BTNUM_CNT, 0, 1, agno, 0);
-
-       arec = XFS_ALLOC_REC_ADDR(mp, block, 1);
-       arec->ar_startblock = cpu_to_be32(libxfs_prealloc_blocks(mp));
-       if (is_log_ag) {
-               xfs_agblock_t   start = XFS_FSB_TO_AGBNO(mp, cfg->logstart);
-
-               ASSERT(start >= libxfs_prealloc_blocks(mp));
-               if (start != libxfs_prealloc_blocks(mp)) {
-                       arec->ar_blockcount = cpu_to_be32(start -
-                                       libxfs_prealloc_blocks(mp));
-                       nrec = arec + 1;
-                       nrec->ar_startblock = cpu_to_be32(
-                                       be32_to_cpu(arec->ar_startblock) +
-                                       be32_to_cpu(arec->ar_blockcount));
-                       arec = nrec;
-                       be16_add_cpu(&block->bb_numrecs, 1);
-               }
-               be32_add_cpu(&arec->ar_startblock, cfg->logblocks);
-       }
-       /*
-        * Calculate the record block count and check for the case where
-        * the log might have consumed all available space in the AG. If
-        * so, reset the record count to 0 to avoid exposure of an invalid
-        * record start block.
-        */
-       arec->ar_blockcount = cpu_to_be32(agsize -
-                                         be32_to_cpu(arec->ar_startblock));
-       if (!arec->ar_blockcount)
-               block->bb_numrecs = 0;
-
-       libxfs_writebuf(buf, LIBXFS_EXIT_ON_FAILURE);
-
-       /*
-        * refcount btree root block
-        */
-       if (xfs_sb_version_hasreflink(sbp)) {
-               buf = libxfs_getbuf(mp->m_ddev_targp,
-                       XFS_AGB_TO_DADDR(mp, agno, libxfs_refc_block(mp)),
-                       BTOBB(cfg->blocksize));
-               buf->b_ops = &xfs_refcountbt_buf_ops;
-
-               block = XFS_BUF_TO_BLOCK(buf);
-               memset(block, 0, cfg->blocksize);
-               libxfs_btree_init_block(mp, buf, XFS_BTNUM_REFC, 0, 0, agno, 0);
-               libxfs_writebuf(buf, LIBXFS_EXIT_ON_FAILURE);
-       }
-
-       /*
-        * INO btree root block
-        */
-       buf = libxfs_getbuf(mp->m_ddev_targp,
-                       XFS_AGB_TO_DADDR(mp, agno, XFS_IBT_BLOCK(mp)),
-                       BTOBB(cfg->blocksize));
-       buf->b_ops = &xfs_inobt_buf_ops;
-       block = XFS_BUF_TO_BLOCK(buf);
-       memset(block, 0, cfg->blocksize);
-       libxfs_btree_init_block(mp, buf, XFS_BTNUM_INO, 0, 0, agno, 0);
-       libxfs_writebuf(buf, LIBXFS_EXIT_ON_FAILURE);
-
-       /*
-        * Free INO btree root block
-        */
-       if (xfs_sb_version_hasfinobt(sbp)) {
-               buf = libxfs_getbuf(mp->m_ddev_targp,
-                               XFS_AGB_TO_DADDR(mp, agno, XFS_FIBT_BLOCK(mp)),
-                               BTOBB(cfg->blocksize));
-               buf->b_ops = &xfs_inobt_buf_ops;
-               block = XFS_BUF_TO_BLOCK(buf);
-               memset(block, 0, cfg->blocksize);
-               libxfs_btree_init_block(mp, buf, XFS_BTNUM_FINO, 0, 0, agno, 0);
-               libxfs_writebuf(buf, LIBXFS_EXIT_ON_FAILURE);
-       }
-
-       /* RMAP btree root block */
-       if (xfs_sb_version_hasrmapbt(sbp)) {
-               struct xfs_rmap_rec     *rrec;
-
-               buf = libxfs_getbuf(mp->m_ddev_targp,
-                       XFS_AGB_TO_DADDR(mp, agno, XFS_RMAP_BLOCK(mp)),
-                       BTOBB(cfg->blocksize));
-               buf->b_ops = &xfs_rmapbt_buf_ops;
-               block = XFS_BUF_TO_BLOCK(buf);
-               memset(block, 0, cfg->blocksize);
-
-               libxfs_btree_init_block(mp, buf, XFS_BTNUM_RMAP, 0, 0, agno, 0);
-
-               /*
-                * mark the AG header regions as static metadata
-                * The BNO btree block is the first block after the
-                * headers, so it's location defines the size of region
-                * the static metadata consumes.
-                */
-               rrec = XFS_RMAP_REC_ADDR(block, 1);
-               rrec->rm_startblock = 0;
-               rrec->rm_blockcount = cpu_to_be32(XFS_BNO_BLOCK(mp));
-               rrec->rm_owner = cpu_to_be64(XFS_RMAP_OWN_FS);
-               rrec->rm_offset = 0;
-               be16_add_cpu(&block->bb_numrecs, 1);
-
-               /* account freespace btree root blocks */
-               rrec = XFS_RMAP_REC_ADDR(block, 2);
-               rrec->rm_startblock = cpu_to_be32(XFS_BNO_BLOCK(mp));
-               rrec->rm_blockcount = cpu_to_be32(2);
-               rrec->rm_owner = cpu_to_be64(XFS_RMAP_OWN_AG);
-               rrec->rm_offset = 0;
-               be16_add_cpu(&block->bb_numrecs, 1);
-
-               /* account inode btree root blocks */
-               rrec = XFS_RMAP_REC_ADDR(block, 3);
-               rrec->rm_startblock = cpu_to_be32(XFS_IBT_BLOCK(mp));
-               rrec->rm_blockcount = cpu_to_be32(XFS_RMAP_BLOCK(mp) -
-                                               XFS_IBT_BLOCK(mp));
-               rrec->rm_owner = cpu_to_be64(XFS_RMAP_OWN_INOBT);
-               rrec->rm_offset = 0;
-               be16_add_cpu(&block->bb_numrecs, 1);
-
-               /* account for rmap btree root */
-               rrec = XFS_RMAP_REC_ADDR(block, 4);
-               rrec->rm_startblock = cpu_to_be32(XFS_RMAP_BLOCK(mp));
-               rrec->rm_blockcount = cpu_to_be32(1);
-               rrec->rm_owner = cpu_to_be64(XFS_RMAP_OWN_AG);
-               rrec->rm_offset = 0;
-               be16_add_cpu(&block->bb_numrecs, 1);
-
-               /* account for refcount btree root */
-               if (xfs_sb_version_hasreflink(sbp)) {
-                       rrec = XFS_RMAP_REC_ADDR(block, 5);
-                       rrec->rm_startblock = cpu_to_be32(libxfs_refc_block(mp));
-                       rrec->rm_blockcount = cpu_to_be32(1);
-                       rrec->rm_owner = cpu_to_be64(XFS_RMAP_OWN_REFC);
-                       rrec->rm_offset = 0;
-                       be16_add_cpu(&block->bb_numrecs, 1);
-               }
-
-               /* account for the log space */
-               if (is_log_ag) {
-                       rrec = XFS_RMAP_REC_ADDR(block,
-                                       be16_to_cpu(block->bb_numrecs) + 1);
-                       rrec->rm_startblock = cpu_to_be32(
-                                       XFS_FSB_TO_AGBNO(mp, cfg->logstart));
-                       rrec->rm_blockcount = cpu_to_be32(cfg->logblocks);
-                       rrec->rm_owner = cpu_to_be64(XFS_RMAP_OWN_LOG);
-                       rrec->rm_offset = 0;
-                       be16_add_cpu(&block->bb_numrecs, 1);
-               }
-
-               libxfs_writebuf(buf, LIBXFS_EXIT_ON_FAILURE);
-       }
-
        libxfs_perag_put(pag);
 }
 
@@ -3757,10 +3465,9 @@ initialise_ag_freespace(
 {
        struct xfs_alloc_arg    args;
        struct xfs_trans        *tp;
-       struct xfs_trans_res tres = {0};
        int                     c;
 
-       c = libxfs_trans_alloc(mp, &tres, worst_freelist, 0, 0, &tp);
+       c = -libxfs_trans_alloc_rollable(mp, worst_freelist, &tp);
        if (c)
                res_failed(c);
 
@@ -3773,7 +3480,12 @@ initialise_ag_freespace(
 
        libxfs_alloc_fix_freelist(&args, 0);
        libxfs_perag_put(args.pag);
-       libxfs_trans_commit(tp);
+       c = -libxfs_trans_commit(tp);
+       if (c) {
+               errno = c;
+               perror(_("initializing AG free space list"));
+               exit(1);
+       }
 }
 
 /*
@@ -3858,15 +3570,17 @@ main(
                        .crcs_enabled = true,
                        .dirftype = true,
                        .finobt = true,
-                       .spinodes = false,
+                       .spinodes = true,
                        .rmapbt = false,
-                       .reflink = false,
+                       .reflink = true,
                        .parent_pointers = false,
                        .nodalign = false,
                        .nortalign = false,
                },
        };
 
+       struct list_head        buffer_list;
+
        platform_uuid_generate(&cli.uuid);
        progname = basename(argv[0]);
        setlocale(LC_ALL, "");
@@ -3979,15 +3693,16 @@ main(
        cfg.rtblocks = calc_dev_size(cli.rtsize, &cfg, &ropts, R_SIZE, "rt");
 
        validate_rtextsize(&cfg, &cli, &ft);
-       calc_stripe_factors(&cfg, &cli, &ft);
 
        /*
         * Open and validate the device configurations
         */
-       open_devices(&cfg, &xi, (discard && !dry_run));
+       open_devices(&cfg, &xi);
+       validate_overwrite(dfile, force_overwrite);
        validate_datadev(&cfg, &cli);
        validate_logdev(&cfg, &cli, &logfile);
        validate_rtdev(&cfg, &cli, &rtfile);
+       calc_stripe_factors(&cfg, &cli, &ft);
 
        /*
         * At this point when know exactly what size all the devices are,
@@ -4005,6 +3720,7 @@ main(
         * the geometry information we've already validated in libxfs
         * provided functions to determine on-disk format information.
         */
+       start_superblock_setup(&cfg, mp, sbp);
        initialise_mount(&cfg, mp, sbp);
 
        /*
@@ -4013,18 +3729,27 @@ main(
         */
        calculate_log_size(&cfg, &cli, mp);
 
-       protostring = setup_proto(protofile);
+       finish_superblock_setup(&cfg, mp, sbp);
 
+       /* Validate the extent size hints now that @mp is fully set up. */
+       validate_extsize_hint(mp, &cli);
+       validate_cowextsize_hint(mp, &cli);
+
+       /* Print the intended geometry of the fs. */
        if (!quiet || dry_run) {
-               print_mkfs_cfg(&cfg, dfile, logfile, rtfile);
+               struct xfs_fsop_geom    geo;
+
+               libxfs_fs_geometry(sbp, &geo, XFS_FS_GEOM_MAX_STRUCT_VER);
+               xfs_report_geom(&geo, dfile, logfile, rtfile);
                if (dry_run)
                        exit(0);
        }
 
        /*
-        * Finish setting up the superblock state ready for formatting.
+        * All values have been validated, discard the old device layout.
         */
-       setup_superblock(&cfg, mp, sbp);
+       if (discard && !dry_run)
+               discard_devices(&xi);
 
        /*
         * we need the libxfs buffer cache from here on in.
@@ -4047,8 +3772,26 @@ main(
        /*
         * Initialise all the static on disk metadata.
         */
-       for (agno = 0; agno < cfg.agcount; agno++)
-               initialise_ag_headers(&cfg, mp, sbp, agno, &worst_freelist);
+       INIT_LIST_HEAD(&buffer_list);
+       for (agno = 0; agno < cfg.agcount; agno++) {
+               initialise_ag_headers(&cfg, mp, sbp, agno, &worst_freelist,
+                               &buffer_list);
+
+               if (agno % 16)
+                       continue;
+
+               if (libxfs_buf_delwri_submit(&buffer_list)) {
+                       fprintf(stderr, _("%s: writing AG headers failed\n"),
+                                       progname);
+                       exit(1);
+               }
+       }
+
+       if (libxfs_buf_delwri_submit(&buffer_list)) {
+               fprintf(stderr, _("%s: writing AG headers failed\n"),
+                               progname);
+               exit(1);
+       }
 
        /*
         * Initialise the freespace freelists (i.e. AGFLs) in each AG.
@@ -4087,7 +3830,9 @@ main(
        /*
         * Mark the filesystem ok.
         */
-       buf = libxfs_getsb(mp, LIBXFS_EXIT_ON_FAILURE);
+       buf = libxfs_getsb(mp);
+       if (!buf || buf->b_error)
+               exit(1);
        (XFS_BUF_TO_SBP(buf))->sb_inprogress = 0;
        libxfs_writebuf(buf, LIBXFS_EXIT_ON_FAILURE);
 
@@ -4097,6 +3842,7 @@ main(
        if (xi.logdev && xi.logdev != xi.ddev)
                libxfs_device_close(xi.logdev);
        libxfs_device_close(xi.ddev);
+       libxfs_destroy();
 
        return 0;
 }