by the filesystem's block size.
If suffixed with \f3k\f1 then the size is converted by multiplying it by 1024.
If suffixed with \f3m\f1 then the size is converted by multiplying it by
+1048576 (1024 * 1024).
If suffixed with \f3g\f1 then the size is converted by multiplying it by
1073741824 (1024 * 1024 * 1024).
.TP
.BR log= ,
or in bytes with
.BR size= .
-The default value is 4096 bytes (4 KB). The minimum value for block
-size is 512; the maximum is 65536 (64 KB). XFS on Linux currently
-only supports 4KB blocks.
+The default value is 4096 bytes (4 KB) on systems with a 4KB pagesize.
+The minimum value for block size is 512; the maximum is 65536 (64 KB).
+XFS on Linux currently only supports pagesize blocks.
.TP
.B \-d
Data section options.
data section of the filesystem.
The valid suboptions are:
\f3agcount=\f1\f2value\f1,
+\f3agsize=\f1\f2value\f1,
\f3file\f1[\f3=\f1\f2value\f1],
\f3name=\f1\f2value\f1,
\f3size=\f1\f2value\f1,
\f3sunit=\f1\f2value\f1,
\f3swidth=\f1\f2value\f1,
+\f3su=\f1\f2value\f1,
+\f3sw=\f1\f2value\f1,
and
\f3unwritten\f1[\f3=\f1\f2value\f1].
.IP
amount of CPU time to be used when the filesystem is close to full.
.IP
The
+.B agsize
+suboption is an alternative to using
+.B agcount.
+The argument provided to
+.B agsize
+is the desired size of the allocation group expressed in bytes
+(usually using the \f3m\f1 or \f3g\f1 suffixes).
+This value must be a multiple of the filesystem block size, and
+must be at least 16MB, and no more than 4GB, and may
+be automatically adjusted to properly align with the stripe geometry.
+The
+.B agcount
+suboption and the
+.B agsize
+suboption are mutually exclusive.
+.IP
+The
.B name
suboption can be used to specify the name of the special file containing
the filesystem.
(with a size, see the
.B \-l
option below) and there can be no real-time section.
-Depending on the filesystem size, mkfs.xfs will try to
.IP
The
.B file
suboption is a regular file.
The suboption value is either 0 or 1,
with 1 signifying that the file is regular.
-This suboption is used only to make a filesystem image
-(for instance, a miniroot image).
+This suboption is used only to make a filesystem image.
If the value is omitted then 1 is assumed.
.IP
The
The
.B sunit
suboption is used to specify the stripe unit for a RAID device or a
-logical volume. The suboption value has to be specified in 512-byte
-block units. This suboption ensures that data allocations will be
-stripe unit aligned when the current end of file is being extended and
-the file size is larger than 512KB. Also inode allocations and the
-internal log will be stripe unit aligned.
+logical volume.
+The suboption value has to be specified in 512-byte block units.
+Use the
+.B su
+suboption to specify the stripe unit size in bytes.
+This suboption ensures that data allocations will be stripe unit aligned
+when the current end of file is being extended and the file size is larger
+than 512KB.
+Also inode allocations and the internal log will be stripe unit aligned.
+.IP
+The
+.B su
+suboption is an alternative to using
+.B sunit.
+The
+.B su
+suboption is used to specify the stripe unit for a RAID device or a
+striped logical volume.
+The suboption value has to be specified in bytes,
+(usually using the \f3m\f1 or \f3g\f1 suffixes).
+This value must be a multiple of the filesystem block size.
.IP
The
.B swidth
suboption is used to specify the stripe width for a RAID device or a
striped logical volume.
The suboption value has to be specified in 512-byte block units.
+Use the
+.B sw
+suboption to specify the stripe width size in bytes.
This suboption is required if
.B \-d sunit
has been specified and it has to be a multiple of the
.IR stat (2)
system call.
.IP
-When a filesystem is created on an LVM or an MD device, mkfs.xfs will
-automatically query the logical volume for appropriate
+The
+.B sw
+suboption is an alternative to using
+.B swidth.
+The
+.B sw
+suboption is used to specify the stripe width for a RAID device or
+striped logical volume.
+The suboption value is expressed as a multiplier of the stripe unit,
+usually the same as the number of stripe members in the logical
+volume configuration, or data disks in a RAID device.
+.IP
+When a filesystem is created on a logical volume device,
+.I mkfs.xfs
+will automatically query the logical volume for appropriate
.B sunit
and
.B swidth
.IP
If the log is contained within the data section and
.B size
-isn't specified, mkfs will try to select a suitable log size depending
+isn't specified,
+.I mkfs.xfs
+will try to select a suitable log size depending
on the size of the filesystem. The actual logsize depends on the
filesystem block size and the directory block size.
.IP
"swidth",
#define D_UNWRITTEN 6
"unwritten",
+#define D_AGSIZE 7
+ "agsize",
+#define D_SU 8
+ "su",
+#define D_SW 9
+ "sw",
NULL
};
}
+static void
+calc_stripe_factors(int dsu, int dsw, int *dsunit, int *dswidth)
+{
+ if (*dsunit || *dswidth) {
+ if (dsu || dsw) {
+ fprintf(stderr,
+ "su/sw should not be used in conjunction with sunit/swidth\n");
+ usage();
+ }
+
+ if ((*dsunit && !*dswidth) || (!*dsunit && *dswidth)) {
+ fprintf(stderr,
+ "both sunit and swidth options have to be specified\n");
+ usage();
+ }
+ }
+
+ if (dsu || dsw) {
+ if (*dsunit || *dswidth) {
+ fprintf(stderr,
+ "sunit/swidth should not be used in conjunction with su/sw\n");
+ usage();
+ }
+
+ if ((dsu && !dsw) || (!dsu && dsw)) {
+ fprintf(stderr,
+ "both su and sw options have to be specified\n");
+ usage();
+ }
+
+ if (dsu % BBSIZE) {
+ fprintf(stderr, "su must be a multiple of %d\n",
+ BBSIZE);
+ usage();
+ }
+
+ *dsunit = (int)BTOBBT(dsu);
+ *dswidth = *dsunit * dsw;
+ }
+
+ 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)
{
xfs_buf_t *buf;
int c;
int daflag;
+ int dasize;
xfs_drfsbno_t dblocks;
char *dfile;
int dirblocklog;
int dirversion;
int do_overlap_checks;
char *dsize;
+ int dsu;
+ int dsw;
int dsunit;
int dswidth;
int extent_flagging;
xfs_sb_t *sbp;
int sectlog;
__uint64_t tmp_agsize;
+ __uint64_t tmp_logblocks;
uuid_t uuid;
int worst_freelist;
libxfs_init_t xi;
progname = basename(argv[0]);
agcount = 8;
blflag = bsflag = 0;
+ dasize = daflag = 0;
blocksize = get_default_blocksize();
blocklog = libxfs_highbit32(blocksize);
agsize = daflag = dblocks = 0;
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;
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";
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)
}
break;
}
+
+ if (daflag && dasize) {
+ fprintf(stderr,
+ "both -d agcount= and agsize= specified, use one or the other\n");
+ usage();
+ }
+
if (!daflag)
agcount = 8;
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 */
} 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,
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",
(long long)
(dblocks / XFS_AG_MIN_BLOCKS(blocklog) +
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",
(long long)
}
agsize = XFS_AG_MAX_BLOCKS(blocklog);
agcount = dblocks / agsize + (dblocks % agsize != 0);
- agsize = dblocks / agcount + (dblocks % 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 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.
*/
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",
(long long)agsize, dsunit);
*/
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 (!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",
(long long)logblocks, dsunit);
}
} else
logstart = 0;
+
if (label)
strncpy(sbp->sb_fname, label, sizeof(sbp->sb_fname));
sbp->sb_magicnum = XFS_SB_MAGIC;
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\
/* 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\n\
-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);
}