]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blobdiff - mkfs/xfs_mkfs.c
Undoes mod: xfs-cmds:slinx:120772a
[thirdparty/xfsprogs-dev.git] / mkfs / xfs_mkfs.c
index 3a4650cfb8e57d6fc9adbc6a7f150c068150c207..5c18439db5efcd9d73c2c3f5019a99854279dfc6 100644 (file)
  * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
  */
 
+#include <fstyp.h>
+#include <stdio.h>
+#include <volume.h>
+#include <mountinfo.h>
 #include <libxfs.h>
-#include <fcntl.h>
-#include <errno.h>
+
 #include "xfs_mkfs.h"
-#include "proto.h"
-#include "volume.h"
 #include "maxtrres.h"
-#include "mountinfo.h"
-
-#if HAVE_LIBLVM
-  #include "lvm_user.h"
-
-  char *cmd;           /* Not used. liblvm is broken */
-  int opt_d;           /* Same thing */
-#endif
-
-#include "md-int.h"
+#include "proto.h"
 
 /*
  * Prototypes for internal functions.
@@ -85,6 +77,12 @@ char *dopts[] = {
        "swidth",
 #define D_UNWRITTEN    6
        "unwritten",
+#define D_AGSIZE       7
+       "agsize",
+#define D_SU           8
+       "su",
+#define D_SW           9
+       "sw",
        NULL
 };
 
@@ -260,98 +258,52 @@ static const int max_trres_v2[DFL_B][DFL_I][DFL_D] = {
        (XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) - 1) + (rb)))
 
 static void
-get_subvol_stripe_wrapper(char *dfile, int type, int *sunit, int *swidth)
+calc_stripe_factors(int dsu, int dsw, int *dsunit, int *dswidth)
 {
-       struct stat64 sb;
-       struct md_array_info_s md;
-#if HAVE_LIBLVM
-        lv_t *lv;
-       char *vgname;
-#endif
-
-        if (!dfile)
-                return;
-        
-        if (stat64 (dfile, &sb)) {
-                fprintf (stderr, "Could not stat %s\n", dfile);
-               usage();
-        }
-
-       /* MD volume */
-       if (sb.st_rdev >> 8 == MD_MAJOR) {
-               int fd;
-
-               /* Open device */
-               fd = open (dfile, O_RDONLY);
-               if (fd == -1)
-                       return;
-               
-               /* Is this thing on... */
-               if (ioctl (fd, GET_ARRAY_INFO, &md)) {
-                       fprintf (stderr, "Error getting array info from %s\n",
-                                dfile);
+       if (*dsunit || *dswidth) {
+               if (dsu || dsw) {
+                       fprintf(stderr,
+       "su/sw should not be used in conjunction with sunit/swidth\n");
                        usage();
                }
 
-               /* Check state */
-               if (md.state) {
-                       fprintf (stderr, "MD array %s not in clean state\n",
-                                dfile);
+               if ((*dsunit && !*dswidth) || (!*dsunit && *dswidth)) {
+                       fprintf(stderr,
+       "both sunit and swidth options have to be specified\n");
                        usage();
                }
-
-               /* Deduct a disk from stripe width on RAID4/5 */
-               if (md.level == 4 || md.level == 5)
-                       md.nr_disks--;
-                       
-               /* Update sizes */
-               *sunit = md.chunk_size >> 9;
-               *swidth = *sunit * md.nr_disks;
-
-               return;
        }
 
-#if HAVE_LIBLVM
-       /* LVM volume */
-       if (sb.st_rdev >> 8 == LVM_BLK_MAJOR) {
-
-               /* Find volume group */
-               if (! (vgname = vg_name_of_lv (dfile))) {
-                       fprintf (stderr, "Can't find volume group for %s\n", 
-                                dfile);
-                       usage();
-               }
-               
-               /* Logical volume */
-               if (! lvm_tab_lv_check_exist (dfile)) {
-                       fprintf (stderr, "Logical volume %s doesn't exist!\n",
-                                dfile);
+       if (dsu || dsw) {
+               if (*dsunit || *dswidth) {
+                       fprintf(stderr,
+       "sunit/swidth should not be used in conjunction with su/sw\n");
                        usage();
                }
-               
-               /* Get status */
-               if (lv_status_byname (vgname, dfile, &lv) < 0 || lv == NULL) {
-                       fprintf (stderr, "Could not get status info from %s\n",
-                                dfile);
+
+               if ((dsu && !dsw) || (!dsu && dsw)) {
+                       fprintf(stderr,
+       "both su and sw options have to be specified\n");
                        usage();
                }
-               
-               /* Check that data is consistent */
-               if (lv_check_consistency (lv) < 0) {
-                       fprintf (stderr, "Logical volume %s is inconsistent\n",
-                                dfile);
+
+               if (dsu % BBSIZE) {
+                       fprintf(stderr, "su must be a multiple of %d\n",
+                                                               BBSIZE);
                        usage();
                }
-               
-               /* Update sizes */
-               *sunit = lv->lv_stripesize;
-               *swidth = lv->lv_stripes * lv->lv_stripesize;
-               
-               return;
+
+               *dsunit  = (int)BTOBBT(dsu);
+               *dswidth = *dsunit * dsw;
        }
-#endif /* HAVE_LIBLVM */
-}
 
+       if (*dsunit && (*dswidth % *dsunit != 0)) {
+               fprintf(stderr,
+       "stripe width (%d) has to be a multiple of the stripe unit (%d)\n",
+                       *dswidth, *dsunit);
+               usage();
+       }
+}
 
 static int
 get_default_blocksize(void)
@@ -366,6 +318,28 @@ get_default_blocksize(void)
        return (1 << XFS_DFL_BLOCKSIZE_LOG);
 }
 
+static int
+check_overwrite(char *device)
+{
+       char *type;
+
+       if (device && *device) {
+               if ((type = fstype(device)) != NULL) {
+                       fprintf(stderr,
+               "%s: %s appears to contain an existing filesystem (%s).\n",
+                               progname, device, type);
+                       return 1;
+               }
+               if ((type = pttype(device)) != NULL) {
+                       fprintf(stderr,
+               "%s: %s appears to contain a partition table (%s).\n",
+                               progname, device, type);
+                       return 1;
+               }
+       }
+       return 0;
+}
+
 
 int
 main(int argc, char **argv)
@@ -385,6 +359,7 @@ main(int argc, char **argv)
        xfs_buf_t               *buf;
        int                     c;
        int                     daflag;
+       int                     dasize;
        xfs_drfsbno_t           dblocks;
        char                    *dfile;
        int                     dirblocklog;
@@ -392,10 +367,12 @@ main(int argc, char **argv)
        int                     dirversion;
        int                     do_overlap_checks;
        char                    *dsize;
+       int                     dsu;
+       int                     dsw;
        int                     dsunit;
        int                     dswidth;
        int                     extent_flagging;
-       int                     force_fs_overwrite;
+       int                     force_overwrite;
        int                     i;
        int                     iaflag;
        int                     ilflag;
@@ -406,6 +383,7 @@ main(int argc, char **argv)
        int                     ipflag;
        int                     isflag;
        int                     isize;
+       char                    *label = NULL;
        int                     laflag;
        int                     lalign;
        int                     ldflag;
@@ -441,6 +419,7 @@ main(int argc, char **argv)
        xfs_sb_t                *sbp;
        int                     sectlog;
        __uint64_t              tmp_agsize;
+       __uint64_t              tmp_logblocks;
        uuid_t                  uuid;
        int                     worst_freelist;
        libxfs_init_t           xi;
@@ -450,6 +429,7 @@ main(int argc, char **argv)
        progname = basename(argv[0]);
        agcount = 8;
        blflag = bsflag = 0;
+       dasize = daflag = 0;
        blocksize = get_default_blocksize();
        blocklog = libxfs_highbit32(blocksize);
        agsize = daflag = dblocks = 0;
@@ -468,19 +448,19 @@ main(int argc, char **argv)
        dfile = logfile = rtfile = NULL;
        dsize = logsize = rtsize = rtextsize = protofile = NULL;
        opterr = 0;
-       dsunit = dswidth = nodsflag = lalign = 0;
+       dsu = dsw = dsunit = dswidth = nodsflag = lalign = 0;
        do_overlap_checks = 1;
        extent_flagging = 0;
-       force_fs_overwrite = 0;
+       force_overwrite = 0;
        worst_freelist = 0;
 
-       while ((c = getopt(argc, argv, "b:d:i:l:n:p:qr:CfV")) != EOF) {
+       while ((c = getopt(argc, argv, "b:d:i:l:L:n:p:qr:CfV")) != EOF) {
                switch (c) {
                case 'C':
                        do_overlap_checks = 0;
                        break;
                case 'f':
-                       force_fs_overwrite = 1;
+                       force_overwrite = 1;
                        break;
                case 'b':
                        p = optarg;
@@ -538,6 +518,18 @@ main(int argc, char **argv)
                                                illegal(value, "d agcount");
                                        daflag = 1;
                                        break;
+                               case D_AGSIZE:
+                                       if (!value)
+                                               reqval('d', dopts, D_AGSIZE);
+                                       if (dasize)
+                                               respec('d', dopts, D_AGSIZE);
+                                       if (blflag || bsflag)
+                                               agsize = cvtnum(blocksize,
+                                                               value);
+                                       else
+                                               agsize = cvtnum(0, value);
+                                       dasize = 1;
+                                       break;
                                case D_FILE:
                                        if (!value)
                                                value = "1";
@@ -566,14 +558,36 @@ main(int argc, char **argv)
                                                reqval('d', dopts, D_SUNIT);
                                        if (dsunit)
                                                respec('d', dopts, D_SUNIT);
-                                       dsunit = cvtnum(0, value);
+                                       if (blflag || bsflag)
+                                               dsunit = cvtnum(blocksize,
+                                                               value);
+                                       else
+                                               dsunit = cvtnum(0, value);
                                        break;
                                case D_SWIDTH:
                                        if (!value)
                                                reqval('d', dopts, D_SWIDTH);
                                        if (dswidth)
                                                respec('d', dopts, D_SWIDTH);
-                                       dswidth = cvtnum(0, value);
+                                       if (blflag || bsflag)
+                                               dswidth = cvtnum(blocksize,
+                                                                value);
+                                       else
+                                               dswidth = cvtnum(0, value);
+                                       break;
+                               case D_SU:
+                                       if (!value)
+                                               reqval('d', dopts, D_SU);
+                                       if (dsu)
+                                               respec('d', dopts, D_SU);
+                                       dsu = cvtnum(0, value);
+                                       break;
+                               case D_SW:
+                                       if (!value)
+                                               reqval('d', dopts, D_SW);
+                                       if (dsw)
+                                               respec('d', dopts, D_SW);
+                                       dsw = cvtnum(0, value);
                                        break;
                                case D_UNWRITTEN:
                                        if (!value)
@@ -761,6 +775,11 @@ main(int argc, char **argv)
                                }
                        }
                        break;
+               case 'L':
+                       if (strlen(optarg) > sizeof(sbp->sb_fname))
+                               illegal(optarg, "L");
+                       label = optarg;
+                       break;
                case 'n':
                        p = optarg;
                        while (*p != '\0') {
@@ -871,7 +890,7 @@ main(int argc, char **argv)
                        break;
                case 'V':
                        printf("%s version %s\n", progname, VERSION);
-                       break;
+                       exit(0);
                case '?':
                        unknown(optopt, "");
                }
@@ -922,6 +941,13 @@ main(int argc, char **argv)
                }
                break;
        }
+
+       if (daflag && dasize) {
+               fprintf(stderr,
+       "both -d agcount= and agsize= specified, use one or the other\n");
+               usage();
+       }
+
        if (!daflag)
                agcount = 8;
 
@@ -937,14 +963,15 @@ main(int argc, char **argv)
                if (dbytes % XFS_MIN_BLOCKSIZE) {
                        fprintf(stderr,
                        "illegal data length %lld, not a multiple of %d\n",
-                               dbytes, XFS_MIN_BLOCKSIZE);
+                               (long long)dbytes, XFS_MIN_BLOCKSIZE);
                        usage();
                }
                dblocks = (xfs_drfsbno_t)(dbytes >> blocklog);
                if (dbytes % blocksize)
                        fprintf(stderr,
        "warning: data length %lld not a multiple of %d, truncated to %lld\n",
-                               dbytes, blocksize, dblocks << blocklog);
+                               (long long)dbytes, blocksize,
+                               (long long)(dblocks << blocklog));
        }
        if (ipflag) {
                inodelog = blocklog - libxfs_highbit32(inopblock);
@@ -967,14 +994,15 @@ main(int argc, char **argv)
                if (logbytes % XFS_MIN_BLOCKSIZE) {
                        fprintf(stderr,
                        "illegal log length %lld, not a multiple of %d\n",
-                               logbytes, XFS_MIN_BLOCKSIZE);
+                               (long long)logbytes, XFS_MIN_BLOCKSIZE);
                        usage();
                }
                logblocks = (xfs_drfsbno_t)(logbytes >> blocklog);
                if (logbytes % blocksize)
                        fprintf(stderr,
        "warning: log length %lld not a multiple of %d, truncated to %lld\n",
-                               logbytes, blocksize, logblocks << blocklog);
+                               (long long)logbytes, blocksize,
+                               (long long)(logblocks << blocklog));
        }
 #ifdef HAVE_VOLUME_MANAGER
        if (xi.risfile && (!rtsize || !xi.rtname)) {
@@ -990,14 +1018,15 @@ main(int argc, char **argv)
                if (rtbytes % XFS_MIN_BLOCKSIZE) {
                        fprintf(stderr,
                        "illegal rt length %lld, not a multiple of %d\n",
-                               rtbytes, XFS_MIN_BLOCKSIZE);
+                               (long long)rtbytes, XFS_MIN_BLOCKSIZE);
                        usage();
                }
                rtblocks = (xfs_drfsbno_t)(rtbytes >> blocklog);
                if (rtbytes % blocksize)
                        fprintf(stderr,
        "warning: rt length %lld not a multiple of %d, truncated to %lld\n",
-                               rtbytes, blocksize, rtblocks << blocklog);
+                               (long long)rtbytes, blocksize,
+                               (long long)(rtblocks << blocklog));
        }
        /*
         * If specified, check rt extent size against its constraints.
@@ -1009,7 +1038,7 @@ main(int argc, char **argv)
                if (rtextbytes % blocksize) {
                        fprintf(stderr,
                        "illegal rt extent size %lld, not a multiple of %d\n",
-                               rtextbytes, blocksize);
+                               (long long)rtextbytes, blocksize);
                        usage();
                }
                if (rtextbytes > XFS_MAX_RTEXTSIZE) {
@@ -1075,18 +1104,7 @@ main(int argc, char **argv)
                usage();
        }
 
-       if (dsunit && !dswidth || !dsunit && dswidth) {
-               fprintf(stderr,
-"both sunit and swidth options have to be specified\n");
-               usage();
-       }
-
-       if (dsunit && dswidth % dsunit != 0) {
-               fprintf(stderr,
-"mount: stripe width (%d) has to be a multiple of the stripe unit (%d)\n",
-                       dswidth, dsunit);
-               return 1;
-       }
+       calc_stripe_factors(dsu, dsw, &dsunit, &dswidth);
 
        /* other global variables */
        sectlog = 9;            /* i.e. 512 bytes */
