]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blobdiff - mkfs/xfs_mkfs.c
mkfs: pass a custom cowextsize into the created filesystem
[thirdparty/xfsprogs-dev.git] / mkfs / xfs_mkfs.c
index 2e4feb835af5c612fccbbac8fe8f29321b0c6660..3058129409010e32c76b6a805bb16b1eb8d391db 100644 (file)
 
 #include "libxfs.h"
 #include <ctype.h>
-#ifdef ENABLE_BLKID
-#  include <blkid/blkid.h>
-#endif /* ENABLE_BLKID */
 #include "xfs_multidisk.h"
-
-/*
- * Device topology information.
- */
-struct fs_topology {
-       int     dsunit;         /* stripe unit - data subvolume */
-       int     dswidth;        /* stripe width - data subvolume */
-       int     rtswidth;       /* stripe width - rt subvolume */
-       int     lsectorsize;    /* logical sector size &*/
-       int     psectorsize;    /* physical sector size */
-};
+#include "libxcmd.h"
 
 /*
  * Prototypes for internal functions.
@@ -200,6 +187,8 @@ struct opt_params dopts = {
                "projinherit",
 #define D_EXTSZINHERIT 14
                "extszinherit",
+#define D_COWEXTSIZE   15
+               "cowextsize",
                NULL
        },
        .subopt_params = {
@@ -316,6 +305,12 @@ struct opt_params dopts = {
                  .maxval = UINT_MAX,
                  .defaultval = SUBOPT_NEEDS_VAL,
                },
+               { .index = D_COWEXTSIZE,
+                 .conflicts = { LAST_CONFLICT },
+                 .minval = 0,
+                 .maxval = UINT_MAX,
+                 .defaultval = SUBOPT_NEEDS_VAL,
+               },
        },
 };
 
@@ -462,7 +457,7 @@ struct opt_params lopts = {
                { .index = L_SUNIT,
                  .conflicts = { L_SU,
                                 LAST_CONFLICT },
-                 .minval = BTOBB(XLOG_MIN_RECORD_BSIZE),
+                 .minval = 1,
                  .maxval = BTOBB(XLOG_MAX_RECORD_BSIZE),
                  .defaultval = SUBOPT_NEEDS_VAL,
                },
@@ -470,7 +465,7 @@ struct opt_params lopts = {
                  .conflicts = { L_SUNIT,
                                 LAST_CONFLICT },
                  .convert = true,
-                 .minval = XLOG_MIN_RECORD_BSIZE,
+                 .minval = BBTOB(1),
                  .maxval = XLOG_MAX_RECORD_BSIZE,
                  .defaultval = SUBOPT_NEEDS_VAL,
                },
@@ -680,6 +675,10 @@ struct opt_params mopts = {
                "finobt",
 #define M_UUID         2
                "uuid",
+#define M_RMAPBT       3
+               "rmapbt",
+#define M_REFLINK      4
+               "reflink",
                NULL
        },
        .subopt_params = {
@@ -699,12 +698,24 @@ struct opt_params mopts = {
                  .conflicts = { LAST_CONFLICT },
                  .defaultval = SUBOPT_NEEDS_VAL,
                },
+               { .index = M_RMAPBT,
+                 .conflicts = { LAST_CONFLICT },
+                 .minval = 0,
+                 .maxval = 1,
+                 .defaultval = 1,
+               },
+               { .index = M_REFLINK,
+                 .conflicts = { LAST_CONFLICT },
+                 .minval = 0,
+                 .maxval = 1,
+                 .defaultval = 1,
+               },
        },
 };
 
-#define TERABYTES(count, blog) ((__uint64_t)(count) << (40 - (blog)))
-#define GIGABYTES(count, blog) ((__uint64_t)(count) << (30 - (blog)))
-#define MEGABYTES(count, blog) ((__uint64_t)(count) << (20 - (blog)))
+#define TERABYTES(count, blog) ((uint64_t)(count) << (40 - (blog)))
+#define GIGABYTES(count, blog) ((uint64_t)(count) << (30 - (blog)))
+#define MEGABYTES(count, blog) ((uint64_t)(count) << (20 - (blog)))
 
 /*
  * Use this macro before we have superblock and mount structure
@@ -726,6 +737,9 @@ struct opt_params mopts = {
  */
 #define WHACK_SIZE (128 * 1024)
 
