+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2000-2005 Silicon Graphics, Inc.
* All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "libfrog.h"
#include "libxfs.h"
#include <ctype.h>
#include "xfs_multidisk.h"
#include "libxcmd.h"
+#include "fsgeom.h"
+
+
+#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)))
/*
- * Prototypes for internal functions.
+ * Use this macro before we have superblock and mount structure to
+ * convert from basic blocks to filesystem blocks.
*/
-static void conflict(char opt, const char *tab[], int oldidx, int newidx);
-static void illegal(const char *value, const char *opt);
-static __attribute__((noreturn)) void usage (void);
-static __attribute__((noreturn)) void reqval(char opt, const char *tab[], int idx);
-static void respec(char opt, const char *tab[], int idx);
-static void unknown(char opt, char *s);
-static int ispow2(unsigned int i);
+#define DTOBT(d, bl) ((xfs_rfsblock_t)((d) >> ((bl) - BBSHIFT)))
+
+/*
+ * amount (in bytes) we zero at the beginning and end of the device to
+ * remove traces of other filesystems, raid superblocks, etc.
+ */
+#define WHACK_SIZE (128 * 1024)
/*
- * The configured block and sector sizes are defined as global variables so
- * that they don't need to be passed to functions that require them.
+ * XXX: The configured block and sector sizes are defined as global variables so
+ * that they don't need to be passed to getnum/cvtnum().
*/
unsigned int blocksize;
unsigned int sectorsize;
-#define MAX_SUBOPTS 17
+/*
+ * Enums for each CLI parameter type are declared first so we can calculate the
+ * maximum array size needed to hold them automatically.
+ */
+enum {
+ B_SIZE = 0,
+ B_MAX_OPTS,
+};
+
+enum {
+ D_AGCOUNT = 0,
+ D_FILE,
+ D_NAME,
+ D_SIZE,
+ D_SUNIT,
+ D_SWIDTH,
+ D_AGSIZE,
+ D_SU,
+ D_SW,
+ D_SECTSIZE,
+ D_NOALIGN,
+ D_RTINHERIT,
+ D_PROJINHERIT,
+ D_EXTSZINHERIT,
+ D_COWEXTSIZE,
+ D_MAX_OPTS,
+};
+
+enum {
+ I_ALIGN = 0,
+ I_MAXPCT,
+ I_PERBLOCK,
+ I_SIZE,
+ I_ATTR,
+ I_PROJID32BIT,
+ I_SPINODES,
+ I_MAX_OPTS,
+};
+
+enum {
+ L_AGNUM = 0,
+ L_INTERNAL,
+ L_SIZE,
+ L_VERSION,
+ L_SUNIT,
+ L_SU,
+ L_DEV,
+ L_SECTSIZE,
+ L_FILE,
+ L_NAME,
+ L_LAZYSBCNTR,
+ L_MAX_OPTS,
+};
+
+enum {
+ N_SIZE = 0,
+ N_VERSION,
+ N_FTYPE,
+ N_MAX_OPTS,
+};
+
+enum {
+ R_EXTSIZE = 0,
+ R_SIZE,
+ R_DEV,
+ R_FILE,
+ R_NAME,
+ R_NOALIGN,
+ R_MAX_OPTS,
+};
+
+enum {
+ S_SIZE = 0,
+ S_SECTSIZE,
+ S_MAX_OPTS,
+};
+
+enum {
+ M_CRC = 0,
+ M_FINOBT,
+ M_UUID,
+ M_RMAPBT,
+ M_REFLINK,
+ M_MAX_OPTS,
+};
+
+/* Just define the max options array size manually right now */
+#define MAX_SUBOPTS D_MAX_OPTS
+
#define SUBOPT_NEEDS_VAL (-1LL)
#define MAX_CONFLICTS 8
#define LAST_CONFLICT (-1)
bool str_seen;
bool convert;
bool is_power_2;
- int conflicts[MAX_CONFLICTS];
+ struct _conflict {
+ struct opt_params *opts;
+ int subopt;
+ } conflicts[MAX_CONFLICTS];
long long minval;
long long maxval;
long long defaultval;
} subopt_params[MAX_SUBOPTS];
};
+/*
+ * The two dimensional conflict array requires some initialisations to know
+ * about tables that haven't yet been defined. Work around this ordering
+ * issue with extern definitions here.
+ */
+extern struct opt_params sopts;
+
struct opt_params bopts = {
.name = 'b',
.subopts = {
-#define B_LOG 0
- "log",
-#define B_SIZE 1
- "size",
- NULL
+ [B_SIZE] = "size",
},
.subopt_params = {
- { .index = B_LOG,
- .conflicts = { B_SIZE,
- LAST_CONFLICT },
- .minval = XFS_MIN_BLOCKSIZE_LOG,
- .maxval = XFS_MAX_BLOCKSIZE_LOG,
- .defaultval = SUBOPT_NEEDS_VAL,
- },
{ .index = B_SIZE,
.convert = true,
.is_power_2 = true,
- .conflicts = { B_LOG,
- LAST_CONFLICT },
+ .conflicts = { { NULL, LAST_CONFLICT } },
.minval = XFS_MIN_BLOCKSIZE,
.maxval = XFS_MAX_BLOCKSIZE,
.defaultval = SUBOPT_NEEDS_VAL,
struct opt_params dopts = {
.name = 'd',
.subopts = {
-#define D_AGCOUNT 0
- "agcount",
-#define D_FILE 1
- "file",
-#define D_NAME 2
- "name",
-#define D_SIZE 3
- "size",
-#define D_SUNIT 4
- "sunit",
-#define D_SWIDTH 5
- "swidth",
-#define D_AGSIZE 6
- "agsize",
-#define D_SU 7
- "su",
-#define D_SW 8
- "sw",
-#define D_SECTLOG 9
- "sectlog",
-#define D_SECTSIZE 10
- "sectsize",
-#define D_NOALIGN 11
- "noalign",
-#define D_RTINHERIT 12
- "rtinherit",
-#define D_PROJINHERIT 13
- "projinherit",
-#define D_EXTSZINHERIT 14
- "extszinherit",
-#define D_COWEXTSIZE 15
- "cowextsize",
- NULL
+ [D_AGCOUNT] = "agcount",
+ [D_FILE] = "file",
+ [D_NAME] = "name",
+ [D_SIZE] = "size",
+ [D_SUNIT] = "sunit",
+ [D_SWIDTH] = "swidth",
+ [D_AGSIZE] = "agsize",
+ [D_SU] = "su",
+ [D_SW] = "sw",
+ [D_SECTSIZE] = "sectsize",
+ [D_NOALIGN] = "noalign",
+ [D_RTINHERIT] = "rtinherit",
+ [D_PROJINHERIT] = "projinherit",
+ [D_EXTSZINHERIT] = "extszinherit",
+ [D_COWEXTSIZE] = "cowextsize",
},
.subopt_params = {
{ .index = D_AGCOUNT,
- .conflicts = { D_AGSIZE,
- LAST_CONFLICT },
+ .conflicts = { { &dopts, D_AGSIZE },
+ { NULL, LAST_CONFLICT } },
.minval = 1,
.maxval = XFS_MAX_AGNUMBER,
.defaultval = SUBOPT_NEEDS_VAL,
},
{ .index = D_FILE,
- .conflicts = { LAST_CONFLICT },
+ .conflicts = { { NULL, LAST_CONFLICT } },
.minval = 0,
.maxval = 1,
.defaultval = 1,
},
{ .index = D_NAME,
- .conflicts = { LAST_CONFLICT },
+ .conflicts = { { NULL, LAST_CONFLICT } },
.defaultval = SUBOPT_NEEDS_VAL,
},
{ .index = D_SIZE,
- .conflicts = { LAST_CONFLICT },
+ .conflicts = { { NULL, LAST_CONFLICT } },
.convert = true,
.minval = XFS_AG_MIN_BYTES,
.maxval = LLONG_MAX,
.defaultval = SUBOPT_NEEDS_VAL,
},
{ .index = D_SUNIT,
- .conflicts = { D_NOALIGN,
- D_SU,
- D_SW,
- LAST_CONFLICT },
+ .conflicts = { { &dopts, D_NOALIGN },
+ { &dopts, D_SU },
+ { &dopts, D_SW },
+ { NULL, LAST_CONFLICT } },
.minval = 0,
.maxval = UINT_MAX,
.defaultval = SUBOPT_NEEDS_VAL,
},
{ .index = D_SWIDTH,
- .conflicts = { D_NOALIGN,
- D_SU,
- D_SW,
- LAST_CONFLICT },
+ .conflicts = { { &dopts, D_NOALIGN },
+ { &dopts, D_SU },
+ { &dopts, D_SW },
+ { NULL, LAST_CONFLICT } },
.minval = 0,
.maxval = UINT_MAX,
.defaultval = SUBOPT_NEEDS_VAL,
},
{ .index = D_AGSIZE,
- .conflicts = { D_AGCOUNT,
- LAST_CONFLICT },
+ .conflicts = { { &dopts, D_AGCOUNT },
+ { NULL, LAST_CONFLICT } },
.convert = true,
.minval = XFS_AG_MIN_BYTES,
.maxval = XFS_AG_MAX_BYTES,
.defaultval = SUBOPT_NEEDS_VAL,
},
{ .index = D_SU,
- .conflicts = { D_NOALIGN,
- D_SUNIT,
- D_SWIDTH,
- LAST_CONFLICT },
+ .conflicts = { { &dopts, D_NOALIGN },
+ { &dopts, D_SUNIT },
+ { &dopts, D_SWIDTH },
+ { NULL, LAST_CONFLICT } },
.convert = true,
.minval = 0,
.maxval = UINT_MAX,
.defaultval = SUBOPT_NEEDS_VAL,
},
{ .index = D_SW,
- .conflicts = { D_NOALIGN,
- D_SUNIT,
- D_SWIDTH,
- LAST_CONFLICT },
+ .conflicts = { { &dopts, D_NOALIGN },
+ { &dopts, D_SUNIT },
+ { &dopts, D_SWIDTH },
+ { NULL, LAST_CONFLICT } },
.minval = 0,
.maxval = UINT_MAX,
.defaultval = SUBOPT_NEEDS_VAL,
},
- { .index = D_SECTLOG,
- .conflicts = { D_SECTSIZE,
- LAST_CONFLICT },
- .minval = XFS_MIN_SECTORSIZE_LOG,
- .maxval = XFS_MAX_SECTORSIZE_LOG,
- .defaultval = SUBOPT_NEEDS_VAL,
- },
{ .index = D_SECTSIZE,
- .conflicts = { D_SECTLOG,
- LAST_CONFLICT },
+ .conflicts = { { &sopts, S_SIZE },
+ { &sopts, S_SECTSIZE },
+ { NULL, LAST_CONFLICT } },
.convert = true,
.is_power_2 = true,
.minval = XFS_MIN_SECTORSIZE,
.defaultval = SUBOPT_NEEDS_VAL,
},
{ .index = D_NOALIGN,
- .conflicts = { D_SU,
- D_SW,
- D_SUNIT,
- D_SWIDTH,
- LAST_CONFLICT },
+ .conflicts = { { &dopts, D_SU },
+ { &dopts, D_SW },
+ { &dopts, D_SUNIT },
+ { &dopts, D_SWIDTH },
+ { NULL, LAST_CONFLICT } },
.minval = 0,
.maxval = 1,
.defaultval = 1,
},
{ .index = D_RTINHERIT,
- .conflicts = { LAST_CONFLICT },
+ .conflicts = { { NULL, LAST_CONFLICT } },
.minval = 1,
.maxval = 1,
.defaultval = 1,
},
{ .index = D_PROJINHERIT,
- .conflicts = { LAST_CONFLICT },
+ .conflicts = { { NULL, LAST_CONFLICT } },
.minval = 0,
.maxval = UINT_MAX,
.defaultval = SUBOPT_NEEDS_VAL,
},
{ .index = D_EXTSZINHERIT,
- .conflicts = { LAST_CONFLICT },
+ .conflicts = { { NULL, LAST_CONFLICT } },
.minval = 0,
.maxval = UINT_MAX,
.defaultval = SUBOPT_NEEDS_VAL,
},
{ .index = D_COWEXTSIZE,
- .conflicts = { LAST_CONFLICT },
+ .conflicts = { { NULL, LAST_CONFLICT } },
.minval = 0,
.maxval = UINT_MAX,
.defaultval = SUBOPT_NEEDS_VAL,
struct opt_params iopts = {
.name = 'i',
.subopts = {
-#define I_ALIGN 0
- "align",
-#define I_LOG 1
- "log",
-#define I_MAXPCT 2
- "maxpct",
-#define I_PERBLOCK 3
- "perblock",
-#define I_SIZE 4
- "size",
-#define I_ATTR 5
- "attr",
-#define I_PROJID32BIT 6
- "projid32bit",
-#define I_SPINODES 7
- "sparse",
- NULL
+ [I_ALIGN] = "align",
+ [I_MAXPCT] = "maxpct",
+ [I_PERBLOCK] = "perblock",
+ [I_SIZE] = "size",
+ [I_ATTR] = "attr",
+ [I_PROJID32BIT] = "projid32bit",
+ [I_SPINODES] = "sparse",
},
.subopt_params = {
{ .index = I_ALIGN,
- .conflicts = { LAST_CONFLICT },
+ .conflicts = { { NULL, LAST_CONFLICT } },
.minval = 0,
.maxval = 1,
.defaultval = 1,
},
- { .index = I_LOG,
- .conflicts = { I_PERBLOCK,
- I_SIZE,
- LAST_CONFLICT },
- .minval = XFS_DINODE_MIN_LOG,
- .maxval = XFS_DINODE_MAX_LOG,
- .defaultval = SUBOPT_NEEDS_VAL,
- },
{ .index = I_MAXPCT,
- .conflicts = { LAST_CONFLICT },
+ .conflicts = { { NULL, LAST_CONFLICT } },
.minval = 0,
.maxval = 100,
.defaultval = SUBOPT_NEEDS_VAL,
},
{ .index = I_PERBLOCK,
- .conflicts = { I_LOG,
- I_SIZE,
- LAST_CONFLICT },
+ .conflicts = { { &iopts, I_SIZE },
+ { NULL, LAST_CONFLICT } },
.is_power_2 = true,
.minval = XFS_MIN_INODE_PERBLOCK,
.maxval = XFS_MAX_BLOCKSIZE / XFS_DINODE_MIN_SIZE,
.defaultval = SUBOPT_NEEDS_VAL,
},
{ .index = I_SIZE,
- .conflicts = { I_PERBLOCK,
- I_LOG,
- LAST_CONFLICT },
+ .conflicts = { { &iopts, I_PERBLOCK },
+ { NULL, LAST_CONFLICT } },
.is_power_2 = true,
.minval = XFS_DINODE_MIN_SIZE,
.maxval = XFS_DINODE_MAX_SIZE,
.defaultval = SUBOPT_NEEDS_VAL,
},
{ .index = I_ATTR,
- .conflicts = { LAST_CONFLICT },
+ .conflicts = { { NULL, LAST_CONFLICT } },
.minval = 0,
.maxval = 2,
.defaultval = SUBOPT_NEEDS_VAL,
},
{ .index = I_PROJID32BIT,
- .conflicts = { LAST_CONFLICT },
+ .conflicts = { { NULL, LAST_CONFLICT } },
.minval = 0,
.maxval = 1,
.defaultval = 1,
},
{ .index = I_SPINODES,
- .conflicts = { LAST_CONFLICT },
+ .conflicts = { { NULL, LAST_CONFLICT } },
.minval = 0,
.maxval = 1,
.defaultval = 1,
struct opt_params lopts = {
.name = 'l',
.subopts = {
-#define L_AGNUM 0
- "agnum",
-#define L_INTERNAL 1
- "internal",
-#define L_SIZE 2
- "size",
-#define L_VERSION 3
- "version",
-#define L_SUNIT 4
- "sunit",
-#define L_SU 5
- "su",
-#define L_DEV 6
- "logdev",
-#define L_SECTLOG 7
- "sectlog",
-#define L_SECTSIZE 8
- "sectsize",
-#define L_FILE 9
- "file",
-#define L_NAME 10
- "name",
-#define L_LAZYSBCNTR 11
- "lazy-count",
- NULL
+ [L_AGNUM] = "agnum",
+ [L_INTERNAL] = "internal",
+ [L_SIZE] = "size",
+ [L_VERSION] = "version",
+ [L_SUNIT] = "sunit",
+ [L_SU] = "su",
+ [L_DEV] = "logdev",
+ [L_SECTSIZE] = "sectsize",
+ [L_FILE] = "file",
+ [L_NAME] = "name",
+ [L_LAZYSBCNTR] = "lazy-count",
},
.subopt_params = {
{ .index = L_AGNUM,
- .conflicts = { L_DEV,
- LAST_CONFLICT },
+ .conflicts = { { &lopts, L_DEV },
+ { NULL, LAST_CONFLICT } },
.minval = 0,
.maxval = UINT_MAX,
.defaultval = SUBOPT_NEEDS_VAL,
},
{ .index = L_INTERNAL,
- .conflicts = { L_FILE,
- L_DEV,
- L_SECTLOG,
- L_SECTSIZE,
- LAST_CONFLICT },
+ .conflicts = { { &lopts, L_FILE },
+ { &lopts, L_DEV },
+ { &lopts, L_SECTSIZE },
+ { NULL, LAST_CONFLICT } },
.minval = 0,
.maxval = 1,
.defaultval = 1,
},
{ .index = L_SIZE,
- .conflicts = { LAST_CONFLICT },
+ .conflicts = { { NULL, LAST_CONFLICT } },
.convert = true,
.minval = 2 * 1024 * 1024LL, /* XXX: XFS_MIN_LOG_BYTES */
.maxval = XFS_MAX_LOG_BYTES,
.defaultval = SUBOPT_NEEDS_VAL,
},
{ .index = L_VERSION,
- .conflicts = { LAST_CONFLICT },
+ .conflicts = { { NULL, LAST_CONFLICT } },
.minval = 1,
.maxval = 2,
.defaultval = SUBOPT_NEEDS_VAL,
},
{ .index = L_SUNIT,
- .conflicts = { L_SU,
- LAST_CONFLICT },
+ .conflicts = { { &lopts, L_SU },
+ { NULL, LAST_CONFLICT } },
.minval = 1,
.maxval = BTOBB(XLOG_MAX_RECORD_BSIZE),
.defaultval = SUBOPT_NEEDS_VAL,
},
{ .index = L_SU,
- .conflicts = { L_SUNIT,
- LAST_CONFLICT },
+ .conflicts = { { &lopts, L_SUNIT },
+ { NULL, LAST_CONFLICT } },
.convert = true,
.minval = BBTOB(1),
.maxval = XLOG_MAX_RECORD_BSIZE,
.defaultval = SUBOPT_NEEDS_VAL,
},
{ .index = L_DEV,
- .conflicts = { L_AGNUM,
- L_INTERNAL,
- LAST_CONFLICT },
- .defaultval = SUBOPT_NEEDS_VAL,
- },
- { .index = L_SECTLOG,
- .conflicts = { L_SECTSIZE,
- L_INTERNAL,
- LAST_CONFLICT },
- .minval = XFS_MIN_SECTORSIZE_LOG,
- .maxval = XFS_MAX_SECTORSIZE_LOG,
+ .conflicts = { { &lopts, L_AGNUM },
+ { &lopts, L_NAME },
+ { &lopts, L_INTERNAL },
+ { NULL, LAST_CONFLICT } },
.defaultval = SUBOPT_NEEDS_VAL,
},
{ .index = L_SECTSIZE,
- .conflicts = { L_SECTLOG,
- L_INTERNAL,
- LAST_CONFLICT },
+ .conflicts = { { &lopts, L_INTERNAL },
+ { NULL, LAST_CONFLICT } },
.convert = true,
.is_power_2 = true,
.minval = XFS_MIN_SECTORSIZE,
.defaultval = SUBOPT_NEEDS_VAL,
},
{ .index = L_FILE,
- .conflicts = { L_INTERNAL,
- LAST_CONFLICT },
+ .conflicts = { { &lopts, L_INTERNAL },
+ { NULL, LAST_CONFLICT } },
.minval = 0,
.maxval = 1,
.defaultval = 1,
},
{ .index = L_NAME,
- .conflicts = { L_AGNUM,
- L_INTERNAL,
- LAST_CONFLICT },
+ .conflicts = { { &lopts, L_AGNUM },
+ { &lopts, L_DEV },
+ { &lopts, L_INTERNAL },
+ { NULL, LAST_CONFLICT } },
.defaultval = SUBOPT_NEEDS_VAL,
},
{ .index = L_LAZYSBCNTR,
- .conflicts = { LAST_CONFLICT },
+ .conflicts = { { NULL, LAST_CONFLICT } },
.minval = 0,
.maxval = 1,
.defaultval = 1,
struct opt_params nopts = {
.name = 'n',
.subopts = {
-#define N_LOG 0
- "log",
-#define N_SIZE 1
- "size",
-#define N_VERSION 2
- "version",
-#define N_FTYPE 3
- "ftype",
- NULL,
+ [N_SIZE] = "size",
+ [N_VERSION] = "version",
+ [N_FTYPE] = "ftype",
},
.subopt_params = {
- { .index = N_LOG,
- .conflicts = { N_SIZE,
- LAST_CONFLICT },
- .minval = XFS_MIN_REC_DIRSIZE,
- .maxval = XFS_MAX_BLOCKSIZE_LOG,
- .defaultval = SUBOPT_NEEDS_VAL,
- },
{ .index = N_SIZE,
- .conflicts = { N_LOG,
- LAST_CONFLICT },
+ .conflicts = { { NULL, LAST_CONFLICT } },
.convert = true,
.is_power_2 = true,
.minval = 1 << XFS_MIN_REC_DIRSIZE,
.defaultval = SUBOPT_NEEDS_VAL,
},
{ .index = N_VERSION,
- .conflicts = { LAST_CONFLICT },
+ .conflicts = { { NULL, LAST_CONFLICT } },
.minval = 2,
.maxval = 2,
.defaultval = SUBOPT_NEEDS_VAL,
},
{ .index = N_FTYPE,
- .conflicts = { LAST_CONFLICT },
+ .conflicts = { { NULL, LAST_CONFLICT } },
.minval = 0,
.maxval = 1,
.defaultval = 1,
struct opt_params ropts = {
.name = 'r',
.subopts = {
-#define R_EXTSIZE 0
- "extsize",
-#define R_SIZE 1
- "size",
-#define R_DEV 2
- "rtdev",
-#define R_FILE 3
- "file",
-#define R_NAME 4
- "name",
-#define R_NOALIGN 5
- "noalign",
- NULL
+ [R_EXTSIZE] = "extsize",
+ [R_SIZE] = "size",
+ [R_DEV] = "rtdev",
+ [R_FILE] = "file",
+ [R_NAME] = "name",
+ [R_NOALIGN] = "noalign",
},
.subopt_params = {
{ .index = R_EXTSIZE,
- .conflicts = { LAST_CONFLICT },
+ .conflicts = { { NULL, LAST_CONFLICT } },
.convert = true,
.minval = XFS_MIN_RTEXTSIZE,
.maxval = XFS_MAX_RTEXTSIZE,
.defaultval = SUBOPT_NEEDS_VAL,
},
{ .index = R_SIZE,
- .conflicts = { LAST_CONFLICT },
+ .conflicts = { { NULL, LAST_CONFLICT } },
.convert = true,
.minval = 0,
.maxval = LLONG_MAX,
.defaultval = SUBOPT_NEEDS_VAL,
},
{ .index = R_DEV,
- .conflicts = { LAST_CONFLICT },
+ .conflicts = { { &ropts, R_NAME },
+ { NULL, LAST_CONFLICT } },
.defaultval = SUBOPT_NEEDS_VAL,
},
{ .index = R_FILE,
.minval = 0,
.maxval = 1,
.defaultval = 1,
- .conflicts = { LAST_CONFLICT },
+ .conflicts = { { NULL, LAST_CONFLICT } },
},
{ .index = R_NAME,
- .conflicts = { LAST_CONFLICT },
+ .conflicts = { { &ropts, R_DEV },
+ { NULL, LAST_CONFLICT } },
.defaultval = SUBOPT_NEEDS_VAL,
},
{ .index = R_NOALIGN,
.minval = 0,
.maxval = 1,
.defaultval = 1,
- .conflicts = { LAST_CONFLICT },
+ .conflicts = { { NULL, LAST_CONFLICT } },
},
},
};
struct opt_params sopts = {
.name = 's',
.subopts = {
-#define S_LOG 0
- "log",
-#define S_SECTLOG 1
- "sectlog",
-#define S_SIZE 2
- "size",
-#define S_SECTSIZE 3
- "sectsize",
- NULL
+ [S_SIZE] = "size",
+ [S_SECTSIZE] = "sectsize",
},
.subopt_params = {
- { .index = S_LOG,
- .conflicts = { S_SIZE,
- S_SECTSIZE,
- LAST_CONFLICT },
- .minval = XFS_MIN_SECTORSIZE_LOG,
- .maxval = XFS_MAX_SECTORSIZE_LOG,
- .defaultval = SUBOPT_NEEDS_VAL,
- },
- { .index = S_SECTLOG,
- .conflicts = { S_SIZE,
- S_SECTSIZE,
- LAST_CONFLICT },
- .minval = XFS_MIN_SECTORSIZE_LOG,
- .maxval = XFS_MAX_SECTORSIZE_LOG,
- .defaultval = SUBOPT_NEEDS_VAL,
- },
{ .index = S_SIZE,
- .conflicts = { S_LOG,
- S_SECTLOG,
- LAST_CONFLICT },
+ .conflicts = { { &sopts, S_SECTSIZE },
+ { &dopts, D_SECTSIZE },
+ { NULL, LAST_CONFLICT } },
.convert = true,
.is_power_2 = true,
.minval = XFS_MIN_SECTORSIZE,
.defaultval = SUBOPT_NEEDS_VAL,
},
{ .index = S_SECTSIZE,
- .conflicts = { S_LOG,
- S_SECTLOG,
- LAST_CONFLICT },
+ .conflicts = { { &sopts, S_SIZE },
+ { &dopts, D_SECTSIZE },
+ { NULL, LAST_CONFLICT } },
.convert = true,
.is_power_2 = true,
.minval = XFS_MIN_SECTORSIZE,
struct opt_params mopts = {
.name = 'm',
.subopts = {
-#define M_CRC 0
- "crc",
-#define M_FINOBT 1
- "finobt",
-#define M_UUID 2
- "uuid",
-#define M_RMAPBT 3
- "rmapbt",
-#define M_REFLINK 4
- "reflink",
- NULL
+ [M_CRC] = "crc",
+ [M_FINOBT] = "finobt",
+ [M_UUID] = "uuid",
+ [M_RMAPBT] = "rmapbt",
+ [M_REFLINK] = "reflink",
},
.subopt_params = {
{ .index = M_CRC,
- .conflicts = { LAST_CONFLICT },
+ .conflicts = { { NULL, LAST_CONFLICT } },
.minval = 0,
.maxval = 1,
.defaultval = 1,
},
{ .index = M_FINOBT,
- .conflicts = { LAST_CONFLICT },
+ .conflicts = { { NULL, LAST_CONFLICT } },
.minval = 0,
.maxval = 1,
.defaultval = 1,
},
{ .index = M_UUID,
- .conflicts = { LAST_CONFLICT },
+ .conflicts = { { NULL, LAST_CONFLICT } },
.defaultval = SUBOPT_NEEDS_VAL,
},
{ .index = M_RMAPBT,
- .conflicts = { LAST_CONFLICT },
+ .conflicts = { { NULL, LAST_CONFLICT } },
.minval = 0,
.maxval = 1,
.defaultval = 1,
},
{ .index = M_REFLINK,
- .conflicts = { LAST_CONFLICT },
+ .conflicts = { { NULL, LAST_CONFLICT } },
.minval = 0,
.maxval = 1,
.defaultval = 1,
int log_version;
int attr_version;
int dir_version;
- bool inode_align;
- bool nci;
- bool lazy_sb_counters;
- bool projid16bit;
- bool crcs_enabled;
- bool dirftype;
- bool finobt;
- bool spinodes;
- bool rmapbt;
- bool reflink;
- bool parent_pointers;
+ bool inode_align; /* XFS_SB_VERSION_ALIGNBIT */
+ bool nci; /* XFS_SB_VERSION_BORGBIT */
+ bool lazy_sb_counters; /* XFS_SB_VERSION2_LAZYSBCOUNTBIT */
+ bool parent_pointers; /* XFS_SB_VERSION2_PARENTBIT */
+ bool projid32bit; /* XFS_SB_VERSION2_PROJID32BIT */
+ bool crcs_enabled; /* XFS_SB_VERSION2_CRCBIT */
+ bool dirftype; /* XFS_SB_VERSION2_FTYPE */
+ bool finobt; /* XFS_SB_FEAT_RO_COMPAT_FINOBT */
+ bool spinodes; /* XFS_SB_FEAT_INCOMPAT_SPINODES */
+ bool rmapbt; /* XFS_SB_FEAT_RO_COMPAT_RMAPBT */
+ bool reflink; /* XFS_SB_FEAT_RO_COMPAT_REFLINK */
bool nodalign;
bool nortalign;
- uuid_t m_uuid;
};
struct cli_params {
/* parameters where 0 is not a valid value */
int64_t agcount;
- int dirblocklog;
int inodesize;
int inopblock;
int imaxpct;
struct fsxattr fsx;
};
-#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)))
+static void __attribute__((noreturn))
+usage( void )
+{
+ fprintf(stderr, _("Usage: %s\n\
+/* blocksize */ [-b size=num]\n\
+/* metadata */ [-m crc=0|1,finobt=0|1,uuid=xxx,rmapbt=0|1,reflink=0|1]\n\
+/* data subvol */ [-d agcount=n,agsize=n,file,name=xxx,size=num,\n\
+ (sunit=value,swidth=value|su=num,sw=num|noalign),\n\
+ sectsize=num\n\
+/* force overwrite */ [-f]\n\
+/* inode size */ [-i log=n|perblock=n|size=num,maxpct=n,attr=0|1|2,\n\
+ projid32bit=0|1,sparse=0|1]\n\
+/* no discard */ [-K]\n\
+/* log subvol */ [-l agnum=n,internal,size=num,logdev=xxx,version=n\n\
+ sunit=value|su=num,sectsize=num,lazy-count=0|1]\n\
+/* label */ [-L label (maximum 12 characters)]\n\
+/* naming */ [-n size=num,version=2|ci,ftype=0|1]\n\
+/* no-op info only */ [-N]\n\
+/* prototype file */ [-p fname]\n\
+/* quiet */ [-q]\n\
+/* realtime subvol */ [-r extsize=num,size=num,rtdev=xxx]\n\
+/* sectorsize */ [-s size=num]\n\
+/* version */ [-V]\n\
+ devicename\n\
+<devicename> is required unless -d name=xxx is given.\n\
+<num> is xxx (bytes), xxxs (sectors), xxxb (fs blocks), xxxk (xxx KiB),\n\
+ xxxm (xxx MiB), xxxg (xxx GiB), xxxt (xxx TiB) or xxxp (xxx PiB).\n\
+<value> is xxx (512 byte blocks).\n"),
+ progname);
+ exit(1);
+}
-/*
- * Use this macro before we have superblock and mount structure
- */
-#define DTOBT(d, bl) ((xfs_rfsblock_t)((d) >> ((bl) - BBSHIFT)))
+static void
+conflict(
+ struct opt_params *opts,
+ int option,
+ struct opt_params *con_opts,
+ int conflict)
+{
+ fprintf(stderr, _("Cannot specify both -%c %s and -%c %s\n"),
+ con_opts->name, con_opts->subopts[conflict],
+ opts->name, opts->subopts[option]);
+ usage();
+}
-/*
- * Use this for block reservations needed for mkfs's conditions
- * (basically no fragmentation).
- */
-#define MKFS_BLOCKRES_INODE \
- ((uint)(mp->m_ialloc_blks + (mp->m_in_maxlevels - 1)))
-#define MKFS_BLOCKRES(rb) \
- ((uint)(MKFS_BLOCKRES_INODE + XFS_DA_NODE_MAXDEPTH + \
- (XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) - 1) + (rb)))
-/* amount (in bytes) we zero at the beginning and end of the device to
- * remove traces of other filesystems, raid superblocks, etc.
- */
-#define WHACK_SIZE (128 * 1024)
+static void
+illegal(
+ const char *value,
+ const char *opt)
+{
+ fprintf(stderr, _("Invalid value %s for -%s option\n"), value, opt);
+ usage();
+}
+
+static int
+ispow2(
+ unsigned int i)
+{
+ return (i & (i - 1)) == 0;
+}
+
+static void __attribute__((noreturn))
+reqval(
+ char opt,
+ const char *tab[],
+ int idx)
+{
+ fprintf(stderr, _("-%c %s option requires a value\n"), opt, tab[idx]);
+ usage();
+}
+
+static void
+respec(
+ char opt,
+ const char *tab[],
+ int idx)
+{
+ fprintf(stderr, "-%c ", opt);
+ if (tab)
+ fprintf(stderr, "%s ", tab[idx]);
+ fprintf(stderr, _("option respecified\n"));
+ usage();
+}
+
+static void
+unknown(
+ char opt,
+ char *s)
+{
+ fprintf(stderr, _("unknown option -%c %s\n"), opt, s);
+ usage();
+}
+
+long long
+cvtnum(
+ unsigned int blksize,
+ unsigned int sectsize,
+ const char *s)
+{
+ long long i;
+ char *sp;
+ int c;
+
+ i = strtoll(s, &sp, 0);
+ if (i == 0 && sp == s)
+ return -1LL;
+ if (*sp == '\0')
+ return i;
+
+ if (sp[1] != '\0')
+ return -1LL;
+
+ 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:
+ break;
+ }
+ return -1LL;
+}
static void
check_device_type(
}
static void
-fixup_log_stripe_unit(
- int lsflag,
- int sunit,
- xfs_rfsblock_t *logblocks,
- int blocklog)
-{
- uint64_t tmp_logblocks;
-
- /*
- * Make sure that the log size is a multiple of the stripe unit
- */
- if ((*logblocks % sunit) != 0) {
- if (!lsflag) {
- tmp_logblocks = ((*logblocks + (sunit - 1))
- / sunit) * sunit;
- /*
- * 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 / sunit) * sunit;
- }
- *logblocks = tmp_logblocks;
- } else {
- fprintf(stderr, _("log size %lld is not a multiple "
- "of the log stripe unit %d\n"),
- (long long) *logblocks, sunit);
- usage();
- }
- }
-}
-
-static xfs_fsblock_t
-fixup_internal_log_stripe(
- xfs_mount_t *mp,
- int lsflag,
- xfs_fsblock_t logstart,
- uint64_t agsize,
- int sunit,
- xfs_rfsblock_t *logblocks,
+validate_ag_geometry(
int blocklog,
- int *lalign)
+ uint64_t dblocks,
+ uint64_t agsize,
+ uint64_t agcount)
{
- if ((logstart % sunit) != 0) {
- logstart = ((logstart + (sunit - 1))/sunit) * sunit;
- *lalign = 1;
+ if (agsize < XFS_AG_MIN_BLOCKS(blocklog)) {
+ fprintf(stderr,
+ _("agsize (%lld blocks) too small, need at least %lld blocks\n"),
+ (long long)agsize,
+ (long long)XFS_AG_MIN_BLOCKS(blocklog));
+ usage();
}
- fixup_log_stripe_unit(lsflag, sunit, logblocks, blocklog);
-
- if (*logblocks > agsize - XFS_FSB_TO_AGBNO(mp, logstart)) {
+ if (agsize > XFS_AG_MAX_BLOCKS(blocklog)) {
fprintf(stderr,
- _("Due to stripe alignment, the internal log size "
- "(%lld) is too large.\n"), (long long) *logblocks);
- fprintf(stderr, _("Must fit within an allocation group.\n"));
+ _("agsize (%lld blocks) too big, maximum is %lld blocks\n"),
+ (long long)agsize,
+ (long long)XFS_AG_MAX_BLOCKS(blocklog));
usage();
}
- return logstart;
-}
-void
-validate_log_size(uint64_t logblocks, int blocklog, int min_logblocks)
-{
- if (logblocks < min_logblocks) {
+ if (agsize > dblocks) {
fprintf(stderr,
- _("log size %lld blocks too small, minimum size is %d blocks\n"),
- (long long)logblocks, min_logblocks);
- usage();
+ _("agsize (%lld blocks) too big, data area is %lld blocks\n"),
+ (long long)agsize, (long long)dblocks);
+ usage();
}
- if (logblocks > XFS_MAX_LOG_BLOCKS) {
+
+ if (agsize < XFS_AG_MIN_BLOCKS(blocklog)) {
fprintf(stderr,
- _("log size %lld blocks too large, maximum size is %lld blocks\n"),
- (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 %lld bytes\n"),
- (long long)(logblocks << blocklog), XFS_MAX_LOG_BYTES);
- usage();
- }
-}
-
-static int
-calc_default_imaxpct(
- int blocklog,
- uint64_t dblocks)
-{
- /*
- * This returns the % of the disk space that is used for
- * inodes, it changes relatively to the FS size:
- * - over 50 TB, use 1%,
- * - 1TB - 50 TB, use 5%,
- * - under 1 TB, use XFS_DFL_IMAXIMUM_PCT (25%).
- */
-
- if (dblocks < TERABYTES(1, blocklog)) {
- return XFS_DFL_IMAXIMUM_PCT;
- } else if (dblocks < TERABYTES(50, blocklog)) {
- return 5;
- }
-
- return 1;
-}
-
-static void
-validate_ag_geometry(
- int blocklog,
- uint64_t dblocks,
- uint64_t agsize,
- uint64_t agcount)
-{
- if (agsize < XFS_AG_MIN_BLOCKS(blocklog)) {
- fprintf(stderr,
- _("agsize (%lld blocks) 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 (%lld blocks) too big, maximum is %lld blocks\n"),
- (long long)agsize,
- (long long)XFS_AG_MAX_BLOCKS(blocklog));
- usage();
- }
-
- if (agsize > dblocks) {
- fprintf(stderr,
- _("agsize (%lld blocks) too big, data area is %lld blocks\n"),
- (long long)agsize, (long long)dblocks);
- usage();
- }
-
- if (agsize < XFS_AG_MIN_BLOCKS(blocklog)) {
- fprintf(stderr,
- _("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) +
- (dblocks % XFS_AG_MIN_BLOCKS(blocklog) != 0)));
+ _("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) +
+ (dblocks % XFS_AG_MIN_BLOCKS(blocklog) != 0)));
usage();
}
platform_discard_blocks(fd, 0, nsectors << 9);
}
-static void
-sb_set_features(
- struct xfs_sb *sbp,
- struct sb_feat_args *fp,
- int sectsize,
- int lsectsize,
- int dsunit)
-{
-
- sbp->sb_versionnum = XFS_DFL_SB_VERSION_BITS;
- if (fp->crcs_enabled)
- sbp->sb_versionnum |= XFS_SB_VERSION_5;
- else
- sbp->sb_versionnum |= XFS_SB_VERSION_4;
-
- if (fp->inode_align)
- sbp->sb_versionnum |= XFS_SB_VERSION_ALIGNBIT;
- if (dsunit)
- sbp->sb_versionnum |= XFS_SB_VERSION_DALIGNBIT;
- if (fp->log_version == 2)
- sbp->sb_versionnum |= XFS_SB_VERSION_LOGV2BIT;
- if (fp->attr_version == 1)
- sbp->sb_versionnum |= XFS_SB_VERSION_ATTRBIT;
- if (sectsize > BBSIZE || lsectsize > BBSIZE)
- sbp->sb_versionnum |= XFS_SB_VERSION_SECTORBIT;
- if (fp->nci)
- sbp->sb_versionnum |= XFS_SB_VERSION_BORGBIT;
-
-
- sbp->sb_features2 = 0;
- if (fp->lazy_sb_counters)
- sbp->sb_features2 |= XFS_SB_VERSION2_LAZYSBCOUNTBIT;
- if (!fp->projid16bit)
- sbp->sb_features2 |= XFS_SB_VERSION2_PROJID32BIT;
- if (fp->parent_pointers)
- sbp->sb_features2 |= XFS_SB_VERSION2_PARENTBIT;
- if (fp->crcs_enabled)
- sbp->sb_features2 |= XFS_SB_VERSION2_CRCBIT;
- if (fp->attr_version == 2)
- sbp->sb_features2 |= XFS_SB_VERSION2_ATTR2BIT;
-
- /* v5 superblocks have their own feature bit for dirftype */
- if (fp->dirftype && !fp->crcs_enabled)
- sbp->sb_features2 |= XFS_SB_VERSION2_FTYPE;
-
- /* update whether extended features are in use */
- if (sbp->sb_features2 != 0)
- sbp->sb_versionnum |= XFS_SB_VERSION_MOREBITSBIT;
-
- /*
- * Due to a structure alignment issue, sb_features2 ended up in one
- * of two locations, the second "incorrect" location represented by
- * the sb_bad_features2 field. To avoid older kernels mounting
- * filesystems they shouldn't, set both field to the same value.
- */
- sbp->sb_bad_features2 = sbp->sb_features2;
-
- if (!fp->crcs_enabled)
- return;
-
- /* default features for v5 filesystems */
- sbp->sb_features_compat = 0;
- sbp->sb_features_ro_compat = 0;
- sbp->sb_features_incompat = XFS_SB_FEAT_INCOMPAT_FTYPE;
- sbp->sb_features_log_incompat = 0;
-
- 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.
- * First, sparse chunk alignment must match the cluster size. Second,
- * full chunk alignment must match the inode chunk size.
- *
- * Copy the already calculated/scaled inoalignmt to spino_align and
- * update the former to the full inode chunk size.
- */
- if (fp->spinodes) {
- sbp->sb_spino_align = sbp->sb_inoalignmt;
- sbp->sb_inoalignmt = XFS_INODES_PER_CHUNK *
- sbp->sb_inodesize >> sbp->sb_blocklog;
- sbp->sb_features_incompat |= XFS_SB_FEAT_INCOMPAT_SPINODES;
- }
-
-}
-
static __attribute__((noreturn)) void
illegal_option(
const char *value,
const char *reason)
{
fprintf(stderr,
- _("Illegal value %s for -%c %s option. %s\n"),
+ _("Invalid value %s for -%c %s option. %s\n"),
value, opts->name, opts->subopts[index],
- reason ? reason : "");
+ reason);
usage();
}
/* check for conflicts with the option */
for (i = 0; i < MAX_CONFLICTS; i++) {
- int conflict_opt = sp->conflicts[i];
+ struct _conflict *con = &sp->conflicts[i];
- if (conflict_opt == LAST_CONFLICT)
+ if (con->subopt == LAST_CONFLICT)
break;
- if (opts->subopt_params[conflict_opt].seen ||
- opts->subopt_params[conflict_opt].str_seen)
- conflict(opts->name, opts->subopts,
- conflict_opt, index);
+ if (con->opts->subopt_params[con->subopt].seen ||
+ con->opts->subopt_params[con->subopt].str_seen)
+ conflict(opts, index, con->opts, con->subopt);
}
}
c = strtoll(str, &str_end, 0);
if (c == 0 && str_end == str)
- illegal_option(str, opts, index, NULL);
+ illegal_option(str, opts, index,
+ _("Value not recognized as number."));
if (*str_end != '\0')
- illegal_option(str, opts, index, NULL);
+ illegal_option(str, opts, index,
+ _("Unit suffixes are not allowed."));
}
/* Validity check the result. */
if (c < sp->minval)
- illegal_option(str, opts, index, _("value is too small"));
+ illegal_option(str, opts, index, _("Value is too small."));
else if (c > sp->maxval)
- illegal_option(str, opts, index, _("value is too large"));
+ illegal_option(str, opts, index, _("Value is too large."));
if (sp->is_power_2 && !ispow2(c))
- illegal_option(str, opts, index, _("value must be a power of 2"));
+ illegal_option(str, opts, index, _("Value must be a power of 2."));
return c;
}
char *value,
struct cli_params *cli)
{
- int blocklog;
-
switch (subopt) {
- case B_LOG:
- blocklog = getnum(value, opts, B_LOG);
- cli->blocksize = 1 << blocklog;
- break;
case B_SIZE:
- cli->blocksize = getnum(value, opts, B_SIZE);
+ cli->blocksize = getnum(value, opts, subopt);
break;
default:
return -EINVAL;
char *value,
struct cli_params *cli)
{
- int sectorlog;
-
switch (subopt) {
case D_AGCOUNT:
- cli->agcount = getnum(value, opts, D_AGCOUNT);
+ cli->agcount = getnum(value, opts, subopt);
break;
case D_AGSIZE:
- cli->agsize = getstr(value, opts, D_AGSIZE);
+ cli->agsize = getstr(value, opts, subopt);
break;
case D_FILE:
- cli->xi->disfile = getnum(value, opts, D_FILE);
+ cli->xi->disfile = getnum(value, opts, subopt);
break;
case D_NAME:
- cli->xi->dname = getstr(value, opts, D_NAME);
+ cli->xi->dname = getstr(value, opts, subopt);
break;
case D_SIZE:
- cli->dsize = getstr(value, opts, D_SIZE);
+ cli->dsize = getstr(value, opts, subopt);
break;
case D_SUNIT:
- cli->dsunit = getnum(value, opts, D_SUNIT);
+ cli->dsunit = getnum(value, opts, subopt);
break;
case D_SWIDTH:
- cli->dswidth = getnum(value, opts, D_SWIDTH);
+ cli->dswidth = getnum(value, opts, subopt);
break;
case D_SU:
- cli->dsu = getstr(value, opts, D_SU);
+ cli->dsu = getstr(value, opts, subopt);
break;
case D_SW:
- cli->dsw = getnum(value, opts, D_SW);
+ cli->dsw = getnum(value, opts, subopt);
break;
case D_NOALIGN:
- cli->sb_feat.nodalign = getnum(value, opts, D_NOALIGN);
- break;
- case D_SECTLOG:
- if (cli->sectorsize)
- conflict('d', opts->subopts, D_SECTSIZE, D_SECTLOG);
- sectorlog = getnum(value, opts, D_SECTLOG);
- cli->sectorsize = 1 << sectorlog;
+ cli->sb_feat.nodalign = getnum(value, opts, subopt);
break;
case D_SECTSIZE:
- if (cli->sectorsize)
- conflict('d', opts->subopts, D_SECTSIZE, D_SECTLOG);
- cli->sectorsize = getnum(value, opts, D_SECTSIZE);
+ cli->sectorsize = getnum(value, opts, subopt);
break;
case D_RTINHERIT:
- if (getnum(value, opts, D_RTINHERIT))
+ if (getnum(value, opts, subopt))
cli->fsx.fsx_xflags |= XFS_DIFLAG_RTINHERIT;
break;
case D_PROJINHERIT:
- cli->fsx.fsx_projid = getnum(value, opts, D_PROJINHERIT);
+ cli->fsx.fsx_projid = getnum(value, opts, subopt);
cli->fsx.fsx_xflags |= XFS_DIFLAG_PROJINHERIT;
break;
case D_EXTSZINHERIT:
- cli->fsx.fsx_extsize = getnum(value, opts, D_EXTSZINHERIT);
+ cli->fsx.fsx_extsize = getnum(value, opts, subopt);
cli->fsx.fsx_xflags |= XFS_DIFLAG_EXTSZINHERIT;
break;
case D_COWEXTSIZE:
- cli->fsx.fsx_cowextsize = getnum(value, opts, D_COWEXTSIZE);
+ cli->fsx.fsx_cowextsize = getnum(value, opts, subopt);
cli->fsx.fsx_xflags |= FS_XFLAG_COWEXTSIZE;
break;
default:
char *value,
struct cli_params *cli)
{
- int inodelog;
-
switch (subopt) {
case I_ALIGN:
- cli->sb_feat.inode_align = getnum(value, &iopts, I_ALIGN);
- break;
- case I_LOG:
- inodelog = getnum(value, &iopts, I_LOG);
- cli->inodesize = 1 << inodelog;
+ cli->sb_feat.inode_align = getnum(value, opts, subopt);
break;
case I_MAXPCT:
- cli->imaxpct = getnum(value, &iopts, I_MAXPCT);
+ cli->imaxpct = getnum(value, opts, subopt);
break;
case I_PERBLOCK:
- cli->inopblock = getnum(value, &iopts, I_PERBLOCK);
+ cli->inopblock = getnum(value, opts, subopt);
break;
case I_SIZE:
- cli->inodesize = getnum(value, &iopts, I_SIZE);
+ cli->inodesize = getnum(value, opts, subopt);
break;
case I_ATTR:
- cli->sb_feat.attr_version = getnum(value, &iopts, I_ATTR);
+ cli->sb_feat.attr_version = getnum(value, opts, subopt);
break;
case I_PROJID32BIT:
- cli->sb_feat.projid16bit = !getnum(value, &iopts, I_PROJID32BIT);
+ cli->sb_feat.projid32bit = getnum(value, opts, subopt);
break;
case I_SPINODES:
- cli->sb_feat.spinodes = getnum(value, &iopts, I_SPINODES);
+ cli->sb_feat.spinodes = getnum(value, opts, subopt);
break;
default:
return -EINVAL;
char *value,
struct cli_params *cli)
{
- int lsectorlog;
-
switch (subopt) {
case L_AGNUM:
- cli->logagno = getnum(value, &lopts, L_AGNUM);
+ cli->logagno = getnum(value, opts, subopt);
break;
case L_FILE:
- cli->xi->lisfile = getnum(value, &lopts, L_FILE);
+ cli->xi->lisfile = getnum(value, opts, subopt);
break;
case L_INTERNAL:
- cli->loginternal = getnum(value, &lopts, L_INTERNAL);
+ cli->loginternal = getnum(value, opts, subopt);
break;
case L_SU:
- cli->lsu = getstr(value, &lopts, L_SU);
+ cli->lsu = getstr(value, opts, subopt);
break;
case L_SUNIT:
- cli->lsunit = getnum(value, &lopts, L_SUNIT);
+ cli->lsunit = getnum(value, opts, subopt);
break;
case L_NAME:
case L_DEV:
- cli->xi->logname = getstr(value, &lopts, L_NAME);
+ cli->xi->logname = getstr(value, opts, subopt);
cli->loginternal = 0;
break;
case L_VERSION:
- cli->sb_feat.log_version = getnum(value, &lopts, L_VERSION);
+ cli->sb_feat.log_version = getnum(value, opts, subopt);
break;
case L_SIZE:
- cli->logsize = getstr(value, &lopts, L_SIZE);
- break;
- case L_SECTLOG:
- lsectorlog = getnum(value, &lopts, L_SECTLOG);
- cli->lsectorsize = 1 << lsectorlog;
+ cli->logsize = getstr(value, opts, subopt);
break;
case L_SECTSIZE:
- cli->lsectorsize = getnum(value, &lopts, L_SECTSIZE);
+ cli->lsectorsize = getnum(value, opts, subopt);
break;
case L_LAZYSBCNTR:
- cli->sb_feat.lazy_sb_counters = getnum(value, &lopts, L_LAZYSBCNTR);
+ cli->sb_feat.lazy_sb_counters = getnum(value, opts, subopt);
break;
default:
return -EINVAL;
{
switch (subopt) {
case M_CRC:
- cli->sb_feat.crcs_enabled = getnum(value, &mopts, M_CRC);
+ cli->sb_feat.crcs_enabled = getnum(value, opts, subopt);
if (cli->sb_feat.crcs_enabled)
cli->sb_feat.dirftype = true;
break;
case M_FINOBT:
- cli->sb_feat.finobt = getnum(value, &mopts, M_FINOBT);
+ cli->sb_feat.finobt = getnum(value, opts, subopt);
break;
case M_UUID:
if (!value || *value == '\0')
- reqval('m', opts->subopts, M_UUID);
+ reqval('m', opts->subopts, subopt);
if (platform_uuid_parse(value, &cli->uuid))
illegal(value, "m uuid");
break;
case M_RMAPBT:
- cli->sb_feat.rmapbt = getnum(value, &mopts, M_RMAPBT);
+ cli->sb_feat.rmapbt = getnum(value, opts, subopt);
break;
case M_REFLINK:
- cli->sb_feat.reflink = getnum(value, &mopts, M_REFLINK);
+ cli->sb_feat.reflink = getnum(value, opts, subopt);
break;
default:
return -EINVAL;
struct cli_params *cli)
{
switch (subopt) {
- case N_LOG:
- cli->dirblocklog = getnum(value, opts, N_LOG);
- break;
case N_SIZE:
- cli->dirblocksize = getstr(value, opts, N_SIZE);
+ cli->dirblocksize = getstr(value, opts, subopt);
break;
case N_VERSION:
- value = getstr(value, &nopts, N_VERSION);
+ value = getstr(value, &nopts, subopt);
if (!strcasecmp(value, "ci")) {
/* ASCII CI mode */
cli->sb_feat.nci = true;
} else {
- cli->sb_feat.dir_version = getnum(value, opts, N_VERSION);
+ cli->sb_feat.dir_version = getnum(value, opts, subopt);
}
break;
case N_FTYPE:
- cli->sb_feat.dirftype = getnum(value, opts, N_FTYPE);
+ cli->sb_feat.dirftype = getnum(value, opts, subopt);
break;
default:
return -EINVAL;
{
switch (subopt) {
case R_EXTSIZE:
- cli->rtextsize = getstr(value, &ropts, R_EXTSIZE);
+ cli->rtextsize = getstr(value, opts, subopt);
break;
case R_FILE:
- cli->xi->risfile = getnum(value, &ropts, R_FILE);
+ cli->xi->risfile = getnum(value, opts, subopt);
break;
case R_NAME:
case R_DEV:
- cli->xi->rtname = getstr(value, &ropts, R_NAME);
+ cli->xi->rtname = getstr(value, opts, subopt);
break;
case R_SIZE:
- cli->rtsize = getstr(value, &ropts, R_SIZE);
+ cli->rtsize = getstr(value, opts, subopt);
break;
case R_NOALIGN:
- cli->sb_feat.nortalign = getnum(value, &ropts, R_NOALIGN);
+ cli->sb_feat.nortalign = getnum(value, opts, subopt);
break;
default:
return -EINVAL;
char *value,
struct cli_params *cli)
{
- int sectorlog;
-
switch (subopt) {
- case S_LOG:
- case S_SECTLOG:
- if (cli->sectorsize)
- conflict('s', opts->subopts, S_SECTSIZE, S_SECTLOG);
- sectorlog = getnum(value, &sopts, S_SECTLOG);
- cli->sectorsize = 1 << sectorlog;
- cli->lsectorsize = cli->sectorsize;
- break;
case S_SIZE:
case S_SECTSIZE:
- if (cli->sectorsize)
- conflict('s', opts->subopts, S_SECTLOG, S_SECTSIZE);
- cli->sectorsize = getnum(value, &sopts, S_SECTSIZE);
+ cli->sectorsize = getnum(value, opts, subopt);
cli->lsectorsize = cli->sectorsize;
break;
default:
/* inodes always aligned */
if (!cli->sb_feat.inode_align) {
fprintf(stderr,
-_("Inodes always aligned for CRC enabled filesytems\n"));
+_("Inodes always aligned for CRC enabled filesystems\n"));
usage();
}
/* lazy sb counters always on */
if (!cli->sb_feat.lazy_sb_counters) {
fprintf(stderr,
-_("Lazy superblock counted always enabled for CRC enabled filesytems\n"));
+_("Lazy superblock counters always enabled for CRC enabled filesystems\n"));
usage();
}
/* version 2 logs always on */
if (cli->sb_feat.log_version != 2) {
fprintf(stderr,
-_("V2 logs always enabled for CRC enabled filesytems\n"));
+_("V2 logs always enabled for CRC enabled filesystems\n"));
usage();
}
/* attr2 always on */
if (cli->sb_feat.attr_version != 2) {
fprintf(stderr,
-_("V2 attribute format always enabled on CRC enabled filesytems\n"));
+_("V2 attribute format always enabled on CRC enabled filesystems\n"));
usage();
}
/* 32 bit project quota always on */
/* attr2 always on */
- if (cli->sb_feat.projid16bit) {
+ if (!cli->sb_feat.projid32bit) {
fprintf(stderr,
-_("32 bit Project IDs always enabled on CRC enabled filesytems\n"));
+_("32 bit Project IDs always enabled on CRC enabled filesystems\n"));
usage();
}
/* ftype always on */
if (!cli->sb_feat.dirftype) {
fprintf(stderr,
-_("Directory ftype field always enabled on CRC enabled filesytems\n"));
+_("Directory ftype field always enabled on CRC enabled filesystems\n"));
usage();
}
}
cli->sb_feat.finobt = false;
- if (cli->sb_feat.spinodes) {
+ if (cli->sb_feat.spinodes && cli_opt_set(&iopts, I_SPINODES)) {
fprintf(stderr,
_("sparse inodes not supported without CRC support\n"));
usage();
usage();
}
+ if (cli->sb_feat.reflink && cli->xi->rtname) {
+ fprintf(stderr,
+_("reflink not supported with realtime devices\n"));
+ usage();
+ cli->sb_feat.reflink = false;
+ }
+
if (cli->sb_feat.rmapbt && cli->xi->rtname) {
fprintf(stderr,
_("rmapbt not supported with realtime devices\n"));
if (cli->dirblocksize)
cfg->dirblocksize = getnum(cli->dirblocksize, &nopts, N_SIZE);
- if (cli->dirblocklog)
- cfg->dirblocksize = 1 << cli->dirblocklog;
if (cfg->dirblocksize) {
if (cfg->dirblocksize < cfg->blocksize ||
int maxsz;
fprintf(stderr, _("illegal inode size %d\n"), cfg->inodesize);
- maxsz = MIN(cfg->blocksize / XFS_MIN_INODE_PERBLOCK,
+ maxsz = min(cfg->blocksize / XFS_MIN_INODE_PERBLOCK,
XFS_DINODE_MAX_SIZE);
if (XFS_DINODE_MIN_SIZE == maxsz)
fprintf(stderr,
struct cli_params *cli,
struct fs_topology *ft)
{
+ long long int big_dswidth;
int dsunit = 0;
int dswidth = 0;
int lsunit = 0;
dsw = cli->dsw;
/* data sunit/swidth options */
- if ((dsunit && !dswidth) || (!dsunit && dswidth)) {
+ if (cli_opt_set(&dopts, D_SUNIT) != cli_opt_set(&dopts, D_SWIDTH)) {
fprintf(stderr,
_("both data sunit and data swidth options must be specified\n"));
usage();
/* convert dsu/dsw to dsunit/dswidth and use them from now on */
if (dsu || dsw) {
- if ((dsu && !dsw) || (!dsu && dsw)) {
+ if (cli_opt_set(&dopts, D_SU) != cli_opt_set(&dopts, D_SW)) {
fprintf(stderr,
_("both data su and data sw options must be specified\n"));
usage();
}
dsunit = (int)BTOBBT(dsu);
- dswidth = dsunit * dsw;
+ big_dswidth = (long long int)dsunit * dsw;
+ if (big_dswidth > INT_MAX) {
+ fprintf(stderr,
+_("data stripe width (%lld) is too large of a multiple of the data stripe unit (%d)\n"),
+ big_dswidth, dsunit);
+ usage();
+ }
+ dswidth = big_dswidth;
}
- if (dsunit && (dswidth % dsunit != 0)) {
+ if ((dsunit && !dswidth) || (!dsunit && dswidth) ||
+ (dsunit && (dswidth % dsunit != 0))) {
fprintf(stderr,
_("data stripe width (%d) must be a multiple of the data stripe unit (%d)\n"),
dswidth, dsunit);
/* if no stripe config set, use the device default */
if (!dsunit) {
- dsunit = ft->dsunit;
- dswidth = ft->dswidth;
- use_dev = true;
+ /* Ignore nonsense from device. XXX add more validation */
+ if (ft->dsunit && ft->dswidth == 0) {
+ fprintf(stderr,
+_("%s: Volume reports stripe unit of %d bytes and stripe width of 0, ignoring.\n"),
+ progname, BBTOB(ft->dsunit));
+ ft->dsunit = 0;
+ ft->dswidth = 0;
+ } else {
+ dsunit = ft->dsunit;
+ dswidth = ft->dswidth;
+ use_dev = true;
+ }
} else {
- /* check and warn is alignment is sub-optimal */
+ /* check and warn if user-specified alignment is sub-optimal */
if (ft->dsunit && ft->dsunit != dsunit) {
fprintf(stderr,
_("%s: Specified data stripe unit %d is not the same as the volume stripe unit %d\n"),
}
static void
-print_mkfs_cfg(
+open_devices(
struct mkfs_params *cfg,
- char *dfile,
- char *logfile,
- char *rtfile)
+ struct libxfs_xinit *xi,
+ bool discard)
{
- struct sb_feat_args *fp = &cfg->sb_feat;
+ uint64_t sector_mask;
+
+ /*
+ * Initialize. This will open the log and rt devices as well.
+ */
+ xi->setblksize = cfg->sectorsize;
+ if (!libxfs_init(xi))
+ usage();
+ if (!xi->ddev) {
+ fprintf(stderr, _("no device name given in argument list\n"));
+ usage();
+ }
+
+ /*
+ * 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. The same issue exists for larger
+ * sector sizes - we cannot write past the last sector.
+ *
+ * So, we reduce the size (in basic blocks) to a perfect
+ * multiple of the sector size, or 1024, whichever is larger.
+ */
+ sector_mask = (uint64_t)-1 << (max(cfg->sectorlog, 10) - BBSHIFT);
+ xi->dsize &= sector_mask;
+ xi->rtsize &= sector_mask;
+ xi->logBBsize &= (uint64_t)-1 << (max(cfg->lsectorlog, 10) - BBSHIFT);
+
+
+ if (!discard)
+ return;
+
+ if (!xi->disfile)
+ discard_blocks(xi->ddev, xi->dsize);
+ if (xi->rtdev && !xi->risfile)
+ discard_blocks(xi->rtdev, xi->rtsize);
+ if (xi->logdev && xi->logdev != xi->ddev && !xi->lisfile)
+ discard_blocks(xi->logdev, xi->logBBsize);
+}
- printf(_(
-"meta-data=%-22s isize=%-6d agcount=%lld, agsize=%lld blks\n"
-" =%-22s sectsz=%-5u attr=%u, projid32bit=%u\n"
-" =%-22s crc=%-8u finobt=%u, sparse=%u, rmapbt=%u, reflink=%u\n"
-"data =%-22s bsize=%-6u blocks=%llu, imaxpct=%u\n"
-" =%-22s sunit=%-6u swidth=%u blks\n"
-"naming =version %-14u bsize=%-6u ascii-ci=%d ftype=%d\n"
-"log =%-22s bsize=%-6d blocks=%lld, version=%d\n"
-" =%-22s sectsz=%-5u sunit=%d blks, lazy-count=%d\n"
-"realtime =%-22s extsz=%-6d blocks=%lld, rtextents=%lld\n"),
- dfile, cfg->inodesize, (long long)cfg->agcount,
- (long long)cfg->agsize,
- "", cfg->sectorsize, fp->attr_version, !fp->projid16bit,
- "", fp->crcs_enabled, fp->finobt, fp->spinodes, fp->rmapbt,
- fp->reflink,
- "", cfg->blocksize, (long long)cfg->dblocks, cfg->imaxpct,
- "", cfg->dsunit, cfg->dswidth,
- fp->dir_version, cfg->dirblocksize, fp->nci, fp->dirftype,
- logfile, cfg->blocksize, (long long)cfg->logblocks,
- fp->log_version,
- "", cfg->lsectorsize, cfg->lsunit, fp->lazy_sb_counters,
- rtfile, (int)cfg->rtextblocks << cfg->blocklog,
- (long long)cfg->rtblocks, (long long)cfg->rtextents);
+static void
+validate_datadev(
+ struct mkfs_params *cfg,
+ struct cli_params *cli)
+{
+ struct libxfs_xinit *xi = cli->xi;
+
+ if (!xi->dsize) {
+ /*
+ * if the device is a file, we can't validate the size here.
+ * Instead, the file will be truncated to the correct length
+ * later on. if it's not a file, we've got a dud device.
+ */
+ if (!xi->disfile) {
+ fprintf(stderr, _("can't get size of data subvolume\n"));
+ usage();
+ }
+ ASSERT(cfg->dblocks);
+ } else if (cfg->dblocks) {
+ /* check the size fits into the underlying device */
+ if (cfg->dblocks > DTOBT(xi->dsize, cfg->blocklog)) {
+ fprintf(stderr,
+_("size %s specified for data subvolume is too large, maximum is %lld blocks\n"),
+ cli->dsize,
+ (long long)DTOBT(xi->dsize, cfg->blocklog));
+ usage();
+ }
+ } else {
+ /* no user size, so use the full block device */
+ cfg->dblocks = DTOBT(xi->dsize, cfg->blocklog);
+ }
+
+ if (cfg->dblocks < XFS_MIN_DATA_BLOCKS) {
+ fprintf(stderr,
+_("size %lld of data subvolume is too small, minimum %d blocks\n"),
+ (long long)cfg->dblocks, XFS_MIN_DATA_BLOCKS);
+ usage();
+ }
+
+ if (xi->dbsize > cfg->sectorsize) {
+ fprintf(stderr, _(
+"Warning: the data subvolume sector size %u is less than the sector size \n\
+reported by the device (%u).\n"),
+ cfg->sectorsize, xi->dbsize);
+ }
}
/*
- * Format everything from the generated config into the superblock that
- * will be used to initialise the on-disk superblock. This is the in-memory
- * copy, so no need to care about endian swapping here.
+ * This is more complex than it needs to be because we still support volume
+ * based external logs. They are only discovered *after* the devices have been
+ * opened, hence the crazy "is this really an internal log" checks here.
*/
static void
-setup_superblock(
+validate_logdev(
struct mkfs_params *cfg,
- struct xfs_mount *mp,
- struct xfs_sb *sbp)
+ struct cli_params *cli,
+ char **devname)
{
- if (cfg->label)
- strncpy(sbp->sb_fname, cfg->label, sizeof(sbp->sb_fname));
+ struct libxfs_xinit *xi = cli->xi;
+
+ *devname = NULL;
+
+ /* check for volume log first */
+ if (cli->loginternal && xi->volname && xi->logdev) {
+ *devname = _("volume log");
+ cfg->loginternal = false;
+ } else
+ cfg->loginternal = cli->loginternal;
+
+ /* now run device checks */
+ if (cfg->loginternal) {
+ if (xi->logdev) {
+ fprintf(stderr,
+_("can't have both external and internal logs\n"));
+ usage();
+ }
+
+ /*
+ * if no sector size has been specified on the command line,
+ * use what has been configured and validated for the data
+ * device.
+ */
+ if (!cli->lsectorsize) {
+ cfg->lsectorsize = cfg->sectorsize;
+ cfg->lsectorlog = cfg->sectorlog;
+ }
+
+ if (cfg->sectorsize != cfg->lsectorsize) {
+ fprintf(stderr,
+_("data and log sector sizes must be equal for internal logs\n"));
+ usage();
+ }
+ if (cli->logsize && cfg->logblocks >= cfg->dblocks) {
+ fprintf(stderr,
+_("log size %lld too large for internal log\n"),
+ (long long)cfg->logblocks);
+ usage();
+ }
+ *devname = _("internal log");
+ return;
+ }
+
+ /* External/log subvolume checks */
+ if (xi->logname)
+ *devname = xi->logname;
+ if (!*devname || !xi->logdev) {
+ fprintf(stderr, _("no log subvolume or external log.\n"));
+ usage();
+ }
+
+ if (!cfg->logblocks) {
+ if (xi->logBBsize == 0) {
+ fprintf(stderr,
+_("unable to get size of the log subvolume.\n"));
+ usage();
+ }
+ cfg->logblocks = DTOBT(xi->logBBsize, cfg->blocklog);
+ } else if (cfg->logblocks > DTOBT(xi->logBBsize, cfg->blocklog)) {
+ fprintf(stderr,
+_("size %s specified for log subvolume is too large, maximum is %lld blocks\n"),
+ cli->logsize,
+ (long long)DTOBT(xi->logBBsize, cfg->blocklog));
+ usage();
+ }
+
+ if (xi->lbsize > cfg->lsectorsize) {
+ fprintf(stderr, _(
+"Warning: the log subvolume sector size %u is less than the sector size\n\
+reported by the device (%u).\n"),
+ cfg->lsectorsize, xi->lbsize);
+ }
+}
+
+static void
+validate_rtdev(
+ struct mkfs_params *cfg,
+ struct cli_params *cli,
+ char **devname)
+{
+ struct libxfs_xinit *xi = cli->xi;
+
+ *devname = NULL;
+
+ if (!xi->rtdev) {
+ if (cli->rtsize) {
+ fprintf(stderr,
+_("size specified for non-existent rt subvolume\n"));
+ usage();
+ }
+
+ *devname = _("none");
+ cfg->rtblocks = 0;
+ cfg->rtextents = 0;
+ cfg->rtbmblocks = 0;
+ return;
+ }
+ if (!xi->rtsize) {
+ fprintf(stderr, _("Invalid zero length rt subvolume found\n"));
+ usage();
+ }
+
+ /* volume rtdev */
+ if (xi->volname)
+ *devname = _("volume rt");
+ else
+ *devname = xi->rtname;
+
+ if (cli->rtsize) {
+ if (cfg->rtblocks > DTOBT(xi->rtsize, cfg->blocklog)) {
+ fprintf(stderr,
+_("size %s specified for rt subvolume is too large, maxi->um is %lld blocks\n"),
+ cli->rtsize,
+ (long long)DTOBT(xi->rtsize, cfg->blocklog));
+ usage();
+ }
+ if (xi->rtbsize > cfg->sectorsize) {
+ fprintf(stderr, _(
+"Warning: the realtime subvolume sector size %u is less than the sector size\n\
+reported by the device (%u).\n"),
+ cfg->sectorsize, xi->rtbsize);
+ }
+ } else {
+ /* grab volume size */
+ cfg->rtblocks = DTOBT(xi->rtsize, cfg->blocklog);
+ }
+
+ cfg->rtextents = cfg->rtblocks / cfg->rtextblocks;
+ cfg->rtbmblocks = (xfs_extlen_t)howmany(cfg->rtextents,
+ NBBY * cfg->blocksize);
+}
+
+static void
+calculate_initial_ag_geometry(
+ struct mkfs_params *cfg,
+ struct cli_params *cli)
+{
+ if (cli->agsize) { /* User-specified AG size */
+ cfg->agsize = getnum(cli->agsize, &dopts, D_AGSIZE);
+
+ /*
+ * Check specified agsize is a multiple of blocksize.
+ */
+ if (cfg->agsize % cfg->blocksize) {
+ fprintf(stderr,
+_("agsize (%s) not a multiple of fs blk size (%d)\n"),
+ cli->agsize, cfg->blocksize);
+ usage();
+ }
+ cfg->agsize /= cfg->blocksize;
+ cfg->agcount = cfg->dblocks / cfg->agsize +
+ (cfg->dblocks % cfg->agsize != 0);
+
+ } else if (cli->agcount) { /* User-specified AG count */
+ cfg->agcount = cli->agcount;
+ cfg->agsize = cfg->dblocks / cfg->agcount +
+ (cfg->dblocks % cfg->agcount != 0);
+ } else {
+ calc_default_ag_geometry(cfg->blocklog, cfg->dblocks,
+ cfg->dsunit, &cfg->agsize,
+ &cfg->agcount);
+ }
+}
+
+/*
+ * Align the AG size to stripe geometry. If this fails and we are using
+ * discovered stripe geometry, tell the caller to clear the stripe geometry.
+ * Otherwise, set the aligned geometry (valid or invalid!) so that the
+ * validation call will fail and exit.
+ */
+static void
+align_ag_geometry(
+ struct mkfs_params *cfg)
+{
+ uint64_t tmp_agsize;
+ int dsunit = cfg->dsunit;
+
+ if (!dsunit)
+ goto validate;
+
+ /*
+ * agsize is not a multiple of dsunit
+ */
+ if ((cfg->agsize % dsunit) != 0) {
+ /*
+ * Round up to stripe unit boundary. Also make sure
+ * that agsize is still larger than
+ * XFS_AG_MIN_BLOCKS(blocklog)
+ */
+ tmp_agsize = ((cfg->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(cfg->blocklog))
+ tmp_agsize = (cfg->agsize / dsunit) * dsunit;
+
+ if (tmp_agsize < XFS_AG_MIN_BLOCKS(cfg->blocklog) &&
+ tmp_agsize > XFS_AG_MAX_BLOCKS(cfg->blocklog)) {
+
+ /*
+ * If the AG size is invalid and we are using device
+ * probed stripe alignment, just clear the alignment
+ * and continue on.
+ */
+ if (!cli_opt_set(&dopts, D_SUNIT) &&
+ !cli_opt_set(&dopts, D_SU)) {
+ cfg->dsunit = 0;
+ cfg->dswidth = 0;
+ goto validate;
+ }
+ /*
+ * set the agsize to the invalid value so the following
+ * validation of the ag will fail and print a nice error
+ * and exit.
+ */
+ cfg->agsize = tmp_agsize;
+ goto validate;
+ }
+
+ /* update geometry to be stripe unit aligned */
+ cfg->agsize = tmp_agsize;
+ if (!cli_opt_set(&dopts, D_AGCOUNT))
+ cfg->agcount = cfg->dblocks / cfg->agsize +
+ (cfg->dblocks % cfg->agsize != 0);
+ if (cli_opt_set(&dopts, D_AGSIZE))
+ fprintf(stderr,
+_("agsize rounded to %lld, sunit = %d\n"),
+ (long long)cfg->agsize, dsunit);
+ }
+
+ if ((cfg->agsize % cfg->dswidth) == 0 &&
+ cfg->dswidth != cfg->dsunit &&
+ cfg->agcount > 1) {
+
+ if (cli_opt_set(&dopts, D_AGCOUNT) ||
+ cli_opt_set(&dopts, D_AGSIZE)) {
+ 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, run mkfs with\n\
+an AG size that is one stripe unit smaller or larger, for example %llu.\n"),
+ (unsigned long long)cfg->agsize - dsunit);
+ goto validate;
+ }
+
+ /*
+ * 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 does not happen.
+ */
+ tmp_agsize = cfg->agsize - dsunit;
+ if (tmp_agsize < XFS_AG_MIN_BLOCKS(cfg->blocklog)) {
+ tmp_agsize = cfg->agsize + dsunit;
+ if (cfg->dblocks < cfg->agsize) {
+ /* oh well, nothing to do */
+ tmp_agsize = cfg->agsize;
+ }
+ }
+
+ cfg->agsize = tmp_agsize;
+ cfg->agcount = cfg->dblocks / cfg->agsize +
+ (cfg->dblocks % cfg->agsize != 0);
+ }
+
+validate:
+ /*
+ * If the last AG is too small, reduce the filesystem size
+ * and drop the blocks.
+ */
+ if (cfg->dblocks % cfg->agsize != 0 &&
+ (cfg->dblocks % cfg->agsize < XFS_AG_MIN_BLOCKS(cfg->blocklog))) {
+ ASSERT(!cli_opt_set(&dopts, D_AGCOUNT));
+ cfg->dblocks = (xfs_rfsblock_t)((cfg->agcount - 1) * cfg->agsize);
+ cfg->agcount--;
+ ASSERT(cfg->agcount != 0);
+ }
+
+ validate_ag_geometry(cfg->blocklog, cfg->dblocks,
+ cfg->agsize, cfg->agcount);
+}
+
+static void
+calculate_imaxpct(
+ struct mkfs_params *cfg,
+ struct cli_params *cli)
+{
+ cfg->imaxpct = cli->imaxpct;
+ if (cfg->imaxpct)
+ return;
+
+ /*
+ * This returns the % of the disk space that is used for
+ * inodes, it changes relatively to the FS size:
+ * - over 50 TB, use 1%,
+ * - 1TB - 50 TB, use 5%,
+ * - under 1 TB, use XFS_DFL_IMAXIMUM_PCT (25%).
+ */
+
+ if (cfg->dblocks < TERABYTES(1, cfg->blocklog))
+ cfg->imaxpct = XFS_DFL_IMAXIMUM_PCT;
+ else if (cfg->dblocks < TERABYTES(50, cfg->blocklog))
+ cfg->imaxpct = 5;
+ else
+ cfg->imaxpct = 1;
+}
+
+/*
+ * Set up the initial state of the superblock so we can start using the
+ * libxfs geometry macros.
+ */
+static void
+sb_set_features(
+ struct mkfs_params *cfg,
+ struct xfs_sb *sbp)
+{
+ struct sb_feat_args *fp = &cfg->sb_feat;
+
+ sbp->sb_versionnum = XFS_DFL_SB_VERSION_BITS;
+ if (fp->crcs_enabled)
+ sbp->sb_versionnum |= XFS_SB_VERSION_5;
+ else
+ sbp->sb_versionnum |= XFS_SB_VERSION_4;
+
+ if (fp->inode_align) {
+ int cluster_size = XFS_INODE_BIG_CLUSTER_SIZE;
+
+ sbp->sb_versionnum |= XFS_SB_VERSION_ALIGNBIT;
+ if (cfg->sb_feat.crcs_enabled)
+ cluster_size *= cfg->inodesize / XFS_DINODE_MIN_SIZE;
+ sbp->sb_inoalignmt = cluster_size >> cfg->blocklog;
+ } else
+ sbp->sb_inoalignmt = 0;
+
+ if (cfg->dsunit)
+ sbp->sb_versionnum |= XFS_SB_VERSION_DALIGNBIT;
+ if (fp->log_version == 2)
+ sbp->sb_versionnum |= XFS_SB_VERSION_LOGV2BIT;
+ if (fp->attr_version == 1)
+ sbp->sb_versionnum |= XFS_SB_VERSION_ATTRBIT;
+ if (fp->nci)
+ sbp->sb_versionnum |= XFS_SB_VERSION_BORGBIT;
+
+ if (cfg->sectorsize > BBSIZE || cfg->lsectorsize > BBSIZE) {
+ sbp->sb_versionnum |= XFS_SB_VERSION_SECTORBIT;
+ sbp->sb_logsectlog = (uint8_t)cfg->lsectorlog;
+ sbp->sb_logsectsize = (uint16_t)cfg->lsectorsize;
+ } else {
+ sbp->sb_logsectlog = 0;
+ sbp->sb_logsectsize = 0;
+ }
+
+ sbp->sb_features2 = 0;
+ if (fp->lazy_sb_counters)
+ sbp->sb_features2 |= XFS_SB_VERSION2_LAZYSBCOUNTBIT;
+ if (fp->projid32bit)
+ sbp->sb_features2 |= XFS_SB_VERSION2_PROJID32BIT;
+ if (fp->parent_pointers)
+ sbp->sb_features2 |= XFS_SB_VERSION2_PARENTBIT;
+ if (fp->crcs_enabled)
+ sbp->sb_features2 |= XFS_SB_VERSION2_CRCBIT;
+ if (fp->attr_version == 2)
+ sbp->sb_features2 |= XFS_SB_VERSION2_ATTR2BIT;
+
+ /* v5 superblocks have their own feature bit for dirftype */
+ if (fp->dirftype && !fp->crcs_enabled)
+ sbp->sb_features2 |= XFS_SB_VERSION2_FTYPE;
+
+ /* update whether extended features are in use */
+ if (sbp->sb_features2 != 0)
+ sbp->sb_versionnum |= XFS_SB_VERSION_MOREBITSBIT;
+
+ /*
+ * Due to a structure alignment issue, sb_features2 ended up in one
+ * of two locations, the second "incorrect" location represented by
+ * the sb_bad_features2 field. To avoid older kernels mounting
+ * filesystems they shouldn't, set both field to the same value.
+ */
+ sbp->sb_bad_features2 = sbp->sb_features2;
+
+ if (!fp->crcs_enabled)
+ return;
+
+ /* default features for v5 filesystems */
+ sbp->sb_features_compat = 0;
+ sbp->sb_features_ro_compat = 0;
+ sbp->sb_features_incompat = XFS_SB_FEAT_INCOMPAT_FTYPE;
+ sbp->sb_features_log_incompat = 0;
+
+ 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.
+ * First, sparse chunk alignment must match the cluster size. Second,
+ * full chunk alignment must match the inode chunk size.
+ *
+ * Copy the already calculated/scaled inoalignmt to spino_align and
+ * update the former to the full inode chunk size.
+ */
+ if (fp->spinodes) {
+ sbp->sb_spino_align = sbp->sb_inoalignmt;
+ sbp->sb_inoalignmt = XFS_INODES_PER_CHUNK *
+ cfg->inodesize >> cfg->blocklog;
+ sbp->sb_features_incompat |= XFS_SB_FEAT_INCOMPAT_SPINODES;
+ }
+
+}
+
+/*
+ * Make sure that the log size is a multiple of the stripe unit
+ */
+static void
+align_log_size(
+ struct mkfs_params *cfg,
+ int sunit)
+{
+ uint64_t tmp_logblocks;
+
+ /* nothing to do if it's already aligned. */
+ if ((cfg->logblocks % sunit) == 0)
+ return;
+
+ if (cli_opt_set(&lopts, L_SIZE)) {
+ fprintf(stderr,
+_("log size %lld is not a multiple of the log stripe unit %d\n"),
+ (long long) cfg->logblocks, sunit);
+ usage();
+ }
+
+ tmp_logblocks = ((cfg->logblocks + (sunit - 1)) / sunit) * sunit;
+
+ /* If the log is too large, round down instead of round up */
+ if ((tmp_logblocks > XFS_MAX_LOG_BLOCKS) ||
+ ((tmp_logblocks << cfg->blocklog) > XFS_MAX_LOG_BYTES)) {
+ tmp_logblocks = (cfg->logblocks / sunit) * sunit;
+ }
+ cfg->logblocks = tmp_logblocks;
+}
+
+/*
+ * Make sure that the internal log is correctly aligned to the specified
+ * stripe unit.
+ */
+static void
+align_internal_log(
+ struct mkfs_params *cfg,
+ struct xfs_mount *mp,
+ int sunit)
+{
+ /* round up log start if necessary */
+ if ((cfg->logstart % sunit) != 0)
+ cfg->logstart = ((cfg->logstart + (sunit - 1)) / sunit) * sunit;
+
+ /* round up/down the log size now */
+ align_log_size(cfg, sunit);
+
+ /* check the aligned log still fits in an AG. */
+ if (cfg->logblocks > cfg->agsize - XFS_FSB_TO_AGBNO(mp, cfg->logstart)) {
+ fprintf(stderr,
+_("Due to stripe alignment, the internal log size (%lld) is too large.\n"
+ "Must fit within an allocation group.\n"),
+ (long long) cfg->logblocks);
+ usage();
+ }
+}
+
+void
+validate_log_size(uint64_t logblocks, int blocklog, int min_logblocks)
+{
+ if (logblocks < min_logblocks) {
+ fprintf(stderr,
+ _("log size %lld blocks too small, minimum size is %d blocks\n"),
+ (long long)logblocks, min_logblocks);
+ usage();
+ }
+ if (logblocks > XFS_MAX_LOG_BLOCKS) {
+ fprintf(stderr,
+ _("log size %lld blocks too large, maximum size is %lld blocks\n"),
+ (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 %lld bytes\n"),
+ (long long)(logblocks << blocklog), XFS_MAX_LOG_BYTES);
+ usage();
+ }
+}
+
+static void
+calculate_log_size(
+ struct mkfs_params *cfg,
+ struct cli_params *cli,
+ struct xfs_mount *mp)
+{
+ struct xfs_sb *sbp = &mp->m_sb;
+ int min_logblocks;
+ struct xfs_mount mount;
+
+ /* we need a temporary mount to calculate the minimum log size. */
+ memset(&mount, 0, sizeof(mount));
+ mount.m_sb = *sbp;
+ libxfs_mount(&mount, &mp->m_sb, 0, 0, 0, 0);
+ min_logblocks = libxfs_log_calc_minimum_size(&mount);
+ libxfs_umount(&mount);
+
+ ASSERT(min_logblocks);
+ min_logblocks = max(XFS_MIN_LOG_BLOCKS, min_logblocks);
+
+ /* if we have lots of blocks, check against XFS_MIN_LOG_BYTES, too */
+ if (!cli->logsize &&
+ cfg->dblocks >= (1024*1024*1024) >> cfg->blocklog)
+ min_logblocks = max(min_logblocks,
+ XFS_MIN_LOG_BYTES >> cfg->blocklog);
+
+ /*
+ * external logs will have a device and size by now, so all we have
+ * to do is validate it against minimum size and align it.
+ */
+ if (!cfg->loginternal) {
+ if (min_logblocks > cfg->logblocks) {
+ fprintf(stderr,
+_("external log device %lld too small, must be at least %lld blocks\n"),
+ (long long)cfg->logblocks,
+ (long long)min_logblocks);
+ usage();
+ }
+ cfg->logstart = 0;
+ cfg->logagno = 0;
+ if (cfg->lsunit)
+ align_log_size(cfg, cfg->lsunit);
+
+ validate_log_size(cfg->logblocks, cfg->blocklog, min_logblocks);
+ return;
+ }
+
+ /* internal log - if no size specified, calculate automatically */
+ if (!cfg->logblocks) {
+ if (cfg->dblocks < GIGABYTES(1, cfg->blocklog)) {
+ /* tiny filesystems get minimum sized logs. */
+ cfg->logblocks = min_logblocks;
+ } else if (cfg->dblocks < GIGABYTES(16, cfg->blocklog)) {
+
+ /*
+ * For small filesystems, we want to use the
+ * XFS_MIN_LOG_BYTES for filesystems smaller than 16G if
+ * at all possible, ramping up to 128MB at 256GB.
+ */
+ cfg->logblocks = min(XFS_MIN_LOG_BYTES >> cfg->blocklog,
+ min_logblocks * XFS_DFL_LOG_FACTOR);
+ } else {
+ /*
+ * With a 2GB max log size, default to maximum size
+ * at 4TB. This keeps the same ratio from the older
+ * max log size of 128M at 256GB fs size. IOWs,
+ * the ratio of fs size to log size is 2048:1.
+ */
+ cfg->logblocks = (cfg->dblocks << cfg->blocklog) / 2048;
+ cfg->logblocks = cfg->logblocks >> cfg->blocklog;
+ }
+
+ /* Ensure the chosen size meets minimum log size requirements */
+ cfg->logblocks = max(min_logblocks, cfg->logblocks);
+
+ /*
+ * Make sure the log fits wholly within an AG
+ *
+ * XXX: If agf->freeblks ends up as 0 because the log uses all
+ * the free space, it causes the kernel all sorts of problems
+ * with per-ag reservations. Right now just back it off one
+ * block, but there's a whole can of worms here that needs to be
+ * opened to decide what is the valid maximum size of a log in
+ * an AG.
+ */
+ cfg->logblocks = min(cfg->logblocks,
+ libxfs_alloc_ag_max_usable(mp) - 1);
+
+ /* and now clamp the size to the maximum supported size */
+ cfg->logblocks = min(cfg->logblocks, XFS_MAX_LOG_BLOCKS);
+ if ((cfg->logblocks << cfg->blocklog) > XFS_MAX_LOG_BYTES)
+ cfg->logblocks = XFS_MAX_LOG_BYTES >> cfg->blocklog;
+
+ validate_log_size(cfg->logblocks, cfg->blocklog, min_logblocks);
+ }
+
+ if (cfg->logblocks > sbp->sb_agblocks - libxfs_prealloc_blocks(mp)) {
+ fprintf(stderr,
+_("internal log size %lld too large, must fit in allocation group\n"),
+ (long long)cfg->logblocks);
+ usage();
+ }
+
+ if (cli_opt_set(&lopts, L_AGNUM)) {
+ if (cli->logagno >= sbp->sb_agcount) {
+ fprintf(stderr,
+_("log ag number %lld too large, must be less than %lld\n"),
+ (long long)cli->logagno,
+ (long long)sbp->sb_agcount);
+ usage();
+ }
+ cfg->logagno = cli->logagno;
+ } else
+ cfg->logagno = (xfs_agnumber_t)(sbp->sb_agcount / 2);
+
+ cfg->logstart = XFS_AGB_TO_FSB(mp, cfg->logagno,
+ libxfs_prealloc_blocks(mp));
+
+ /*
+ * Align the logstart at stripe unit boundary.
+ */
+ if (cfg->lsunit) {
+ align_internal_log(cfg, mp, cfg->lsunit);
+ } else if (cfg->dsunit) {
+ align_internal_log(cfg, mp, cfg->dsunit);
+ }
+ validate_log_size(cfg->logblocks, cfg->blocklog, min_logblocks);
+}
+
+/*
+ * Set up superblock with the minimum parameters required for
+ * the libxfs macros needed by the log sizing code to run successfully.
+ * This includes a minimum log size calculation, so we need everything
+ * that goes into that calculation to be setup here including feature
+ * flags.
+ */
+static void
+start_superblock_setup(
+ struct mkfs_params *cfg,
+ struct xfs_mount *mp,
+ struct xfs_sb *sbp)
+{
+ sbp->sb_magicnum = XFS_SB_MAGIC;
+ sbp->sb_sectsize = (uint16_t)cfg->sectorsize;
+ sbp->sb_sectlog = (uint8_t)cfg->sectorlog;
+ sbp->sb_blocksize = cfg->blocksize;
+ sbp->sb_blocklog = (uint8_t)cfg->blocklog;
+
+ sbp->sb_agblocks = (xfs_agblock_t)cfg->agsize;
+ sbp->sb_agblklog = (uint8_t)log2_roundup(cfg->agsize);
+ sbp->sb_agcount = (xfs_agnumber_t)cfg->agcount;
+
+ sbp->sb_inodesize = (uint16_t)cfg->inodesize;
+ sbp->sb_inodelog = (uint8_t)cfg->inodelog;
+ sbp->sb_inopblock = (uint16_t)(cfg->blocksize / cfg->inodesize);
+ sbp->sb_inopblog = (uint8_t)(cfg->blocklog - cfg->inodelog);
- sbp->sb_magicnum = XFS_SB_MAGIC;
- sbp->sb_blocksize = cfg->blocksize;
- sbp->sb_dblocks = cfg->dblocks;
- sbp->sb_rblocks = cfg->rtblocks;
- sbp->sb_rextents = cfg->rtextents;
- platform_uuid_copy(&sbp->sb_uuid, &cfg->uuid);
- /* Only in memory; libxfs expects this as if read from disk */
- platform_uuid_copy(&sbp->sb_meta_uuid, &cfg->uuid);
- sbp->sb_logstart = cfg->logstart;
- sbp->sb_rootino = sbp->sb_rbmino = sbp->sb_rsumino = NULLFSINO;
- sbp->sb_rextsize = cfg->rtextblocks;
- sbp->sb_agcount = (xfs_agnumber_t)cfg->agcount;
- sbp->sb_rbmblocks = cfg->rtbmblocks;
- sbp->sb_logblocks = (xfs_extlen_t)cfg->logblocks;
- sbp->sb_sectsize = (uint16_t)cfg->sectorsize;
- sbp->sb_inodesize = (uint16_t)cfg->inodesize;
- sbp->sb_inopblock = (uint16_t)(cfg->blocksize / cfg->inodesize);
- sbp->sb_sectlog = (uint8_t)cfg->sectorlog;
- sbp->sb_inodelog = (uint8_t)cfg->inodelog;
- sbp->sb_inopblog = (uint8_t)(cfg->blocklog - cfg->inodelog);
- sbp->sb_rextslog = (uint8_t)(cfg->rtextents ?
- libxfs_highbit32((unsigned int)cfg->rtextents) : 0);
- sbp->sb_inprogress = 1; /* mkfs is in progress */
- sbp->sb_imax_pct = cfg->imaxpct;
- sbp->sb_icount = 0;
- sbp->sb_ifree = 0;
- sbp->sb_fdblocks = cfg->dblocks -
- cfg->agcount * libxfs_prealloc_blocks(mp) -
- (cfg->loginternal ? cfg->logblocks : 0);
- sbp->sb_frextents = 0; /* will do a free later */
- sbp->sb_uquotino = sbp->sb_gquotino = sbp->sb_pquotino = 0;
- sbp->sb_qflags = 0;
- sbp->sb_unit = cfg->dsunit;
- sbp->sb_width = cfg->dswidth;
sbp->sb_dirblklog = cfg->dirblocklog - cfg->blocklog;
- /*
- * log stripe unit is stored in bytes on disk and cannot be zero
- * for v2 logs.
- */
- if (cfg->sb_feat.log_version == 2) {
- if (cfg->lsunit)
- sbp->sb_logsunit = XFS_FSB_TO_B(mp, cfg->lsunit);
- else
- sbp->sb_logsunit = 1;
- } else
- sbp->sb_logsunit = 0;
+ sb_set_features(cfg, sbp);
+
+ /*
+ * log stripe unit is stored in bytes on disk and cannot be zero
+ * for v2 logs.
+ */
+ if (cfg->sb_feat.log_version == 2) {
+ if (cfg->lsunit)
+ sbp->sb_logsunit = XFS_FSB_TO_B(mp, cfg->lsunit);
+ else
+ sbp->sb_logsunit = 1;
+ } else
+ sbp->sb_logsunit = 0;
+
+}
+
+static void
+initialise_mount(
+ struct mkfs_params *cfg,
+ struct xfs_mount *mp,
+ struct xfs_sb *sbp)
+{
+ /* Minimum needed for libxfs_prealloc_blocks() */
+ mp->m_blkbb_log = sbp->sb_blocklog - BBSHIFT;
+ mp->m_sectbb_log = sbp->sb_sectlog - BBSHIFT;
+}
+
+/*
+ * Format everything from the generated config into the superblock that
+ * will be used to initialise the on-disk superblock. This is the in-memory
+ * copy, so no need to care about endian swapping here.
+ */
+static void
+finish_superblock_setup(
+ struct mkfs_params *cfg,
+ struct xfs_mount *mp,
+ struct xfs_sb *sbp)
+{
+ if (cfg->label)
+ strncpy(sbp->sb_fname, cfg->label, sizeof(sbp->sb_fname));
- if (cfg->sb_feat.inode_align) {
- int cluster_size = XFS_INODE_BIG_CLUSTER_SIZE;
- if (cfg->sb_feat.crcs_enabled)
- cluster_size *= cfg->inodesize / XFS_DINODE_MIN_SIZE;
- sbp->sb_inoalignmt = cluster_size >> cfg->blocklog;
- } else
- sbp->sb_inoalignmt = 0;
+ sbp->sb_dblocks = cfg->dblocks;
+ sbp->sb_rblocks = cfg->rtblocks;
+ sbp->sb_rextents = cfg->rtextents;
+ platform_uuid_copy(&sbp->sb_uuid, &cfg->uuid);
+ /* Only in memory; libxfs expects this as if read from disk */
+ platform_uuid_copy(&sbp->sb_meta_uuid, &cfg->uuid);
+ sbp->sb_logstart = cfg->logstart;
+ sbp->sb_rootino = sbp->sb_rbmino = sbp->sb_rsumino = NULLFSINO;
+ sbp->sb_rextsize = cfg->rtextblocks;
+ sbp->sb_agcount = (xfs_agnumber_t)cfg->agcount;
+ sbp->sb_rbmblocks = cfg->rtbmblocks;
+ sbp->sb_logblocks = (xfs_extlen_t)cfg->logblocks;
+ sbp->sb_rextslog = (uint8_t)(cfg->rtextents ?
+ libxfs_highbit32((unsigned int)cfg->rtextents) : 0);
+ sbp->sb_inprogress = 1; /* mkfs is in progress */
+ sbp->sb_imax_pct = cfg->imaxpct;
+ sbp->sb_icount = 0;
+ sbp->sb_ifree = 0;
+ sbp->sb_fdblocks = cfg->dblocks -
+ cfg->agcount * libxfs_prealloc_blocks(mp) -
+ (cfg->loginternal ? cfg->logblocks : 0);
+ sbp->sb_frextents = 0; /* will do a free later */
+ sbp->sb_uquotino = sbp->sb_gquotino = sbp->sb_pquotino = 0;
+ sbp->sb_qflags = 0;
+ sbp->sb_unit = cfg->dsunit;
+ sbp->sb_width = cfg->dswidth;
- if (cfg->lsectorsize != BBSIZE || cfg->sectorsize != BBSIZE) {
- sbp->sb_logsectlog = (uint8_t)cfg->lsectorlog;
- sbp->sb_logsectsize = (uint16_t)cfg->lsectorsize;
- } else {
- sbp->sb_logsectlog = 0;
- sbp->sb_logsectsize = 0;
- }
}
/*
*/
buf = libxfs_getbuf(mp->m_ddev_targp, (xi->dsize - whack_blks),
whack_blks);
- memset(XFS_BUF_PTR(buf), 0, WHACK_SIZE);
+ memset(buf->b_addr, 0, WHACK_SIZE);
libxfs_writebuf(buf, LIBXFS_EXIT_ON_FAILURE);
libxfs_purgebuf(buf);
* ext[2,3] and reiserfs (64k) - and hopefully all else.
*/
buf = libxfs_getbuf(mp->m_ddev_targp, 0, whack_blks);
- memset(XFS_BUF_PTR(buf), 0, WHACK_SIZE);
+ memset(buf->b_addr, 0, WHACK_SIZE);
libxfs_writebuf(buf, LIBXFS_EXIT_ON_FAILURE);
libxfs_purgebuf(buf);
/* OK, now write the superblock... */
buf = libxfs_getbuf(mp->m_ddev_targp, XFS_SB_DADDR, XFS_FSS_TO_BB(mp, 1));
buf->b_ops = &xfs_sb_buf_ops;
- memset(XFS_BUF_PTR(buf), 0, cfg->sectorsize);
- libxfs_sb_to_disk((void *)XFS_BUF_PTR(buf), sbp);
+ memset(buf->b_addr, 0, cfg->sectorsize);
+ libxfs_sb_to_disk(buf->b_addr, sbp);
libxfs_writebuf(buf, LIBXFS_EXIT_ON_FAILURE);
libxfs_purgebuf(buf);
buf = libxfs_getbuf(mp->m_rtdev_targp,
XFS_FSB_TO_BB(mp, cfg->rtblocks - 1LL),
BTOBB(cfg->blocksize));
- memset(XFS_BUF_PTR(buf), 0, cfg->blocksize);
+ memset(buf->b_addr, 0, cfg->blocksize);
libxfs_writebuf(buf, LIBXFS_EXIT_ON_FAILURE);
libxfs_purgebuf(buf);
}
XFS_AG_DADDR(mp, agno, XFS_SB_DADDR),
XFS_FSS_TO_BB(mp, 1));
buf->b_ops = &xfs_sb_buf_ops;
- memset(XFS_BUF_PTR(buf), 0, cfg->sectorsize);
- libxfs_sb_to_disk((void *)XFS_BUF_PTR(buf), sbp);
+ memset(buf->b_addr, 0, cfg->sectorsize);
+ libxfs_sb_to_disk(buf->b_addr, sbp);
libxfs_writebuf(buf, LIBXFS_EXIT_ON_FAILURE);
/*
}
agf->agf_flfirst = 0;
- agf->agf_fllast = cpu_to_be32(XFS_AGFL_SIZE(mp) - 1);
+ agf->agf_fllast = cpu_to_be32(libxfs_agfl_size(mp) - 1);
agf->agf_flcount = 0;
agblocks = (xfs_agblock_t)(agsize - libxfs_prealloc_blocks(mp));
agf->agf_freeblks = cpu_to_be32(agblocks);
agfl->agfl_magicnum = cpu_to_be32(XFS_AGFL_MAGIC);
agfl->agfl_seqno = cpu_to_be32(agno);
platform_uuid_copy(&agfl->agfl_uuid, &sbp->sb_uuid);
- for (bucket = 0; bucket < XFS_AGFL_SIZE(mp); bucket++)
+ for (bucket = 0; bucket < libxfs_agfl_size(mp); bucket++)
agfl->agfl_bno[bucket] = cpu_to_be32(NULLAGBLOCK);
}
struct xfs_trans_res tres = {0};
int c;
- c = libxfs_trans_alloc(mp, &tres, worst_freelist, 0, 0, &tp);
+ c = -libxfs_trans_alloc(mp, &tres, worst_freelist, 0, 0, &tp);
if (c)
res_failed(c);
int argc,
char **argv)
{
- uint64_t agcount;
xfs_agnumber_t agno;
- uint64_t agsize;
- int blocklog;
xfs_buf_t *buf;
int c;
- int daflag;
- int dasize;
- xfs_rfsblock_t dblocks;
- char *dfile;
- int dirblocklog;
- int dirblocksize;
- char *dsize;
- int dsunit;
- int dswidth;
- int force_overwrite;
- struct fsxattr fsx;
- int imaxpct;
- int imflag;
- int inodelog;
- int inopblock;
- int isize;
- char *label = NULL;
- int laflag;
- int lalign;
- int ldflag;
- int liflag;
- xfs_agnumber_t logagno;
- xfs_rfsblock_t logblocks;
- char *logfile;
- int loginternal;
- char *logsize;
- xfs_fsblock_t logstart;
- int lvflag;
- int lsflag;
- int lsectorlog;
- int lsectorsize;
- int lsunit;
- int min_logblocks;
- xfs_mount_t *mp;
- xfs_mount_t mbuf;
- xfs_extlen_t nbmblocks;
- int nodsflag;
+ char *dfile = NULL;
+ char *logfile = NULL;
+ char *rtfile = NULL;
int dry_run = 0;
int discard = 1;
- char *protofile;
- char *protostring;
+ int force_overwrite = 0;
int quiet = 0;
- xfs_rfsblock_t rtblocks;
- xfs_extlen_t rtextblocks;
- xfs_rtblock_t rtextents;
- char *rtfile;
- char *rtsize;
- xfs_sb_t *sbp;
- int sectorlog;
- uint64_t sector_mask;
- uint64_t tmp_agsize;
- uuid_t uuid;
- int worst_freelist;
- libxfs_init_t xi;
- struct fs_topology ft;
- struct sb_feat_args sb_feat;
+ char *protofile = NULL;
+ char *protostring = NULL;
+ int worst_freelist = 0;
+
+ struct libxfs_xinit xi = {
+ .isdirect = LIBXFS_DIRECT,
+ .isreadonly = LIBXFS_EXCLUSIVELY,
+ };
+ struct xfs_mount mbuf = {};
+ struct xfs_mount *mp = &mbuf;
+ struct xfs_sb *sbp = &mp->m_sb;
+ struct fs_topology ft = {};
+ struct cli_params cli = {
+ .xi = &xi,
+ .loginternal = 1,
+ };
+ struct mkfs_params cfg = {};
+
/* build time defaults */
struct mkfs_default_params dft = {
- .source = "package build definitions",
+ .source = _("package build definitions"),
.sectorsize = XFS_MIN_SECTORSIZE,
.blocksize = 1 << XFS_DFL_BLOCKSIZE_LOG,
.sb_feat = {
.log_version = 2,
.attr_version = 2,
- .dir_version = XFS_DFL_DIR_VERSION,
- .inode_align = XFS_IFLAG_ALIGN,
+ .dir_version = 2,
+ .inode_align = true,
.nci = false,
.lazy_sb_counters = true,
- .projid16bit = false,
+ .projid32bit = true,
.crcs_enabled = true,
.dirftype = true,
.finobt = true,
- .spinodes = false,
+ .spinodes = true,
.rmapbt = false,
.reflink = false,
.parent_pointers = false,
.nortalign = false,
},
};
- struct cli_params cli = {
- .xi = &xi,
- };
- struct mkfs_params cfg = {};
platform_uuid_generate(&cli.uuid);
progname = basename(argv[0]);
* defaults. If a file exists in <package location>, read in the new
* default values and overwrite them in the &dft structure. This way the
* new defaults will apply before we parse the CLI, and the CLI will
- * still be able to override them. Emit a message to indicate where the
- * defaults being used came from.
+ * still be able to override them. When more than one source is
+ * implemented, emit a message to indicate where the defaults being
+ * used came from.
+ *
+ * printf(_("Default configuration sourced from %s\n"), dft.source);
*/
- printf(_("Default configuration sourced from %s\n"), dft.source);
/* copy new defaults into CLI parsing structure */
memcpy(&cli.sb_feat, &dft.sb_feat, sizeof(cli.sb_feat));
memcpy(&cli.fsx, &dft.fsx, sizeof(cli.fsx));
- /*
- * Initialise cli parameters that can be set to zero to an appropriate
- * value so we can tell if they have been set or or changed from the
- * default value.
- */
- cli.loginternal = 1; /* internal by default */
-
- agsize = daflag = dasize = dblocks = 0;
- imflag = 0;
- liflag = laflag = lsflag = ldflag = lvflag = 0;
- loginternal = 1;
- logagno = logblocks = rtblocks = rtextblocks = 0;
- imaxpct = inodelog = inopblock = isize = 0;
- dfile = logfile = rtfile = NULL;
- dsize = logsize = rtsize = protofile = NULL;
- dsunit = dswidth = lalign = lsunit = 0;
- nodsflag = 0;
- force_overwrite = 0;
- worst_freelist = 0;
- memset(&fsx, 0, sizeof(fsx));
-
- memset(&xi, 0, sizeof(xi));
- xi.isdirect = LIBXFS_DIRECT;
- xi.isreadonly = LIBXFS_EXCLUSIVELY;
-
while ((c = getopt(argc, argv, "b:d:i:l:L:m:n:KNp:qr:s:CfV")) != EOF) {
switch (c) {
case 'C':
force_overwrite = 1;
break;
case 'b':
- case 'n':
- case 's':
- parse_subopts(c, optarg, &cli);
- break;
case 'd':
- parse_subopts(c, optarg, &cli);
-
- /* temp don't break code */
- agcount = cli.agcount;
- if (cli_opt_set(&dopts, D_AGSIZE)) {
- agsize = getnum(cli.agsize, &dopts, D_AGSIZE);
- dasize = 1;
- }
- daflag = cli_opt_set(&dopts, D_AGCOUNT);
-
- fsx.fsx_xflags |= cli.fsx.fsx_xflags;
- fsx.fsx_projid = cli.fsx.fsx_projid;
- fsx.fsx_extsize = cli.fsx.fsx_extsize;
- /* end temp don't break code */
- break;
case 'i':
- parse_subopts(c, optarg, &cli);
-
- /* temp don't break code */
- imaxpct = cli.imaxpct;
- imflag = cli_opt_set(&iopts, I_MAXPCT);
- /* end temp don't break code */
- break;
case 'l':
+ case 'm':
+ case 'n':
+ case 'r':
+ case 's':
parse_subopts(c, optarg, &cli);
-
- /* temp don't break code */
- logagno = cli.logagno;
- loginternal = cli.loginternal;
- logfile = xi.logname;
- logsize = cli.logsize;
-
- laflag = cli_opt_set(&lopts, L_AGNUM);
- liflag = cli_opt_set(&lopts, L_INTERNAL);
- ldflag = cli_opt_set(&lopts, L_NAME) ||
- cli_opt_set(&lopts, L_DEV);
- lvflag = cli_opt_set(&lopts, L_VERSION);
- /* end temp don't break code */
break;
case 'L':
if (strlen(optarg) > sizeof(sbp->sb_fname))
illegal(optarg, "L");
- label = optarg;
- break;
- case 'm':
- parse_subopts(c, optarg, &cli);
-
- /* temp don't break code */
- platform_uuid_copy(&uuid, &cli.uuid);
- /* end temp don't break code */
+ cfg.label = optarg;
break;
case 'N':
dry_run = 1;
case 'K':
discard = 0;
break;
- case 'p':
- if (protofile)
- respec('p', NULL, 0);
- protofile = optarg;
- break;
- case 'q':
- quiet = 1;
- break;
- case 'r':
- parse_subopts(c, optarg, &cli);
-
- /* temp don't break code */
- rtsize = cli.rtsize;
- /* end temp don't break code */
- break;
- break;
- case 'V':
- printf(_("%s version %s\n"), progname, VERSION);
- exit(0);
- case '?':
- unknown(optopt, "");
- }
- }
- if (argc - optind > 1) {
- fprintf(stderr, _("extra arguments\n"));
- usage();
- } else if (argc - optind == 1) {
- dfile = xi.volname = getstr(argv[optind], &dopts, D_NAME);
- } else
- dfile = xi.dname;
-
- /* temp don't break code */
- sb_feat = cli.sb_feat;
- /* end temp don't break code */
-
- /*
- * Extract as much of the valid config as we can from the CLI input
- * before opening the libxfs devices.
- */
- validate_blocksize(&cfg, &cli, &dft);
- validate_sectorsize(&cfg, &cli, &dft, &ft, dfile, dry_run,
- force_overwrite);
- validate_log_sectorsize(&cfg, &cli, &dft);
- validate_sb_features(&cfg, &cli);
-
- /*
- * we've now completed basic validation of the features, sector and
- * block sizes, so from this point onwards we use the values found in
- * the cfg structure for them, not the command line structure.
- */
- validate_dirblocksize(&cfg, &cli);
- validate_inodesize(&cfg, &cli);
-
- /*
- * if the device size was specified convert it to a block count
- * now we have a valid block size. These will be set to zero if
- * nothing was specified, indicating we should use the full device.
- */
- cfg.dblocks = calc_dev_size(cli.dsize, &cfg, &dopts, D_SIZE, "data");
- cfg.logblocks = calc_dev_size(cli.logsize, &cfg, &lopts, L_SIZE, "log");
- cfg.rtblocks = calc_dev_size(cli.rtsize, &cfg, &ropts, R_SIZE, "rt");
-
- validate_rtextsize(&cfg, &cli, &ft);
- calc_stripe_factors(&cfg, &cli, &ft);
-
- /* temp don't break code */
- sectorsize = cfg.sectorsize;
- sectorlog = cfg.sectorlog;
- blocksize = cfg.blocksize;
- blocklog = cfg.blocklog;
- lsectorsize = cfg.lsectorsize;
- lsectorlog = cfg.lsectorlog;
- platform_uuid_copy(&uuid, &cfg.uuid);
- sb_feat = cfg.sb_feat;
- dirblocksize = cfg.dirblocksize;
- dirblocklog = cfg.dirblocklog;
- isize = cfg.inodesize;
- inodelog = cfg.inodelog;
- inopblock = cfg.inopblock;
- dblocks = cfg.dblocks;
- logblocks = cfg.logblocks;
- rtblocks = cfg.rtblocks;
- rtextblocks = cfg.rtextblocks;
- dsunit = cfg.dsunit;
- dswidth = cfg.dswidth;
- lsunit = cfg.lsunit;
- nodsflag = cfg.sb_feat.nodalign;
- /* end temp don't break code */
-
-
- xi.setblksize = sectorsize;
-
- /*
- * Initialize. This will open the log and rt devices as well.
- */
- if (!libxfs_init(&xi))
- usage();
- if (!xi.ddev) {
- fprintf(stderr, _("no device name given in argument list\n"));
- usage();
- }
-
- /*
- * 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. The same issue exists for larger
- * sector sizes - we cannot write past the last sector.
- *
- * So, we reduce the size (in basic blocks) to a perfect
- * multiple of the sector size, or 1024, whichever is larger.
- */
-
- sector_mask = (uint64_t)-1 << (MAX(sectorlog, 10) - BBSHIFT);
- xi.dsize &= sector_mask;
- xi.rtsize &= sector_mask;
- xi.logBBsize &= (uint64_t)-1 << (MAX(lsectorlog, 10) - BBSHIFT);
-
-
- /* don't do discards on print-only runs or on files */
- if (discard && !dry_run) {
- if (!xi.disfile)
- discard_blocks(xi.ddev, xi.dsize);
- if (xi.rtdev && !xi.risfile)
- discard_blocks(xi.rtdev, xi.rtsize);
- if (xi.logdev && xi.logdev != xi.ddev && !xi.lisfile)
- discard_blocks(xi.logdev, xi.logBBsize);
- }
-
- if (!liflag && !ldflag)
- loginternal = xi.logdev == 0;
- if (xi.logname)
- logfile = xi.logname;
- else if (loginternal)
- logfile = _("internal log");
- else if (xi.volname && xi.logdev)
- logfile = _("volume log");
- else if (!ldflag) {
- fprintf(stderr, _("no log subvolume or internal log\n"));
- usage();
- }
- if (xi.rtname)
- rtfile = xi.rtname;
- else
- if (xi.volname && xi.rtdev)
- rtfile = _("volume rt");
- else if (!xi.rtdev)
- rtfile = _("none");
- if (dsize && xi.dsize > 0 && dblocks > DTOBT(xi.dsize, blocklog)) {
- fprintf(stderr,
- _("size %s specified for data subvolume is too large, "
- "maximum is %lld blocks\n"),
- dsize, (long long)DTOBT(xi.dsize, blocklog));
- usage();
- } else if (!dsize && xi.dsize > 0)
- dblocks = DTOBT(xi.dsize, blocklog);
- else if (!dsize) {
- fprintf(stderr, _("can't get size of data subvolume\n"));
- usage();
- }
- if (dblocks < XFS_MIN_DATA_BLOCKS) {
- fprintf(stderr,
- _("size %lld of data subvolume is too small, minimum %d blocks\n"),
- (long long)dblocks, XFS_MIN_DATA_BLOCKS);
- usage();
- }
-
- if (loginternal && xi.logdev) {
- fprintf(stderr,
- _("can't have both external and internal logs\n"));
- usage();
- } else if (loginternal && sectorsize != lsectorsize) {
- fprintf(stderr,
- _("data and log sector sizes must be equal for internal logs\n"));
- usage();
- }
-
- if (xi.dbsize > sectorsize) {
- fprintf(stderr, _(
-"Warning: the data subvolume sector size %u is less than the sector size \n\
-reported by the device (%u).\n"),
- sectorsize, xi.dbsize);
- }
- if (!loginternal && xi.lbsize > lsectorsize) {
- fprintf(stderr, _(
-"Warning: the log subvolume sector size %u is less than the sector size\n\
-reported by the device (%u).\n"),
- lsectorsize, xi.lbsize);
- }
- if (rtsize && xi.rtsize > 0 && xi.rtbsize > sectorsize) {
- fprintf(stderr, _(
-"Warning: the realtime subvolume sector size %u is less than the sector size\n\
-reported by the device (%u).\n"),
- sectorsize, xi.rtbsize);
- }
-
- if (rtsize && xi.rtsize > 0 && rtblocks > DTOBT(xi.rtsize, blocklog)) {
- fprintf(stderr,
- _("size %s specified for rt subvolume is too large, "
- "maximum is %lld blocks\n"),
- rtsize, (long long)DTOBT(xi.rtsize, blocklog));
- usage();
- } else if (!rtsize && xi.rtsize > 0)
- rtblocks = DTOBT(xi.rtsize, blocklog);
- else if (rtsize && !xi.rtdev) {
- fprintf(stderr,
- _("size specified for non-existent rt subvolume\n"));
- usage();
- }
- if (xi.rtdev) {
- rtextents = rtblocks / rtextblocks;
- nbmblocks = (xfs_extlen_t)howmany(rtextents, NBBY * blocksize);
- } else {
- rtextents = rtblocks = 0;
- nbmblocks = 0;
- }
-
- if (dasize) { /* User-specified AG size */
- /*
- * Check specified agsize is a multiple of blocksize.
- */
- if (agsize % blocksize) {
- fprintf(stderr,
- _("agsize (%lld) not a multiple of fs blk size (%d)\n"),
- (long long)agsize, blocksize);
- usage();
- }
- agsize /= blocksize;
- agcount = dblocks / agsize + (dblocks % agsize != 0);
-
- } else if (daflag) { /* User-specified AG count */
- agsize = dblocks / agcount + (dblocks % agcount != 0);
- } else {
- calc_default_ag_geometry(blocklog, dblocks,
- dsunit | dswidth, &agsize, &agcount);
- }
-
- /*
- * If dsunit is a multiple of fs blocksize, then check that is a
- * multiple of the agsize too
- */
- if (dsunit && !(BBTOB(dsunit) % blocksize) &&
- dswidth && !(BBTOB(dswidth) % blocksize)) {
-
- /* convert from 512 byte blocks to fs blocksize */
- dsunit = DTOBT(dsunit, blocklog);
- dswidth = DTOBT(dswidth, blocklog);
-
- /*
- * agsize is not a multiple of dsunit
- */
- if ((agsize % dsunit) != 0) {
- /*
- * 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))) {
- agsize = tmp_agsize;
- if (!daflag)
- agcount = dblocks/agsize +
- (dblocks % agsize != 0);
- if (dasize)
- fprintf(stderr,
- _("agsize rounded to %lld, swidth = %d\n"),
- (long long)agsize, dswidth);
- } else {
- if (nodsflag) {
- dsunit = dswidth = 0;
- } else {
- /*
- * agsize is out of bounds, this will
- * print nice details & exit.
- */
- validate_ag_geometry(blocklog, dblocks,
- agsize, agcount);
- exit(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
- * does not happen.
- */
- tmp_agsize = agsize - dsunit;
- if (tmp_agsize < XFS_AG_MIN_BLOCKS(blocklog)) {
- tmp_agsize = agsize + dsunit;
- if (dblocks < agsize) {
- /* oh well, nothing to do */
- tmp_agsize = agsize;
- }
- }
- 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, run mkfs with\n\
-an AG size that is one stripe unit smaller, for example %llu.\n"),
- (unsigned long long)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_rfsblock_t)((agcount - 1) * agsize);
- agcount--;
- ASSERT(agcount != 0);
- }
- }
- }
- } else {
- if (nodsflag)
- dsunit = dswidth = 0;
- else {
- fprintf(stderr,
- _("%s: Stripe unit(%d) or stripe width(%d) is "
- "not a multiple of the block size(%d)\n"),
- progname, BBTOB(dsunit), BBTOB(dswidth),
- blocksize);
- exit(1);
+ case 'p':
+ if (protofile)
+ respec('p', NULL, 0);
+ protofile = optarg;
+ break;
+ case 'q':
+ quiet = 1;
+ break;
+ case 'V':
+ printf(_("%s version %s\n"), progname, VERSION);
+ exit(0);
+ case '?':
+ unknown(optopt, "");
}
}
+ if (argc - optind > 1) {
+ fprintf(stderr, _("extra arguments\n"));
+ usage();
+ } else if (argc - optind == 1) {
+ dfile = xi.volname = getstr(argv[optind], &dopts, D_NAME);
+ } else
+ dfile = xi.dname;
+
+ protostring = setup_proto(protofile);
/*
- * If the last AG is too small, reduce the filesystem size
- * and drop the blocks.
+ * Extract as much of the valid config as we can from the CLI input
+ * before opening the libxfs devices.
*/
- if ( dblocks % agsize != 0 &&
- (dblocks % agsize < XFS_AG_MIN_BLOCKS(blocklog))) {
- ASSERT(!daflag);
- dblocks = (xfs_rfsblock_t)((agcount - 1) * agsize);
- agcount--;
- ASSERT(agcount != 0);
- }
-
- validate_ag_geometry(blocklog, dblocks, agsize, agcount);
+ validate_blocksize(&cfg, &cli, &dft);
+ validate_sectorsize(&cfg, &cli, &dft, &ft, dfile, dry_run,
+ force_overwrite);
- if (!imflag)
- imaxpct = calc_default_imaxpct(blocklog, dblocks);
+ /*
+ * XXX: we still need to set block size and sector size global variables
+ * so that getnum/cvtnum works correctly
+ */
+ blocksize = cfg.blocksize;
+ sectorsize = cfg.sectorsize;
- 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.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)
- min_logblocks = MAX(min_logblocks, XFS_MIN_LOG_BYTES>>blocklog);
- if (logsize && xi.logBBsize > 0 && logblocks > DTOBT(xi.logBBsize, blocklog)) {
- fprintf(stderr,
-_("size %s specified for log subvolume is too large, maximum is %lld blocks\n"),
- logsize, (long long)DTOBT(xi.logBBsize, blocklog));
- usage();
- } else if (!logsize && xi.logBBsize > 0) {
- logblocks = DTOBT(xi.logBBsize, blocklog);
- } else if (logsize && !xi.logdev && !loginternal) {
- fprintf(stderr,
- _("size specified for non-existent log subvolume\n"));
- usage();
- } else if (loginternal && logsize && logblocks >= dblocks) {
- fprintf(stderr, _("size %lld too large for internal log\n"),
- (long long)logblocks);
- usage();
- } else if (!loginternal && !xi.logdev) {
- logblocks = 0;
- } else if (loginternal && !logsize) {
+ validate_log_sectorsize(&cfg, &cli, &dft);
+ validate_sb_features(&cfg, &cli);
- if (dblocks < GIGABYTES(1, blocklog)) {
- /* tiny filesystems get minimum sized logs. */
- logblocks = min_logblocks;
- } else if (dblocks < GIGABYTES(16, blocklog)) {
+ /*
+ * we've now completed basic validation of the features, sector and
+ * block sizes, so from this point onwards we use the values found in
+ * the cfg structure for them, not the command line structure.
+ */
+ validate_dirblocksize(&cfg, &cli);
+ validate_inodesize(&cfg, &cli);
- /*
- * For small filesystems, we want to use the
- * XFS_MIN_LOG_BYTES for filesystems smaller than 16G if
- * at all possible, ramping up to 128MB at 256GB.
- */
- logblocks = MIN(XFS_MIN_LOG_BYTES >> blocklog,
- min_logblocks * XFS_DFL_LOG_FACTOR);
- } else {
- /*
- * With a 2GB max log size, default to maximum size
- * at 4TB. This keeps the same ratio from the older
- * max log size of 128M at 256GB fs size. IOWs,
- * the ratio of fs size to log size is 2048:1.
- */
- logblocks = (dblocks << blocklog) / 2048;
- logblocks = logblocks >> blocklog;
- }
+ /*
+ * if the device size was specified convert it to a block count
+ * now we have a valid block size. These will be set to zero if
+ * nothing was specified, indicating we should use the full device.
+ */
+ cfg.dblocks = calc_dev_size(cli.dsize, &cfg, &dopts, D_SIZE, "data");
+ cfg.logblocks = calc_dev_size(cli.logsize, &cfg, &lopts, L_SIZE, "log");
+ cfg.rtblocks = calc_dev_size(cli.rtsize, &cfg, &ropts, R_SIZE, "rt");
- /* Ensure the chosen size meets minimum log size requirements */
- logblocks = MAX(min_logblocks, logblocks);
+ validate_rtextsize(&cfg, &cli, &ft);
+ calc_stripe_factors(&cfg, &cli, &ft);
- /* make sure the log fits wholly within an AG */
- if (logblocks >= agsize)
- logblocks = min_logblocks;
+ /*
+ * Open and validate the device configurations
+ */
+ open_devices(&cfg, &xi, (discard && !dry_run));
+ validate_datadev(&cfg, &cli);
+ validate_logdev(&cfg, &cli, &logfile);
+ validate_rtdev(&cfg, &cli, &rtfile);
- /* and now clamp the size to the maximum supported size */
- logblocks = MIN(logblocks, XFS_MAX_LOG_BLOCKS);
- if ((logblocks << blocklog) > XFS_MAX_LOG_BYTES)
- logblocks = XFS_MAX_LOG_BYTES >> blocklog;
+ /*
+ * At this point when know exactly what size all the devices are,
+ * so we can start validating and calculating layout options that are
+ * dependent on device sizes. Once calculated, make sure everything
+ * aligns to device geometry correctly.
+ */
+ calculate_initial_ag_geometry(&cfg, &cli);
+ align_ag_geometry(&cfg);
- }
- validate_log_size(logblocks, blocklog, min_logblocks);
+ calculate_imaxpct(&cfg, &cli);
- protostring = setup_proto(protofile);
- 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)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;
+ /*
+ * Set up the basic superblock parameters now so that we can use
+ * the geometry information we've already validated in libxfs
+ * provided functions to determine on-disk format information.
+ */
+ start_superblock_setup(&cfg, mp, sbp);
+ initialise_mount(&cfg, mp, sbp);
/*
- * sb_versionnum, finobt and rmapbt flags must be set before we use
- * libxfs_prealloc_blocks().
+ * With the mount set up, we can finally calculate the log size
+ * constraints and do default size calculations and final validation
*/
- sb_set_features(&mp->m_sb, &sb_feat, sectorsize, lsectorsize, dsunit);
+ calculate_log_size(&cfg, &cli, mp);
+ finish_superblock_setup(&cfg, mp, sbp);
- if (loginternal) {
- /*
- * Readjust the log size to fit within an AG if it was sized
- * automatically.
- */
- if (!logsize) {
- logblocks = MIN(logblocks,
- libxfs_alloc_ag_max_usable(mp));
+ /* Print the intended geometry of the fs. */
+ if (!quiet || dry_run) {
+ struct xfs_fsop_geom geo;
+ int error;
- /* revalidate the log size is valid if we changed it */
- validate_log_size(logblocks, blocklog, min_logblocks);
- }
- if (logblocks > agsize - libxfs_prealloc_blocks(mp)) {
+ error = -libxfs_fs_geometry(sbp, &geo,
+ XFS_FS_GEOM_MAX_STRUCT_VER);
+ if (error) {
fprintf(stderr,
- _("internal log size %lld too large, must fit in allocation group\n"),
- (long long)logblocks);
- usage();
- }
-
- if (laflag) {
- if (logagno >= agcount) {
- fprintf(stderr,
- _("log ag number %d too large, must be less than %lld\n"),
- logagno, (long long)agcount);
- usage();
- }
- } else
- logagno = (xfs_agnumber_t)(agcount / 2);
-
- logstart = XFS_AGB_TO_FSB(mp, logagno, libxfs_prealloc_blocks(mp));
- /*
- * Align the logstart at stripe unit boundary.
- */
- if (lsunit) {
- logstart = fixup_internal_log_stripe(mp,
- lsflag, logstart, agsize, lsunit,
- &logblocks, blocklog, &lalign);
- } else if (dsunit) {
- logstart = fixup_internal_log_stripe(mp,
- lsflag, logstart, agsize, dsunit,
- &logblocks, blocklog, &lalign);
+ _("%s: failed to generate filesystem geometry\n"),
+ progname);
+ exit(1);
}
- } else {
- logstart = 0;
- if (lsunit)
- fixup_log_stripe_unit(lsflag, lsunit,
- &logblocks, blocklog);
- }
- validate_log_size(logblocks, blocklog, min_logblocks);
-
- /* Temp support code to set up mkfs cfg parameters */
- cfg.blocksize = blocksize;
- cfg.blocklog = blocklog;
- cfg.sectorsize = sectorsize;
- cfg.sectorlog = sectorlog;
- cfg.lsectorsize = lsectorsize;
- cfg.lsectorlog = lsectorlog;
- cfg.dirblocksize = dirblocksize;
- cfg.dirblocklog = dirblocklog;
- cfg.inodesize = isize;
- cfg.inodelog = inodelog;
- cfg.inopblock = inopblock;
-
- cfg.dblocks = dblocks;
- cfg.logblocks = logblocks;
- cfg.rtblocks = rtblocks;
- cfg.rtextblocks = rtextblocks;
- cfg.rtextents = rtextents;
- cfg.rtbmblocks = nbmblocks;
- cfg.dsunit = dsunit;
- cfg.dswidth = dswidth;
- cfg.lsunit = lsunit;
- cfg.agsize = agsize;
- cfg.agcount = agcount;
- cfg.imaxpct = imaxpct;
- cfg.loginternal = loginternal;
- cfg.logstart = logstart;
- cfg.logagno = logagno;
- cfg.label = label;
- platform_uuid_copy(&cfg.uuid, &uuid);
- memcpy(&cfg.sb_feat, &sb_feat, sizeof(sb_feat));
- /* end temp support code */
- if (!quiet || dry_run) {
- print_mkfs_cfg(&cfg, dfile, logfile, rtfile);
+ xfs_report_geom(&geo, dfile, logfile, rtfile);
if (dry_run)
exit(0);
}
- /*
- * Finish setting up the superblock state ready for formatting.
- */
- setup_superblock(&cfg, mp, sbp);
-
/*
* we need the libxfs buffer cache from here on in.
*/
/*
* Allocate the root inode and anything else in the proto file.
*/
- parse_proto(mp, &fsx, &protostring);
+ parse_proto(mp, &cli.fsx, &protostring);
/*
* Protect ourselves against possible stupidity
if (xi.logdev && xi.logdev != xi.ddev)
libxfs_device_close(xi.logdev);
libxfs_device_close(xi.ddev);
+ libxfs_destroy();
return 0;
}
-
-static void
-conflict(
- char opt,
- const char *tab[],
- int oldidx,
- int newidx)
-{
- fprintf(stderr, _("Cannot specify both -%c %s and -%c %s\n"),
- opt, tab[oldidx], opt, tab[newidx]);
- usage();
-}
-
-
-static void
-illegal(
- const char *value,
- const char *opt)
-{
- fprintf(stderr, _("Illegal value %s for -%s option\n"), value, opt);
- usage();
-}
-
-static int
-ispow2(
- unsigned int i)
-{
- return (i & (i - 1)) == 0;
-}
-
-static void __attribute__((noreturn))
-reqval(
- char opt,
- const char *tab[],
- int idx)
-{
- fprintf(stderr, _("-%c %s option requires a value\n"), opt, tab[idx]);
- usage();
-}
-
-static void
-respec(
- char opt,
- const char *tab[],
- int idx)
-{
- fprintf(stderr, "-%c ", opt);
- if (tab)
- fprintf(stderr, "%s ", tab[idx]);
- fprintf(stderr, _("option respecified\n"));
- usage();
-}
-
-static void
-unknown(
- char opt,
- char *s)
-{
- fprintf(stderr, _("unknown option -%c %s\n"), opt, s);
- usage();
-}
-
-long long
-cvtnum(
- unsigned int blksize,
- unsigned int sectsize,
- const char *s)
-{
- long long i;
- char *sp;
- int c;
-
- i = strtoll(s, &sp, 0);
- if (i == 0 && sp == s)
- return -1LL;
- if (*sp == '\0')
- return i;
-
- if (sp[1] != '\0')
- return -1LL;
-
- 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:
- break;
- }
- return -1LL;
-}
-
-static void __attribute__((noreturn))
-usage( void )
-{
- fprintf(stderr, _("Usage: %s\n\
-/* blocksize */ [-b log=n|size=num]\n\
-/* metadata */ [-m crc=0|1,finobt=0|1,uuid=xxx,rmapbt=0|1,reflink=0|1]\n\
-/* data subvol */ [-d agcount=n,agsize=n,file,name=xxx,size=num,\n\
- (sunit=value,swidth=value|su=num,sw=num|noalign),\n\
- sectlog=n|sectsize=num\n\
-/* force overwrite */ [-f]\n\
-/* inode size */ [-i log=n|perblock=n|size=num,maxpct=n,attr=0|1|2,\n\
- projid32bit=0|1,sparse=0|1]\n\
-/* no discard */ [-K]\n\
-/* log subvol */ [-l agnum=n,internal,size=num,logdev=xxx,version=n\n\
- sunit=value|su=num,sectlog=n|sectsize=num,\n\
- lazy-count=0|1]\n\
-/* label */ [-L label (maximum 12 characters)]\n\
-/* naming */ [-n log=n|size=num,version=2|ci,ftype=0|1]\n\
-/* no-op info only */ [-N]\n\
-/* prototype file */ [-p fname]\n\
-/* quiet */ [-q]\n\
-/* realtime subvol */ [-r extsize=num,size=num,rtdev=xxx]\n\
-/* sectorsize */ [-s log=n|size=num]\n\
-/* version */ [-V]\n\
- devicename\n\
-<devicename> is required unless -d name=xxx is given.\n\
-<num> is xxx (bytes), xxxs (sectors), xxxb (fs blocks), xxxk (xxx KiB),\n\
- xxxm (xxx MiB), xxxg (xxx GiB), xxxt (xxx TiB) or xxxp (xxx PiB).\n\
-<value> is xxx (512 byte blocks).\n"),
- progname);
- exit(1);
-}