@@ -1102,47 +1120,22 @@ main(int argc, char **argv)
        }
 
        /*
-        * Check whether this partition contains a known filesystem.
+        * Ok, Linux only has a 1024-byte resolution on device _size_,
+        * and the sizes below are in basic 512-byte blocks,
+        * so if we have (size % 2), on any partition, we can't get
+        * to the last 512 bytes.  Just chop it down by a block.
         */
 
-       if (force_fs_overwrite == 0) {
-               char *fstyp;
-               int fsfound = 0;
+       xi.dsize -= (xi.dsize % 2);
+       xi.rtsize -= (xi.rtsize % 2);
+       xi.logBBsize -= (xi.logBBsize % 2);
 
-               fstyp = (char *) mnt_known_fs_type (dfile);
-               
-               if (fstyp != NULL) {
+       if (!force_overwrite) {
+               if (check_overwrite(dfile) ||
+                   check_overwrite(logfile) ||
+                   check_overwrite(xi.rtname)) {
                        fprintf(stderr, "%s: "
-                       "%s appears to contain an existing filesystem (%s).\n",
-                               progname, dfile, fstyp);
-                       fsfound = 1;
-               }
-
-               if (logfile && *logfile) {
-                       fstyp = (char *) mnt_known_fs_type (logfile);
-                       
-                       if (fstyp != NULL) {
-                               fprintf(stderr, "%s: "
-                       "%s appears to contain an existing filesystem (%s).\n",
-                                       progname, logfile, fstyp);
-                               fsfound = 1;
-                       }
-               }
-
-               if (xi.rtname && *xi.rtname) {
-                       fstyp = (char *) mnt_known_fs_type (xi.rtname);
-                       
-                       if (fstyp != NULL) {
-                               fprintf(stderr, "%s: "
-                       "%s appears to contain an existing filesystem (%s).\n",
-                                       progname, xi.rtname, fstyp);
-                               fsfound = 1;
-                       }
-               }
-
-               if (fsfound) {
-                       fprintf(stderr, "%s: "
-                               "Use the -f option to force overwrite\n",
+                               "Use the -f option to force overwrite.\n",
                                progname);
                        exit(1);
                }
@@ -1214,7 +1207,7 @@ main(int argc, char **argv)
        if (dsize && xi.dsize > 0 && dblocks > DTOBT(xi.dsize)) {
                fprintf(stderr,
 "size %s specified for data subvolume is too large, maximum is %lld blocks\n",
-                       dsize, DTOBT(xi.dsize));
+                       dsize, (long long)DTOBT(xi.dsize));
                usage();
        } else if (!dsize && xi.dsize > 0)
                dblocks = DTOBT(xi.dsize);
@@ -1225,7 +1218,7 @@ main(int argc, char **argv)
        if (dblocks < XFS_MIN_DATA_BLOCKS) {
                fprintf(stderr,
                "size %lld of data subvolume is too small, minimum %d blocks\n",
-                       dblocks, XFS_MIN_DATA_BLOCKS);
+                       (long long)dblocks, XFS_MIN_DATA_BLOCKS);
                usage();
        }
        if (xi.logdev && loginternal) {
@@ -1243,7 +1236,7 @@ main(int argc, char **argv)
        if (logsize && xi.logBBsize > 0 && logblocks > DTOBT(xi.logBBsize)) {
                fprintf(stderr,
 "size %s specified for log subvolume is too large, maximum is %lld blocks\n",
-                       logsize, DTOBT(xi.logBBsize));
+                       logsize, (long long)DTOBT(xi.logBBsize));
                usage();
        } else if (!logsize && xi.logBBsize > 0)
                logblocks = DTOBT(xi.logBBsize);
@@ -1253,37 +1246,49 @@ main(int argc, char **argv)
                usage();
        } else if (loginternal && logsize && logblocks >= dblocks) {
                fprintf(stderr, "size %lld too large for internal log\n",
-                       logblocks);
+                       (long long)logblocks);
                usage();
        } else if (!loginternal && !xi.logdev)
                logblocks = 0;
        else if (loginternal && !logsize) {
-               logblocks = MAX(XFS_DFL_LOG_SIZE, i * XFS_DFL_LOG_FACTOR);
-                logblocks = MAX(logblocks, dblocks / 8192); 
+               /*
+                * logblocks grows from min_logblocks to XFS_MAX_LOG_BLOCKS
+                * at 1TB
+                *
+                * 8192 = 1TB / MAX_LOG_BYTES
+                */
+               logblocks = (dblocks << blocklog) / 8192;
+               logblocks = logblocks >> blocklog;
+               logblocks = MAX(min_logblocks, logblocks);
+                logblocks = MAX(logblocks,
+                               MAX(XFS_DFL_LOG_SIZE, i * XFS_DFL_LOG_FACTOR));
                 logblocks = MIN(logblocks, XFS_MAX_LOG_BLOCKS); 
+               if ((logblocks << blocklog) > XFS_MAX_LOG_BYTES) {
+                       logblocks = XFS_MAX_LOG_BYTES >> blocklog;
+               }
         } 
        if (logblocks < min_logblocks) {
                fprintf(stderr,
                "log size %lld blocks too small, minimum size is %d blocks\n",
-                       logblocks, min_logblocks);
+                       (long long)logblocks, min_logblocks);
                usage();
        }
        if (logblocks > XFS_MAX_LOG_BLOCKS) {
                fprintf(stderr,
                "log size %lld blocks too large, maximum size is %d blocks\n",
-                       logblocks, XFS_MAX_LOG_BLOCKS);
+                       (long long)logblocks, XFS_MAX_LOG_BLOCKS);
                usage();
        }
        if ((logblocks << blocklog) > XFS_MAX_LOG_BYTES) {
                fprintf(stderr,
                "log size %lld bytes too large, maximum size is %d bytes\n",
-                       logblocks << blocklog, XFS_MAX_LOG_BYTES);
+                       (long long)(logblocks << blocklog), XFS_MAX_LOG_BYTES);
                usage();
        }
        if (rtsize && xi.rtsize > 0 && rtblocks > DTOBT(xi.rtsize)) {
                fprintf(stderr,
 "size %s specified for rt subvolume is too large, maximum is %lld blocks\n",
-                       rtsize, DTOBT(xi.rtsize));
+                       rtsize, (long long)DTOBT(xi.rtsize));
                usage();
        } else if (!rtsize && xi.rtsize > 0)
                rtblocks = DTOBT(xi.rtsize);