+/*
+ * Convert lsu to lsunit for 512 bytes blocks and check validity of the values.
+ */
 static void
 calc_stripe_factors(
        int             dsu,
@@ -775,246 +789,19 @@ calc_stripe_factors(
 
        if (lsu)
                *lsunit = (int)BTOBBT(lsu);
-}
-
-/*
- * Check for existing filesystem or partition table on device.
- * Returns:
- *      1 for existing fs or partition
- *      0 for nothing found
- *     -1 for internal error
- */
-#ifdef ENABLE_BLKID
-static int
-check_overwrite(
-       const char      *device)
-{
-       const char      *type;
-       blkid_probe     pr = NULL;
-       int             ret;
-       int             fd;
-       long long       size;
-       int             bsz;
-
-       if (!device || !*device)
-               return 0;
-
-       ret = -1; /* will reset on success of all setup calls */
-
-       fd = open(device, O_RDONLY);
-       if (fd < 0)
-               goto out;
-       platform_findsizes((char *)device, fd, &size, &bsz);
-       close(fd);
-
-       /* nothing to overwrite on a 0-length device */
-       if (size == 0) {
-               ret = 0;
-               goto out;
-       }
-
-       pr = blkid_new_probe_from_filename(device);
-       if (!pr)
-               goto out;
-
-       ret = blkid_probe_enable_partitions(pr, 1);
-       if (ret < 0)
-               goto out;
-
-       ret = blkid_do_fullprobe(pr);
-       if (ret < 0)
-               goto out;
-
-       /*
-        * Blkid returns 1 for nothing found and 0 when it finds a signature,
-        * but we want the exact opposite, so reverse the return value here.
-        *
-        * In addition print some useful diagnostics about what actually is
-        * on the device.
-        */
-       if (ret) {
-               ret = 0;
-               goto out;
-       }
-
-       if (!blkid_probe_lookup_value(pr, "TYPE", &type, NULL)) {
-               fprintf(stderr,
-                       _("%s: %s appears to contain an existing "
-                       "filesystem (%s).\n"), progname, device, type);
-       } else if (!blkid_probe_lookup_value(pr, "PTTYPE", &type, NULL)) {
-               fprintf(stderr,
-                       _("%s: %s appears to contain a partition "
-                       "table (%s).\n"), progname, device, type);
-       } else {
-               fprintf(stderr,
-                       _("%s: %s appears to contain something weird "
-                       "according to blkid\n"), progname, device);
-       }
-       ret = 1;
-out:
-       if (pr)
-               blkid_free_probe(pr);
-       if (ret == -1)
-               fprintf(stderr,
-                       _("%s: probe of %s failed, cannot detect "
-                         "existing filesystem.\n"), progname, device);
-       return ret;
-}
-
-static void blkid_get_topology(
-       const char      *device,
-       int             *sunit,
-       int             *swidth,
-       int             *lsectorsize,
-       int             *psectorsize,
-       int             force_overwrite)
-{
-
-       blkid_topology tp;
-       blkid_probe pr;
-       unsigned long val;
-       struct stat statbuf;
 
-       /* can't get topology info from a file */
-       if (!stat(device, &statbuf) && S_ISREG(statbuf.st_mode)) {
+       /* verify if lsu/lsunit is a multiple block size */
+       if (lsu % blocksize != 0) {
                fprintf(stderr,
-       _("%s: Warning: trying to probe topology of a file %s!\n"),
-                       progname, device);
-               return;
-       }
-
-       pr = blkid_new_probe_from_filename(device);
-       if (!pr)
-               return;
-
-       tp = blkid_probe_get_topology(pr);
-       if (!tp)
-               goto out_free_probe;
-
-       val = blkid_topology_get_logical_sector_size(tp);
-       *lsectorsize = val;
-       val = blkid_topology_get_physical_sector_size(tp);
-       *psectorsize = val;
-       val = blkid_topology_get_minimum_io_size(tp);
-       *sunit = val;
-       val = blkid_topology_get_optimal_io_size(tp);
-       *swidth = val;
-
-       /*
-        * If the reported values are the same as the physical sector size
-        * do not bother to report anything.  It will only cause warnings
-        * if people specify larger stripe units or widths manually.
-        */
-       if (*sunit == *psectorsize || *swidth == *psectorsize) {
-               *sunit = 0;
-               *swidth = 0;
+_("log stripe unit (%d) must be a multiple of the block size (%d)\n"),
+               lsu, blocksize);
+               exit(1);
        }
-
-       /*
-        * Blkid reports the information in terms of bytes, but we want it in
-        * terms of 512 bytes blocks (only to convert it to bytes later..)
-        */
-       *sunit = *sunit >> 9;
-       *swidth = *swidth >> 9;
-
-       if (blkid_topology_get_alignment_offset(tp) != 0) {
+       if ((BBTOB(*lsunit) % blocksize != 0)) {
                fprintf(stderr,
-                       _("warning: device is not properly aligned %s\n"),
-                       device);
-
-               if (!force_overwrite) {
-                       fprintf(stderr,
-                               _("Use -f to force usage of a misaligned device\n"));
-
-                       exit(EXIT_FAILURE);
-               }
-               /* Do not use physical sector size if the device is misaligned */
-               *psectorsize = *lsectorsize;
-       }
-
-       blkid_free_probe(pr);
-       return;
-
-out_free_probe:
-       blkid_free_probe(pr);
-       fprintf(stderr,
-               _("warning: unable to probe device topology for device %s\n"),
-               device);
-}
-#else /* ifdef ENABLE_BLKID */
-/*
- * Without blkid, we can't do a good check for signatures.
- * So instead of some messy attempts, just disable any checks
- * and always return 'nothing found'.
- */
-#  warning BLKID is disabled, so signature detection and block device\
- access are not working!
-static int
-check_overwrite(
-       const char      *device)
-{
-       return 1;
-}
-
-static void blkid_get_topology(
-       const char      *device,
-       int             *sunit,
-       int             *swidth,
-       int             *lsectorsize,
-       int             *psectorsize,
-       int             force_overwrite)
-{
-       /*
-        * Shouldn't make any difference (no blkid = no block device access),
-        * but make sure this dummy replacement returns with at least some
-        * sanity.
-        */
-       *lsectorsize = *psectorsize = 512;
-}
-
-#endif /* ENABLE_BLKID */
-
-static void get_topology(
-       libxfs_init_t           *xi,
-       struct fs_topology      *ft,
-       int                     force_overwrite)
-{
-       struct stat statbuf;
-       char *dfile = xi->volname ? xi->volname : xi->dname;
-
-       /*
-        * If our target is a regular file, use platform_findsizes
-        * to try to obtain the underlying filesystem's requirements
-        * for direct IO; we'll set our sector size to that if possible.
-        */
-       if (xi->disfile ||
-           (!stat(dfile, &statbuf) && S_ISREG(statbuf.st_mode))) {
-               int fd;
-               int flags = O_RDONLY;
-               long long dummy;
-
-               /* with xi->disfile we may not have the file yet! */
-               if (xi->disfile)
-                       flags |= O_CREAT;
-
-               fd = open(dfile, flags, 0666);
-               if (fd >= 0) {
-                       platform_findsizes(dfile, fd, &dummy, &ft->lsectorsize);
-                       close(fd);
-                       ft->psectorsize = ft->lsectorsize;
-               } else
-                       ft->psectorsize = ft->lsectorsize = BBSIZE;
-       } else {
-               blkid_get_topology(dfile, &ft->dsunit, &ft->dswidth,
-                                  &ft->lsectorsize, &ft->psectorsize,
-                                  force_overwrite);
-       }
-
-       if (xi->rtname && !xi->risfile) {
-               int sunit, lsectorsize, psectorsize;
-
-               blkid_get_topology(xi->rtname, &sunit, &ft->rtswidth,
-                                  &lsectorsize, &psectorsize, force_overwrite);
+_("log stripe unit (%d) must be a multiple of the block size (%d)\n"),
+               BBTOB(*lsunit), blocksize);
+               exit(1);
        }
 }
 
@@ -1028,7 +815,7 @@ check_device_type(
        bool            force_overwrite,
        const char      *optname)
 {
-       struct stat64 statbuf;
+       struct stat statbuf;
 
        if (*isfile && (no_size || no_name)) {
                fprintf(stderr,
@@ -1042,7 +829,7 @@ check_device_type(
                usage();
        }
 
-       if (stat64(name, &statbuf)) {
+       if (stat(name, &statbuf)) {
                if (errno == ENOENT && *isfile) {
                        if (create)
                                *create = 1;
@@ -1099,7 +886,7 @@ fixup_log_stripe_unit(
        xfs_rfsblock_t  *logblocks,
        int             blocklog)
 {
-       __uint64_t      tmp_logblocks;
+       uint64_t        tmp_logblocks;
 
        /*
         * Make sure that the log size is a multiple of the stripe unit
@@ -1131,7 +918,7 @@ fixup_internal_log_stripe(
        xfs_mount_t     *mp,
        int             lsflag,
        xfs_fsblock_t   logstart,
-       __uint64_t      agsize,
+       uint64_t        agsize,
        int             sunit,
        xfs_rfsblock_t  *logblocks,
        int             blocklog,
@@ -1155,7 +942,7 @@ fixup_internal_log_stripe(
 }
 
 void
-validate_log_size(__uint64_t logblocks, int blocklog, int min_logblocks)
+validate_log_size(uint64_t logblocks, int blocklog, int min_logblocks)
 {
        if (logblocks < min_logblocks) {
                fprintf(stderr,
@@ -1180,7 +967,7 @@ validate_log_size(__uint64_t logblocks, int blocklog, int min_logblocks)
 static int
 calc_default_imaxpct(
        int             blocklog,
-       __uint64_t      dblocks)
+       uint64_t        dblocks)
 {
        /*
         * This returns the % of the disk space that is used for
@@ -1199,86 +986,12 @@ calc_default_imaxpct(
        return 1;
 }
 
-
-void
-calc_default_ag_geometry(
-       int             blocklog,
-       __uint64_t      dblocks,
-       int             multidisk,
-       __uint64_t      *agsize,
-       __uint64_t      *agcount)
-{
-       __uint64_t      blocks = 0;
-       int             shift = 0;
-
-       /*
-        * First handle the high extreme - the point at which we will
-        * always use the maximum AG size.
-        *
-        * This applies regardless of storage configuration.
-        */
-       if (dblocks >= TERABYTES(32, blocklog)) {
-               blocks = XFS_AG_MAX_BLOCKS(blocklog);
-               goto done;
-       }
-
-       /*
-        * For a single underlying storage device over 4TB in size
-        * use the maximum AG size.  Between 128MB and 4TB, just use
-        * 4 AGs and scale up smoothly between min/max AG sizes.
-        */
-       if (!multidisk) {
-               if (dblocks >= TERABYTES(4, blocklog)) {
-                       blocks = XFS_AG_MAX_BLOCKS(blocklog);
-                       goto done;
-               } else if (dblocks >= MEGABYTES(128, blocklog)) {
-                       shift = XFS_NOMULTIDISK_AGLOG;
-                       goto calc_blocks;
-               }
-       }
-
-       /*
-        * For the multidisk configs we choose an AG count based on the number
-        * of data blocks available, trying to keep the number of AGs higher
-        * than the single disk configurations. This makes the assumption that
-        * larger filesystems have more parallelism available to them.
-        */
-       shift = XFS_MULTIDISK_AGLOG;
-       if (dblocks <= GIGABYTES(512, blocklog))
-               shift--;
-       if (dblocks <= GIGABYTES(8, blocklog))
-               shift--;
-       if (dblocks < MEGABYTES(128, blocklog))
-               shift--;
-       if (dblocks < MEGABYTES(64, blocklog))
-               shift--;
-       if (dblocks < MEGABYTES(32, blocklog))
-               shift--;
-
-       /*
-        * If dblocks is not evenly divisible by the number of
-        * desired AGs, round "blocks" up so we don't lose the
-        * last bit of the filesystem. The same principle applies
-        * to the AG count, so we don't lose the last AG!
-        */
-calc_blocks:
-       ASSERT(shift >= 0 && shift <= XFS_MULTIDISK_AGLOG);
-       blocks = dblocks >> shift;
-       if (dblocks & xfs_mask32lo(shift)) {
-               if (blocks < XFS_AG_MAX_BLOCKS(blocklog))
-                   blocks++;
-       }
-done:
-       *agsize = blocks;
-       *agcount = dblocks / blocks + (dblocks % blocks != 0);
-}
-
 static void
 validate_ag_geometry(
        int             blocklog,
-       __uint64_t      dblocks,
-       __uint64_t      agsize,
-       __uint64_t      agcount)
+       uint64_t        dblocks,
+       uint64_t        agsize,
+       uint64_t        agcount)
 {
        if (agsize < XFS_AG_MIN_BLOCKS(blocklog)) {
                fprintf(stderr,
@@ -1354,7 +1067,7 @@ zero_old_xfs_structures(
 {
        void                    *buf;
        xfs_sb_t                sb;
-       __uint32_t              bsize;
+       uint32_t                bsize;
        int                     i;
        xfs_off_t               off;
 
@@ -1407,8 +1120,8 @@ zero_old_xfs_structures(
                        i != sb.sb_blocklog)
                goto done;
 
-       if (sb.sb_dblocks > ((__uint64_t)sb.sb_agcount * sb.sb_agblocks) ||
-                       sb.sb_dblocks < ((__uint64_t)(sb.sb_agcount - 1) *
+       if (sb.sb_dblocks > ((uint64_t)sb.sb_agcount * sb.sb_agblocks) ||
+                       sb.sb_dblocks < ((uint64_t)(sb.sb_agcount - 1) *
                                         sb.sb_agblocks + XFS_MIN_AG_BLOCKS))
                goto done;
 
@@ -1419,7 +1132,7 @@ zero_old_xfs_structures(
        off = 0;
        for (i = 1; i < sb.sb_agcount; i++)  {
                off += sb.sb_agblocks;
-               if (pwrite64(xi->dfd, buf, new_sb->sb_sectsize,
+               if (pwrite(xi->dfd, buf, new_sb->sb_sectsize,
                                        off << sb.sb_blocklog) == -1)
                        break;
        }
@@ -1428,7 +1141,7 @@ done:
 }
 
 static void
-discard_blocks(dev_t dev, __uint64_t nsectors)
+discard_blocks(dev_t dev, uint64_t nsectors)
 {
        int fd;
 
@@ -1454,6 +1167,8 @@ struct sb_feat_args {
        bool    crcs_enabled;
        bool    dirftype;
        bool    parent_pointers;
+       bool    rmapbt;
+       bool    reflink;
 };
 
 static void
@@ -1524,6 +1239,10 @@ sb_set_features(
 
        if (fp->finobt)
                sbp->sb_features_ro_compat = XFS_SB_FEAT_RO_COMPAT_FINOBT;
+       if (fp->rmapbt)
+               sbp->sb_features_ro_compat |= XFS_SB_FEAT_RO_COMPAT_RMAPBT;
+       if (fp->reflink)
+               sbp->sb_features_ro_compat |= XFS_SB_FEAT_RO_COMPAT_REFLINK;
 
        /*
         * Sparse inode chunk support has two main inode alignment requirements.
@@ -1570,7 +1289,7 @@ check_opt(
 
        if (sp->index != index) {
                fprintf(stderr,
-       ("Developer screwed up option parsing (%d/%d)! Please report!\n"),
+       _("Developer screwed up option parsing (%d/%d)! Please report!\n"),
                        sp->index, index);
                reqval(opts->name, (char **)opts->subopts, index);
        }
@@ -1684,11 +1403,11 @@ main(
        int                     argc,
        char                    **argv)
 {
-       __uint64_t              agcount;
+       uint64_t                agcount;
        xfs_agf_t               *agf;
        xfs_agi_t               *agi;
        xfs_agnumber_t          agno;
-       __uint64_t              agsize;
+       uint64_t                agsize;
        xfs_alloc_rec_t         *arec;
        struct xfs_btree_block  *block;
        int                     blflag;
@@ -1708,6 +1427,7 @@ main(
        int                     dsw;
        int                     dsunit;
        int                     dswidth;
+       int                     dsflag;
        int                     force_overwrite;
        struct fsxattr          fsx;
        int                     ilflag;
@@ -1763,10 +1483,10 @@ main(
        char                    *rtsize;
        xfs_sb_t                *sbp;
        int                     sectorlog;
-       __uint64_t              sector_mask;
+       uint64_t                sector_mask;
        int                     slflag;
        int                     ssflag;
-       __uint64_t              tmp_agsize;
+       uint64_t                tmp_agsize;
        uuid_t                  uuid;
        int                     worst_freelist;
        libxfs_init_t           xi;
@@ -1784,6 +1504,8 @@ main(
                .crcs_enabled = true,
                .dirftype = true,
                .parent_pointers = false,
+               .rmapbt = false,
+               .reflink = false,
        };
 
        platform_uuid_generate(&uuid);
@@ -1808,7 +1530,7 @@ main(
        dfile = logfile = rtfile = NULL;
        dsize = logsize = rtsize = rtextsize = protofile = NULL;
        dsu = dsw = dsunit = dswidth = lalign = lsu = lsunit = 0;
-       nodsflag = norsflag = 0;
+       dsflag = nodsflag = norsflag = 0;
        force_overwrite = 0;
        worst_freelist = 0;
        memset(&fsx, 0, sizeof(fsx));
@@ -1829,8 +1551,7 @@ main(
                                char    **subopts = (char **)bopts.subopts;
                                char    *value;
 
-                               switch (getsubopt(&p, (constpp)subopts,
-                                                 &value)) {
+                               switch (getsubopt(&p, subopts, &value)) {
                                case B_LOG:
                                        blocklog = getnum(value, &bopts, B_LOG);
                                        blocksize = 1 << blocklog;
@@ -1853,8 +1574,7 @@ main(
                                char    **subopts = (char **)dopts.subopts;
                                char    *value;
 
-                               switch (getsubopt(&p, (constpp)subopts,
-                                                 &value)) {
+                               switch (getsubopt(&p, subopts, &value)) {
                                case D_AGCOUNT:
                                        agcount = getnum(value, &dopts,
                                                         D_AGCOUNT);
@@ -1876,16 +1596,20 @@ main(
                                        break;
                                case D_SUNIT:
                                        dsunit = getnum(value, &dopts, D_SUNIT);
+                                       dsflag = 1;
                                        break;
                                case D_SWIDTH:
                                        dswidth = getnum(value, &dopts,
                                                         D_SWIDTH);
+                                       dsflag = 1;
                                        break;
                                case D_SU:
                                        dsu = getnum(value, &dopts, D_SU);
+                                       dsflag = 1;
                                        break;
                                case D_SW:
                                        dsw = getnum(value, &dopts, D_SW);
+                                       dsflag = 1;
                                        break;
                                case D_NOALIGN:
                                        nodsflag = getnum(value, &dopts,
@@ -1922,6 +1646,13 @@ main(
                                        fsx.fsx_xflags |=
                                                XFS_DIFLAG_EXTSZINHERIT;
                                        break;
+                               case D_COWEXTSIZE:
+                                       fsx.fsx_cowextsize = getnum(value,
+                                                       &dopts,
+                                                       D_COWEXTSIZE);
+                                       fsx.fsx_xflags |=
+                                               FS_XFLAG_COWEXTSIZE;
+                                       break;
                                default:
                                        unknown('d', value);
                                }
@@ -1933,8 +1664,7 @@ main(
                                char    **subopts = (char **)iopts.subopts;
                                char    *value;
 
-                               switch (getsubopt(&p, (constpp)subopts,
-                                                 &value)) {
+                               switch (getsubopt(&p, subopts, &value)) {
                                case I_ALIGN:
                                        sb_feat.inode_align = getnum(value,
                                                                &iopts, I_ALIGN);
@@ -1983,8 +1713,7 @@ main(
                                char    **subopts = (char **)lopts.subopts;
                                char    *value;
 
-                               switch (getsubopt(&p, (constpp)subopts,
-                                                 &value)) {
+                               switch (getsubopt(&p, subopts, &value)) {
                                case L_AGNUM:
                                        logagno = getnum(value, &lopts, L_AGNUM);
                                        laflag = 1;
@@ -2055,8 +1784,7 @@ main(
                                char    **subopts = (char **)mopts.subopts;
                                char    *value;
 
-                               switch (getsubopt(&p, (constpp)subopts,
-                                                 &value)) {
+                               switch (getsubopt(&p, subopts, &value)) {
                                case M_CRC:
                                        sb_feat.crcs_enabled =
                                                getnum(value, &mopts, M_CRC);
@@ -2073,6 +1801,14 @@ main(
                                        if (platform_uuid_parse(value, &uuid))
                                                illegal(optarg, "m uuid");
                                        break;
+                               case M_RMAPBT:
+                                       sb_feat.rmapbt = getnum(
+                                               value, &mopts, M_RMAPBT);
+                                       break;
+                               case M_REFLINK:
+                                       sb_feat.reflink = getnum(
+                                               value, &mopts, M_REFLINK);
+                                       break;
                                default:
                                        unknown('m', value);
                                }
@@ -2084,8 +1820,7 @@ main(
                                char    **subopts = (char **)nopts.subopts;
                                char    *value;
 
-                               switch (getsubopt(&p, (constpp)subopts,
-                                                 &value)) {
+                               switch (getsubopt(&p, subopts, &value)) {
                                case N_LOG:
                                        dirblocklog = getnum(value, &nopts,
                                                             N_LOG);
@@ -2140,8 +1875,7 @@ main(
                                char    **subopts = (char **)ropts.subopts;
                                char    *value;
 
-                               switch (getsubopt(&p, (constpp)subopts,
-                                                 &value)) {
+                               switch (getsubopt(&p, subopts, &value)) {
                                case R_EXTSIZE:
                                        rtextsize = getstr(value, &ropts,
                                                           R_EXTSIZE);
@@ -2173,8 +1907,7 @@ main(
                                char    **subopts = (char **)sopts.subopts;
                                char    *value;
 
-                               switch (getsubopt(&p, (constpp)subopts,
-                                                 &value)) {
+                               switch (getsubopt(&p, subopts, &value)) {
                                case S_LOG:
                                case S_SECTLOG:
                                        if (lssflag)
@@ -2388,24 +2121,53 @@ _("32 bit Project IDs always enabled on CRC enabled filesytems\n"));
        } else {
                /*
                 * The kernel doesn't currently support crc=0,finobt=1
-                * filesystems. If crcs are not enabled and the user has
-                * explicitly turned them off then silently turn them off
-                * to avoid an unnecessary warning. If the user explicitly
-                * tried to use crc=0,finobt=1, then issue a warning before
-                * turning them off. The same is also for sparse inodes.
+                * 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.
                 */
                if (sb_feat.finobt && mopts.subopt_params[M_FINOBT].seen) {
                        fprintf(stderr,
-_("warning: finobt not supported without CRC support, disabled.\n"));
+_("finobt not supported without CRC support\n"));
+                       usage();
                }
                sb_feat.finobt = 0;
 
                if (sb_feat.spinodes) {
                        fprintf(stderr,
-       _("warning: sparse inodes not supported without CRC support, disabled.\n"));
+_("sparse inodes not supported without CRC support\n"));
+                       usage();
                }
                sb_feat.spinodes = 0;
 
+               if (sb_feat.rmapbt) {
+                       fprintf(stderr,
+_("rmapbt not supported without CRC support\n"));
+                       usage();
+               }
+               sb_feat.rmapbt = false;
+
+               if (sb_feat.reflink) {
+                       fprintf(stderr,
+_("reflink not supported without CRC support\n"));
+                       usage();
+               }
+               sb_feat.reflink = false;
+       }
+
+       if ((fsx.fsx_xflags & FS_XFLAG_COWEXTSIZE) && !sb_feat.reflink) {
+               fprintf(stderr,
+_("cowextsize not supported without reflink support\n"));
+               usage();
+       }
+
+       if (sb_feat.rmapbt && xi.rtname) {
+               fprintf(stderr,
+_("rmapbt not supported with realtime devices\n"));
+               usage();
+               sb_feat.rmapbt = false;
        }
 
        if (nsflag || nlflag) {
@@ -2425,7 +2187,7 @@ _("warning: finobt not supported without CRC support, disabled.\n"));
 
 
        if (dsize) {
-               __uint64_t dbytes;
+               uint64_t dbytes;
 
                dbytes = getnum(dsize, &dopts, D_SIZE);
                if (dbytes % XFS_MIN_BLOCKSIZE) {
@@ -2457,7 +2219,7 @@ _("warning: finobt not supported without CRC support, disabled.\n"));
        }
 
        if (logsize) {
-               __uint64_t logbytes;
+               uint64_t logbytes;
 
                logbytes = getnum(logsize, &lopts, L_SIZE);
                if (logbytes % XFS_MIN_BLOCKSIZE) {
@@ -2474,7 +2236,7 @@ _("warning: finobt not supported without CRC support, disabled.\n"));
                                (long long)(logblocks << blocklog));
        }
        if (rtsize) {
-               __uint64_t rtbytes;
+               uint64_t rtbytes;
 
                rtbytes = getnum(rtsize, &ropts, R_SIZE);
                if (rtbytes % XFS_MIN_BLOCKSIZE) {
@@ -2494,7 +2256,7 @@ _("warning: finobt not supported without CRC support, disabled.\n"));
         * If specified, check rt extent size against its constraints.
         */
        if (rtextsize) {
-               __uint64_t rtextbytes;
+               uint64_t rtextbytes;
 
                rtextbytes = getnum(rtextsize, &ropts, R_EXTSIZE);
                if (rtextbytes % blocksize) {
@@ -2510,8 +2272,8 @@ _("warning: finobt not supported without CRC support, disabled.\n"));
                 * and the underlying volume is striped, then set rtextblocks
                 * to the stripe width.
                 */
-               __uint64_t      rswidth;
-               __uint64_t      rtextbytes;
+               uint64_t        rswidth;
+               uint64_t        rtextbytes;
 
                if (!norsflag && !xi.risfile && !(!rtsize && xi.disfile))
                        rswidth = ft.rtswidth;
@@ -2566,6 +2328,10 @@ _("warning: finobt not supported without CRC support, disabled.\n"));
        calc_stripe_factors(dsu, dsw, sectorsize, lsu, lsectorsize,
                                &dsunit, &dswidth, &lsunit);
 
+       /* If sunit & swidth were manually specified as 0, same as noalign */
+       if (dsflag && !dsunit && !dswidth)
+               nodsflag = 1;
+
        xi.setblksize = sectorsize;
 
        /*
@@ -2589,10 +2355,10 @@ _("warning: finobt not supported without CRC support, disabled.\n"));
         * multiple of the sector size, or 1024, whichever is larger.
         */
 
-       sector_mask = (__uint64_t)-1 << (MAX(sectorlog, 10) - BBSHIFT);
+       sector_mask = (uint64_t)-1 << (MAX(sectorlog, 10) - BBSHIFT);
        xi.dsize &= sector_mask;
        xi.rtsize &= sector_mask;
-       xi.logBBsize &= (__uint64_t)-1 << (MAX(lsectorlog, 10) - BBSHIFT);
+       xi.logBBsize &= (uint64_t)-1 << (MAX(lsectorlog, 10) - BBSHIFT);
 
 
        /* don't do discards on print-only runs or on files */
@@ -2788,7 +2554,9 @@ reported by the device (%u).\n"),
                                }
                        }
                }
-               if (dswidth && ((agsize % dswidth) == 0) && (agcount > 1)) {
+               if (dswidth && ((agsize % dswidth) == 0)
+                           && (dswidth != dsunit)
+                           && (agcount > 1)) {
                        /* This is a non-optimal configuration because all AGs
                         * start on the same disk in the stripe.  Changing
                         * the AG size by one sunit will guarantee that this
@@ -2859,12 +2627,6 @@ an AG size that is one stripe unit smaller, for example %llu.\n"),
         */
 
        if (lsunit) {
-               if ((BBTOB(lsunit) % blocksize != 0)) {
-                       fprintf(stderr,
-       _("log stripe unit (%d) must be a multiple of the block size (%d)\n"),
-                       BBTOB(lsunit), blocksize);
-                       exit(1);
-               }
                /* convert from 512 byte blocks to fs blocks */
                lsunit = DTOBT(lsunit);
        } else if (sb_feat.log_version == 2 && loginternal && dsunit) {
@@ -2884,9 +2646,12 @@ an AG size that is one stripe unit smaller, for example %llu.\n"),
                lsunit = (32 * 1024) >> blocklog;
        }
 
-       min_logblocks = max_trans_res(sb_feat.crcs_enabled, sb_feat.dir_version,
+       min_logblocks = max_trans_res(agsize,
+                                  sb_feat.crcs_enabled, sb_feat.dir_version,
                                   sectorlog, blocklog, inodelog, dirblocklog,
-                                  sb_feat.log_version, lsunit, sb_feat.finobt);
+                                  sb_feat.log_version, lsunit, sb_feat.finobt,
+                                  sb_feat.rmapbt, sb_feat.reflink,
+                                  sb_feat.inode_align);
        ASSERT(min_logblocks);
        min_logblocks = MAX(XFS_MIN_LOG_BLOCKS, min_logblocks);
        if (!logsize && dblocks >= (1024*1024*1024) >> blocklog)
@@ -2953,16 +2718,16 @@ _("size %s specified for log subvolume is too large, maximum is %lld blocks\n"),
        mp = &mbuf;
        sbp = &mp->m_sb;
        memset(mp, 0, sizeof(xfs_mount_t));
-       sbp->sb_blocklog = (__uint8_t)blocklog;
-       sbp->sb_sectlog = (__uint8_t)sectorlog;
-       sbp->sb_agblklog = (__uint8_t)libxfs_log2_roundup((unsigned int)agsize);
+       sbp->sb_blocklog = (uint8_t)blocklog;
+       sbp->sb_sectlog = (uint8_t)sectorlog;
+       sbp->sb_agblklog = (uint8_t)libxfs_log2_roundup((unsigned int)agsize);
        sbp->sb_agblocks = (xfs_agblock_t)agsize;
        mp->m_blkbb_log = sbp->sb_blocklog - BBSHIFT;
        mp->m_sectbb_log = sbp->sb_sectlog - BBSHIFT;
 
        /*
-        * sb_versionnum and finobt flags must be set before we use
-        * XFS_PREALLOC_BLOCKS().
+        * sb_versionnum, finobt and rmapbt flags must be set before we use
+        * libxfs_prealloc_blocks().
         */
        sb_set_features(&mp->m_sb, &sb_feat, sectorsize, lsectorsize, dsunit);
 
@@ -2974,12 +2739,12 @@ _("size %s specified for log subvolume is too large, maximum is %lld blocks\n"),
                 */
                if (!logsize) {
                        logblocks = MIN(logblocks,
-                                       XFS_ALLOC_AG_MAX_USABLE(mp));
+                                       libxfs_alloc_ag_max_usable(mp));
 
                        /* revalidate the log size is valid if we changed it */
                        validate_log_size(logblocks, blocklog, min_logblocks);
                }
-               if (logblocks > agsize - XFS_PREALLOC_BLOCKS(mp)) {
+               if (logblocks > agsize - libxfs_prealloc_blocks(mp)) {
                        fprintf(stderr,
        _("internal log size %lld too large, must fit in allocation group\n"),
                                (long long)logblocks);
@@ -2996,7 +2761,7 @@ _("size %s specified for log subvolume is too large, maximum is %lld blocks\n"),
                } else
                        logagno = (xfs_agnumber_t)(agcount / 2);
 
-               logstart = XFS_AGB_TO_FSB(mp, logagno, XFS_PREALLOC_BLOCKS(mp));
+               logstart = XFS_AGB_TO_FSB(mp, logagno, libxfs_prealloc_blocks(mp));
                /*
                 * Align the logstart at stripe unit boundary.
                 */
@@ -3021,7 +2786,7 @@ _("size %s specified for log subvolume is too large, maximum is %lld blocks\n"),
                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\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"
@@ -3032,6 +2797,7 @@ _("size %s specified for log subvolume is too large, maximum is %lld blocks\n"),
                        "", sectorsize, sb_feat.attr_version,
                                    !sb_feat.projid16bit,
                        "", sb_feat.crcs_enabled, sb_feat.finobt, sb_feat.spinodes,
+                       sb_feat.rmapbt, sb_feat.reflink,
                        "", blocksize, (long long)dblocks, imaxpct,
                        "", dsunit, dswidth,
                        sb_feat.dir_version, dirblocksize, sb_feat.nci,
@@ -3061,20 +2827,20 @@ _("size %s specified for log subvolume is too large, maximum is %lld blocks\n"),
        sbp->sb_agcount = (xfs_agnumber_t)agcount;
        sbp->sb_rbmblocks = nbmblocks;
        sbp->sb_logblocks = (xfs_extlen_t)logblocks;
-       sbp->sb_sectsize = (__uint16_t)sectorsize;
-       sbp->sb_inodesize = (__uint16_t)isize;
-       sbp->sb_inopblock = (__uint16_t)(blocksize / isize);
-       sbp->sb_sectlog = (__uint8_t)sectorlog;
-       sbp->sb_inodelog = (__uint8_t)inodelog;
-       sbp->sb_inopblog = (__uint8_t)(blocklog - inodelog);
+       sbp->sb_sectsize = (uint16_t)sectorsize;
+       sbp->sb_inodesize = (uint16_t)isize;
+       sbp->sb_inopblock = (uint16_t)(blocksize / isize);
+       sbp->sb_sectlog = (uint8_t)sectorlog;
+       sbp->sb_inodelog = (uint8_t)inodelog;
+       sbp->sb_inopblog = (uint8_t)(blocklog - inodelog);
        sbp->sb_rextslog =
-               (__uint8_t)(rtextents ?
+               (uint8_t)(rtextents ?
                        libxfs_highbit32((unsigned int)rtextents) : 0);
        sbp->sb_inprogress = 1; /* mkfs is in progress */
        sbp->sb_imax_pct = imaxpct;
        sbp->sb_icount = 0;
        sbp->sb_ifree = 0;
-       sbp->sb_fdblocks = dblocks - agcount * XFS_PREALLOC_BLOCKS(mp) -
+       sbp->sb_fdblocks = dblocks - agcount * libxfs_prealloc_blocks(mp) -
                (loginternal ? logblocks : 0);
        sbp->sb_frextents = 0;  /* will do a free later */
        sbp->sb_uquotino = sbp->sb_gquotino = sbp->sb_pquotino = 0;
@@ -3096,8 +2862,8 @@ _("size %s specified for log subvolume is too large, maximum is %lld blocks\n"),
        } else
                sbp->sb_inoalignmt = 0;
        if (lsectorsize != BBSIZE || sectorsize != BBSIZE) {
-               sbp->sb_logsectlog = (__uint8_t)lsectorlog;
-               sbp->sb_logsectsize = (__uint16_t)lsectorsize;
+               sbp->sb_logsectlog = (uint8_t)lsectorlog;
+               sbp->sb_logsectsize = (uint16_t)lsectorsize;
        } else {
                sbp->sb_logsectlog = 0;
                sbp->sb_logsectsize = 0;
@@ -3134,7 +2900,7 @@ _("size %s specified for log subvolume is too large, maximum is %lld blocks\n"),
         * code will succeed.
         */
        if (xi.disfile && xi.dsize * xi.dbsize < dblocks * blocksize) {
-               if (ftruncate64(xi.dfd, dblocks * blocksize) < 0) {
+               if (ftruncate(xi.dfd, dblocks * blocksize) < 0) {
                        fprintf(stderr,
                                _("%s: Growing the data section failed\n"),
                                progname);
@@ -3179,7 +2945,7 @@ _("size %s specified for log subvolume is too large, maximum is %lld blocks\n"),
        for (agno = 0; agno < agcount; agno++) {
                struct xfs_agfl *agfl;
                int             bucket;
-               struct xfs_perag *pag = xfs_perag_get(mp, agno);
+               struct xfs_perag *pag = libxfs_perag_get(mp, agno);
 
                /*
                 * Superblock.
@@ -3213,10 +2979,22 @@ _("size %s specified for log subvolume is too large, maximum is %lld blocks\n"),
                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(&mp->m_sb)) {
+                       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);
+               }
+               if (xfs_sb_version_hasreflink(&mp->m_sb)) {
+                       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);
+               }
                agf->agf_flfirst = 0;
                agf->agf_fllast = cpu_to_be32(XFS_AGFL_SIZE(mp) - 1);
                agf->agf_flcount = 0;
-               nbmblocks = (xfs_extlen_t)(agsize - XFS_PREALLOC_BLOCKS(mp));
+               nbmblocks = (xfs_extlen_t)(agsize - libxfs_prealloc_blocks(mp));
                agf->agf_freeblks = cpu_to_be32(nbmblocks);
                agf->agf_longest = cpu_to_be32(nbmblocks);
                if (xfs_sb_version_hascrc(&mp->m_sb))
@@ -3227,8 +3005,8 @@ _("size %s specified for log subvolume is too large, maximum is %lld blocks\n"),
                        agf->agf_longest = cpu_to_be32(agsize -
                                XFS_FSB_TO_AGBNO(mp, logstart) - logblocks);
                }
-               if (xfs_alloc_min_freelist(mp, pag) > worst_freelist)
-                       worst_freelist = xfs_alloc_min_freelist(mp, pag);
+               if (libxfs_alloc_min_freelist(mp, pag) > worst_freelist)
+                       worst_freelist = libxfs_alloc_min_freelist(mp, pag);
                libxfs_writebuf(buf, LIBXFS_EXIT_ON_FAILURE);
 
                /*
@@ -3289,15 +3067,10 @@ _("size %s specified for log subvolume is too large, maximum is %lld blocks\n"),
                buf->b_ops = &xfs_allocbt_buf_ops;
                block = XFS_BUF_TO_BLOCK(buf);
                memset(block, 0, blocksize);
-               if (xfs_sb_version_hascrc(&mp->m_sb))
-                       xfs_btree_init_block(mp, buf, XFS_ABTB_CRC_MAGIC, 0, 1,
-                                               agno, XFS_BTREE_CRC_BLOCKS);
-               else
-                       xfs_btree_init_block(mp, buf, XFS_ABTB_MAGIC, 0, 1,
-                                               agno, 0);
+               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(XFS_PREALLOC_BLOCKS(mp));
+               arec->ar_startblock = cpu_to_be32(libxfs_prealloc_blocks(mp));
                if (loginternal && agno == logagno) {
                        if (lalign) {
                                /*
@@ -3344,15 +3117,10 @@ _("size %s specified for log subvolume is too large, maximum is %lld blocks\n"),
                buf->b_ops = &xfs_allocbt_buf_ops;
                block = XFS_BUF_TO_BLOCK(buf);
                memset(block, 0, blocksize);
-               if (xfs_sb_version_hascrc(&mp->m_sb))
-                       xfs_btree_init_block(mp, buf, XFS_ABTC_CRC_MAGIC, 0, 1,
-                                               agno, XFS_BTREE_CRC_BLOCKS);
-               else
-                       xfs_btree_init_block(mp, buf, XFS_ABTC_MAGIC, 0, 1,
-                                               agno, 0);
+               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(XFS_PREALLOC_BLOCKS(mp));
+               arec->ar_startblock = cpu_to_be32(libxfs_prealloc_blocks(mp));
                if (loginternal && agno == logagno) {
                        if (lalign) {
                                arec->ar_blockcount = cpu_to_be32(
@@ -3380,6 +3148,24 @@ _("size %s specified for log subvolume is too large, maximum is %lld blocks\n"),
 
                libxfs_writebuf(buf, LIBXFS_EXIT_ON_FAILURE);
 
+               /*
+                * refcount btree root block
+                */
+               if (xfs_sb_version_hasreflink(&mp->m_sb)) {
+                       buf = libxfs_getbuf(mp->m_ddev_targp,
+                                       XFS_AGB_TO_DADDR(mp, agno,
+                                               libxfs_refc_block(mp)),
+                                       bsize);
+                       buf->b_ops = &xfs_refcountbt_buf_ops;
+
+                       block = XFS_BUF_TO_BLOCK(buf);
+                       memset(block, 0, 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
                 */
@@ -3389,36 +3175,101 @@ _("size %s specified for log subvolume is too large, maximum is %lld blocks\n"),
                buf->b_ops = &xfs_inobt_buf_ops;
                block = XFS_BUF_TO_BLOCK(buf);
                memset(block, 0, blocksize);
-               if (xfs_sb_version_hascrc(&mp->m_sb))
-                       xfs_btree_init_block(mp, buf, XFS_IBT_CRC_MAGIC, 0, 0,
-                                               agno, XFS_BTREE_CRC_BLOCKS);
-               else
-                       xfs_btree_init_block(mp, buf, XFS_IBT_MAGIC, 0, 0,
-                                               agno, 0);
+               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 (!sb_feat.finobt) {
-                       xfs_perag_put(pag);
-                       continue;
+               if (sb_feat.finobt) {
+                       buf = libxfs_getbuf(mp->m_ddev_targp,
+                                       XFS_AGB_TO_DADDR(mp, agno, XFS_FIBT_BLOCK(mp)),
+                                       bsize);
+                       buf->b_ops = &xfs_inobt_buf_ops;
+                       block = XFS_BUF_TO_BLOCK(buf);
+                       memset(block, 0, blocksize);
+                       libxfs_btree_init_block(mp, buf, XFS_BTNUM_FINO, 0, 0, agno, 0);
+                       libxfs_writebuf(buf, LIBXFS_EXIT_ON_FAILURE);
                }
 
-               buf = libxfs_getbuf(mp->m_ddev_targp,
-                               XFS_AGB_TO_DADDR(mp, agno, XFS_FIBT_BLOCK(mp)),
+               /* RMAP btree root block */
+               if (xfs_sb_version_hasrmapbt(&mp->m_sb)) {
+                       struct xfs_rmap_rec     *rrec;
+
+                       buf = libxfs_getbuf(mp->m_ddev_targp,
+                               XFS_AGB_TO_DADDR(mp, agno, XFS_RMAP_BLOCK(mp)),
                                bsize);
-               buf->b_ops = &xfs_inobt_buf_ops;
-               block = XFS_BUF_TO_BLOCK(buf);
-               memset(block, 0, blocksize);
-               if (xfs_sb_version_hascrc(&mp->m_sb))
-                       xfs_btree_init_block(mp, buf, XFS_FIBT_CRC_MAGIC, 0, 0,
-                                               agno, XFS_BTREE_CRC_BLOCKS);
-               else
-                       xfs_btree_init_block(mp, buf, XFS_FIBT_MAGIC, 0, 0,
-                                               agno, 0);
-               libxfs_writebuf(buf, LIBXFS_EXIT_ON_FAILURE);
-               xfs_perag_put(pag);
+                       buf->b_ops = &xfs_rmapbt_buf_ops;
+                       block = XFS_BUF_TO_BLOCK(buf);
+                       memset(block, 0, 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(&mp->m_sb)) {
+                               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 (loginternal && agno == logagno) {
+                               rrec = XFS_RMAP_REC_ADDR(block,
+                                       be16_to_cpu(block->bb_numrecs) + 1);
+                               rrec->rm_startblock = cpu_to_be32(
+                                               XFS_FSB_TO_AGBNO(mp, logstart));
+                               rrec->rm_blockcount = cpu_to_be32(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);
        }
 
        /*
@@ -3447,18 +3298,19 @@ _("size %s specified for log subvolume is too large, maximum is %lld blocks\n"),
                xfs_trans_t     *tp;
                struct xfs_trans_res tres = {0};
 
+               c = libxfs_trans_alloc(mp, &tres, worst_freelist, 0, 0, &tp);
+               if (c)
+                       res_failed(c);
+
                memset(&args, 0, sizeof(args));
-               args.tp = tp = libxfs_trans_alloc(mp, 0);
+               args.tp = tp;
                args.mp = mp;
                args.agno = agno;
                args.alignment = 1;
-               args.pag = xfs_perag_get(mp,agno);
-               c = -libxfs_trans_reserve(tp, &tres, worst_freelist, 0);
-               if (c)
-                       res_failed(c);
+               args.pag = libxfs_perag_get(mp,agno);
 
                libxfs_alloc_fix_freelist(&args, 0);
-               xfs_perag_put(args.pag);
+               libxfs_perag_put(args.pag);
                libxfs_trans_commit(tp);
        }
 
@@ -3611,23 +3463,42 @@ cvtnum(
        if (sp[1] != '\0')
                return -1LL;
 
-       if (*sp == 'b')
-               return i * blksize;
-       if (*sp == 's')
-               return i * sectsize;
+       if (*sp == 'b') {
+               if (!blksize) {
+                       fprintf(stderr,
+_("Blocksize must be provided prior to using 'b' suffix.\n"));
+                       usage();
+               } else {
+                       return i * blksize;
+               }
+       }
+       if (*sp == 's') {
+               if (!sectsize) {
+                       fprintf(stderr,
+_("Sectorsize must be specified prior to using 's' suffix.\n"));
+                       usage();
+               } else {
+                       return i * sectsize;
+               }
+       }
 
        c = tolower(*sp);
        switch (c) {
        case 'e':
                i *= 1024LL;
+               /* fall through */
        case 'p':
                i *= 1024LL;
+               /* fall through */
        case 't':
                i *= 1024LL;
+               /* fall through */
        case 'g':
                i *= 1024LL;
+               /* fall through */
        case 'm':
                i *= 1024LL;
+               /* fall through */
        case 'k':
                return i * 1024LL;
        default:
@@ -3641,7 +3512,7 @@ usage( void )
 {
        fprintf(stderr, _("Usage: %s\n\
 /* blocksize */                [-b log=n|size=num]\n\
-/* metadata */         [-m crc=0|1,finobt=0|1,uuid=xxx]\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\