@@ -1299,61 +1304,140 @@ main(int argc, char **argv)
                rtextents = rtblocks = 0;
                nbmblocks = 0;
        }
-       agsize = dblocks / agcount + (dblocks % agcount != 0);
+
+       if (dasize) {
+               /*
+                * If the specified agsize isn't a multiple of fs blks,
+                * complain.
+                */
+               if (agsize % blocksize) {
+                       fprintf(stderr,
+                       "agsize (%lld) not a multiple of fs blk size (%d)\n",
+                               (long long)agsize, blocksize);
+                       usage();
+               }
+
+               agsize /= blocksize;
+
+               /*
+                * If the specified agsize is too small, or too large,
+                * complain.
+                */
+               if (agsize < XFS_AG_MIN_BLOCKS(blocklog)) {
+                       fprintf(stderr,
+                       "agsize (%lldb) too small, need at least %lld blocks\n",
+                               (long long)agsize,
+                               (long long)XFS_AG_MIN_BLOCKS(blocklog));
+                       usage();
+               }
+
+               if (agsize > XFS_AG_MAX_BLOCKS(blocklog)) {
+                       fprintf(stderr,
+                       "agsize (%lldb) too big, maximum is %lld blocks\n",
+                               (long long)agsize,
+                               (long long)XFS_AG_MAX_BLOCKS(blocklog));
+                       usage();
+               }
+
+               if (agsize > dblocks)  {
+                       fprintf(stderr,
+                       "agsize (%lldb) too big, data area is %lld blocks\n",
+                               (long long)agsize, (long long)dblocks);
+                       usage();
+               }
+
+               agcount = dblocks / agsize + (dblocks % agsize != 0);
+       } else {
+               agsize = dblocks / agcount + (dblocks % agcount != 0);
+       }
 
        /*
-        * If the ag size is too small, complain if agcount was specified,
-        * and fix it otherwise.
+        * If the ag size is too small, complain if agcount/agsize was
+        * specified, and fix it otherwise.
         */
        if (agsize < XFS_AG_MIN_BLOCKS(blocklog)) {
-               if (daflag) {
+               if (daflag || dasize) {
                        fprintf(stderr,
-                               "too many allocation groups for size\n");
+                               "too many allocation groups for size = %lld\n",
+                               (long long)agsize);
                        fprintf(stderr, "need at most %lld allocation groups\n",
-                               dblocks / XFS_AG_MIN_BLOCKS(blocklog) +
-                               (dblocks % XFS_AG_MIN_BLOCKS(blocklog) != 0));
+                               (long long)
+                               (dblocks / XFS_AG_MIN_BLOCKS(blocklog) +
+                               (dblocks % XFS_AG_MIN_BLOCKS(blocklog) != 0)));
                        usage();
                }
                agsize = XFS_AG_MIN_BLOCKS(blocklog);
                if (dblocks < agsize)
                        agcount = 1;
-               else {
+               else
                        agcount = dblocks / agsize;
-                       agsize = dblocks / agcount + (dblocks % agcount != 0);
-               }
+
+               agsize = dblocks / agcount + (dblocks % agcount != 0);
        }
+
        /*
-        * If the ag size is too large, complain if agcount was specified,
-        * and fix it otherwise.
+        * If the ag size is too large, complain if agcount/agsize was
+        * specified, and fix it otherwise.
         */
        else if (agsize > XFS_AG_MAX_BLOCKS(blocklog)) {
-               if (daflag) {
-                       fprintf(stderr, "too few allocation groups for size\n");
+               if (daflag || dasize) {
+                       fprintf(stderr, "too few allocation groups for size = %lld\n",
+                               (long long)agsize);
                        fprintf(stderr,
                                "need at least %lld allocation groups\n",
-                               dblocks / XFS_AG_MAX_BLOCKS(blocklog) + 
-                               (dblocks % XFS_AG_MAX_BLOCKS(blocklog) != 0));
+                               (long long)
+                               (dblocks / XFS_AG_MAX_BLOCKS(blocklog) + 
+                               (dblocks % XFS_AG_MAX_BLOCKS(blocklog) != 0)));
                        usage();
                }
                agsize = XFS_AG_MAX_BLOCKS(blocklog);
                agcount = dblocks / agsize + (dblocks % agsize != 0);
-               agsize = dblocks / agcount + (dblocks % agcount != 0);
        }
+
+       /*
+        * If the last AG is too small, reduce the filesystem size
+        * and drop the blocks.
+        */
+       if ( dblocks % agsize != 0 &&
+            (dblocks % agsize < XFS_AG_MIN_BLOCKS(blocklog))) {
+               dblocks = (xfs_drfsbno_t)((agcount - 1) * agsize);
+               agcount--;
+               ASSERT(agcount != 0);
+       }
+
        /*
         * If agcount was not specified, and agsize is larger than
         * we'd like, make it the size we want.
         */
-       if (!daflag && agsize > XFS_AG_BEST_BLOCKS(blocklog)) {
-               agsize = XFS_AG_BEST_BLOCKS(blocklog);
+       if (!daflag && !dasize &&
+           (agsize > XFS_AG_BEST_BLOCKS(blocklog,dblocks))) {
+               agsize = XFS_AG_BEST_BLOCKS(blocklog,dblocks);
                agcount = dblocks / agsize + (dblocks % agsize != 0);
-               agsize = dblocks / agcount + (dblocks % agcount != 0);
+               /*
+                * If the last AG is too small, reduce the filesystem size
+                * and drop the blocks.
+                */
+               if ( dblocks % agsize != 0 &&
+                   (dblocks % agsize < XFS_AG_MIN_BLOCKS(blocklog))) {
+                       dblocks = (xfs_drfsbno_t)((agcount - 1) * agsize);
+                       agcount--;
+                       ASSERT(agcount != 0);
+               }
        }
+
        /*
         * If agcount is too large, make it smaller.
         */
        if (agcount > XFS_MAX_AGNUMBER + 1) {
                agcount = XFS_MAX_AGNUMBER + 1;
                agsize = dblocks / agcount + (dblocks % agcount != 0);
+
+               if (dasize || daflag)
+                       fprintf(stderr,
+               "agsize set to %lld, agcount %lld > max (%lld)\n",
+                               (long long)agsize, (long long)agcount,
+                               (long long)XFS_MAX_AGNUMBER+1);
+
                if (agsize > XFS_AG_MAX_BLOCKS(blocklog)) {
                        /*
                         * We're confused.
@@ -1374,13 +1458,11 @@ main(int argc, char **argv)
                        fprintf(stderr, "%s: "
   "Specified data stripe unit %d is not the same as the xlv stripe unit %d\n", 
                                progname, dsunit, xlv_dsunit);
-                       exit(1);
                }
                if (xlv_dswidth && xlv_dswidth != dswidth) {
                        fprintf(stderr, "%s: "
-"Specified data stripe width (%d) is not the same as the xlv stripe width (%d)\n",
+"Specified data stripe width %d is not the same as the xlv stripe width %d\n",
                                progname, dswidth, xlv_dswidth);
-                       exit(1);
                }
        } else {
                dsunit = xlv_dsunit;
@@ -1404,28 +1486,69 @@ main(int argc, char **argv)
                 */
                if ((agsize % dsunit) != 0) {
                        /*
-                        * round up to stripe unit boundary. Also make sure 
+                        * Round up to stripe unit boundary. Also make sure 
                         * that agsize is still larger than 
                         * XFS_AG_MIN_BLOCKS(blocklog)
                         */
                        tmp_agsize = ((agsize + (dsunit - 1))/ dsunit) * dsunit;
+                       /*
+                        * Round down to stripe unit boundary if rounding up
+                        * created an AG size that is larger than the AG max.
+                        */
+                       if (tmp_agsize > XFS_AG_MAX_BLOCKS(blocklog))
+                               tmp_agsize = ((agsize) / dsunit) * dsunit;
                        if ((tmp_agsize >= XFS_AG_MIN_BLOCKS(blocklog)) &&
                            (tmp_agsize <= XFS_AG_MAX_BLOCKS(blocklog)) &&
                            !daflag) {
                                agsize = tmp_agsize;
                                agcount = dblocks/agsize + 
                                                (dblocks % agsize != 0);
+                               if (dasize || daflag)
+                                       fprintf(stderr,
+                                       "agsize rounded to %lld, swidth = %d\n",
+                                               (long long)agsize, dswidth);
                        } else {
-                               if (nodsflag)
+                               if (nodsflag) {
                                        dsunit = dswidth = 0;
-                               else { 
+                               else { 
                                        fprintf(stderr,
 "Allocation group size %lld is not a multiple of the stripe unit %d\n",
-                                               agsize, dsunit);
+                                               (long long)agsize, dsunit);
                                        exit(1);
                                }
                        }
                }
+               if ((agsize % dswidth) == 0) {
+                       /* This is a non-optimal configuration because all AGs
+                        * start on the same disk in the stripe.  Decreasing
+                        * the AG size by one sunit will guarantee that this
+                        * does not happen
+                        */
+                       tmp_agsize = agsize - dsunit;
+                       if (tmp_agsize < XFS_AG_MIN_BLOCKS(blocklog))
+                               tmp_agsize = agsize + dsunit;
+                       if (daflag || dasize) {
+                               fprintf(stderr,
+"Warning: AG size is a multiple of stripe width.  This can cause performance\n"
+"problems by aligning all AGs on the same disk.  To avoid this, rerun mkfs with\n"
+"an AG size that is one stripe unit smaller, for example %lld\n",
+                                       tmp_agsize);
+                       } else {
+                               agsize = tmp_agsize;
+                               agcount = dblocks/agsize + (dblocks % agsize != 0);
+                               /*
+                                * If the last AG is too small, reduce the
+                                * filesystem size and drop the blocks.
+                                */
+                               if ( dblocks % agsize != 0 &&
+                                   (dblocks % agsize <
+                                   XFS_AG_MIN_BLOCKS(blocklog))) {
+                                       dblocks = (xfs_drfsbno_t)((agcount - 1) * agsize);
+                                       agcount--;
+                                       ASSERT(agcount != 0);
+                               }
+                       }
+               }
        } else {
                if (nodsflag)
                        dsunit = dswidth = 0;
@@ -1439,7 +1562,6 @@ main(int argc, char **argv)
 
        protostring = setup_proto(protofile);
        bsize = 1 << (blocklog - BBSHIFT);
-       buf = libxfs_getbuf(xi.ddev, XFS_SB_DADDR, 1);
        mp = &mbuf;
        sbp = &mp->m_sb;
        bzero(mp, sizeof(xfs_mount_t));
@@ -1447,17 +1569,25 @@ main(int argc, char **argv)
        sbp->sb_agblklog = (__uint8_t)libxfs_log2_roundup((unsigned int)agsize);
        mp->m_blkbb_log = sbp->sb_blocklog - BBSHIFT;
        if (loginternal) {
+               /*
+                * Readjust the log size to fit within an AG if it was sized
+                * automaticly.
+                */
+               if (!logsize) {
+                       logblocks = MIN(logblocks,
+                                       agsize - XFS_PREALLOC_BLOCKS(mp));
+               }
                if (logblocks > agsize - XFS_PREALLOC_BLOCKS(mp)) {
                        fprintf(stderr,
        "internal log size %lld too large, must fit in allocation group\n",
-                               logblocks);
+                               (long long)logblocks);
                        usage();
                }
                if (laflag) {
                        if (logagno >= agcount) {
                                fprintf(stderr,
                        "log ag number %d too large, must be less than %lld\n",
-                                       logagno, agcount);
+                                       logagno, (long long)agcount);
                                usage();
                        }
                } else
@@ -1469,33 +1599,45 @@ main(int argc, char **argv)
                 */
                if (dsunit && ((logstart % dsunit) != 0)) {
                        logstart = ((logstart + (dsunit - 1))/dsunit) * dsunit;
-
                        /* 
                         * Make sure that the log size is a multiple of the
                         * stripe unit
                         */
-                       if ((logblocks % dsunit) != 0) 
-                          if (!lsflag) 
-                               logblocks = ((logblocks + (dsunit - 1))
-                                                       /dsunit) * dsunit;
-                          else {
+                       if ((logblocks % dsunit) != 0) {
+                           if (!lsflag) {
+                               tmp_logblocks = ((logblocks + (dsunit - 1))
+                                                       / dsunit) * dsunit;
+                               /*
+                                * If the log is too large, round down
+                                * instead of round up
+                                */
+                               if ((tmp_logblocks > XFS_MAX_LOG_BLOCKS) ||
+                                   ((tmp_logblocks << blocklog) > XFS_MAX_LOG_BYTES)) {
+                                       tmp_logblocks = (logblocks / dsunit) * dsunit;
+                               }
+                               logblocks = tmp_logblocks;
+                           } else {
                                fprintf(stderr,
        "internal log size %lld is not a multiple of the stripe unit %d\n", 
-                                       logblocks, dsunit);
+                                       (long long)logblocks, dsunit);
                                usage();
-                          }
+                           }
+                       }
 
                        if (logblocks > agsize-XFS_FSB_TO_AGBNO(mp,logstart)) {
                                fprintf(stderr,
        "Due to stripe alignment, the internal log size %lld is too large.\n"
        "Must fit in allocation group\n",
-                                       logblocks);
+                                       (long long)logblocks);
                                usage();
                        }
                        lalign = 1;
                }
        } else
                logstart = 0;
+
+       if (label)
+               strncpy(sbp->sb_fname, label, sizeof(sbp->sb_fname));
        sbp->sb_magicnum = XFS_SB_MAGIC;
        sbp->sb_blocksize = blocksize;
        sbp->sb_dblocks = dblocks;
@@ -1526,7 +1668,7 @@ main(int argc, char **argv)
        sbp->sb_fdblocks = dblocks - agcount * XFS_PREALLOC_BLOCKS(mp) -
                (loginternal ? logblocks : 0);
        sbp->sb_frextents = 0;  /* will do a free later */
-       sbp->sb_uquotino = sbp->sb_pquotino = 0;
+       sbp->sb_uquotino = sbp->sb_gquotino = 0;
        sbp->sb_qflags = 0;
        sbp->sb_unit = dsunit;
        sbp->sb_width = dswidth;
@@ -1541,6 +1683,19 @@ main(int argc, char **argv)
                XFS_SB_VERSION_MKFS(iaflag, dsunit != 0, extent_flagging,
                        dirversion == 2);
 
+       /*
+        * Zero out the first 68k in on the device, to obliterate any old 
+        * filesystem signatures out there.  This should take care of 
+        * swap (somewhere around the page size), jfs (32k), 
+        * ext[2,3] and reiser (64k) - and hopefully all else.
+        */
+        
+       buf = libxfs_getbuf(xi.ddev, 0, 136);
+       bzero(XFS_BUF_PTR(buf), 136*BBSIZE);
+       libxfs_writebuf(buf, 1);
+
+       /* OK, now write the superblock */
+       buf = libxfs_getbuf(xi.ddev, XFS_SB_DADDR, 1);
        bzero(XFS_BUF_PTR(buf), BBSIZE);
        libxfs_xlate_sb(XFS_BUF_PTR(buf), sbp, -1, ARCH_CONVERT,
                        XFS_SB_ALL_BITS);
@@ -1554,12 +1709,13 @@ main(int argc, char **argv)
                   "naming   =version %-14d bsize=%-6d\n"
                   "log      =%-22s bsize=%-6d blocks=%lld\n"
                   "realtime =%-22s extsz=%-6d blocks=%lld, rtextents=%lld\n",
-                       dfile, isize, agcount, agsize,
-                       "", blocksize, dblocks, sbp->sb_imax_pct,
+                       dfile, isize, (long long)agcount, (long long)agsize,
+                       "", blocksize, (long long)dblocks, sbp->sb_imax_pct,
                        "", dsunit, dswidth, extent_flagging,
                        dirversion, dirversion == 1 ? blocksize : dirblocksize,
-                       logfile, 1 << blocklog, logblocks,
-                       rtfile, rtextblocks << blocklog, rtblocks, rtextents);
+                       logfile, 1 << blocklog, (long long)logblocks,
+                       rtfile, rtextblocks << blocklog,
+                       (long long)rtblocks, (long long)rtextents);
        /*
         * If the data area is a file, then grow it out to its final size
         * so that the reads for the end of the device in the mount code
@@ -1570,6 +1726,18 @@ main(int argc, char **argv)
                        progname);
                exit(1);
        }
+
+       /*
+        * Zero out the last 64k on the device, to obliterate any
+        * old MD RAID (or other) metadata at the end of the device.
+        */
+       if (!xi.disfile) {
+               buf = libxfs_getbuf(xi.ddev, (xi.dsize - BTOBB(65536)), 
+                                   BTOBB(65536));
+               bzero(XFS_BUF_PTR(buf), 65536);
+               libxfs_writebuf(buf, 1);
+       }
+
        /*
         * Zero the log if there is one.
         */
@@ -1584,8 +1752,8 @@ main(int argc, char **argv)
                     XLOG_FMT);
 
        mp = libxfs_mount(mp, sbp, xi.ddev, xi.logdev, xi.rtdev, 1);
-       if (!mp) {
-               fprintf(stderr, "%s: mount initialization failed\n", progname);
+       if (mp == NULL) {
+               fprintf(stderr, "%s: filesystem failed to initialize\n", progname);
                exit(1);
        }
        if (xi.logdev &&
@@ -1593,7 +1761,7 @@ main(int argc, char **argv)
            XFS_MIN_LOG_FACTOR * max_trans_res(mp)) {
                fprintf(stderr, "%s: log size (%lld) is too small for "
                                "transaction reservations\n",
-                       progname, logblocks);
+                       progname, (long long)logblocks);
                exit(1);
        }
 
@@ -1789,7 +1957,7 @@ main(int argc, char **argv)
                args.alignment = 1;
                args.minalignslop = UINT_MAX;
                args.pag = &mp->m_perag[agno];
-               if (i = libxfs_trans_reserve(tp, worst_freelist, 0, 0, 0, 0))
+               if ((i = libxfs_trans_reserve(tp, worst_freelist, 0, 0, 0, 0)))
                        res_failed(i);
                libxfs_alloc_fix_freelist(&args, 0);
                libxfs_trans_commit(tp, 0, NULL);
@@ -1971,20 +2139,24 @@ usage(void)
        fprintf(stderr, "Usage: %s\n\
 /* blocksize */                [-b log=n|size=num]\n\
 /* data subvol */      [-d agcount=n,agsize=n,file,name=xxx,size=num,\n\
-                           sunit=value,swidth=value,unwritten=0|1]\n\
+                           sunit=value,swidth=value,unwritten=0|1,\n\
+                           su=value,sw=value]\n\
 /* inode size */       [-i log=n|perblock=n|size=num,maxpct=n]\n\
 /* log subvol */       [-l agnum=n,internal,size=num,logdev=xxx]\n\
 /* naming */           [-n log=n|size=num|version=n]\n\
+/* label */            [-L label (maximum 12 characters)]\n\
 /* prototype file */   [-p fname]\n\
 /* quiet */            [-q]\n\
 /* version */          [-V]\n\
 /* realtime subvol */  [-r extsize=num,size=num,rtdev=xxx]\n\
                        devicename\n\
-devicename is required unless -d name=xxx is given\n\
-internal 1000 block log is default unless overridden or using a volume\
-manager with log\n\
-num is xxx (bytes), or xxxb (blocks), or xxxk (xxx KB), or xxxm (xxx MB)\n\
-value is xxx (512 blocks)\n",
+<devicename> is required unless -d name=xxx is given.\n\
+Internal log by default, size is scaled from 1,000 blocks to 32,768 blocks\n\
+based on the filesystem size.  Default log reaches its largest size at 1TB.\n\
+This can be overridden with the -l options or using a volume manager with a\n\
+log subvolume.\n\
+<num> is xxx (bytes), or xxxb (blocks), or xxxk (xxx KB), or xxxm (xxx MB)\n\
+<value> is xxx (512 blocks).\n",
                progname);
        exit(1);
 }