+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2000-2005 Silicon Graphics, Inc.
* All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include "libfrog.h"
+#include "libfrog/util.h"
#include "libxfs.h"
#include <ctype.h>
#include "xfs_multidisk.h"
#include "libxcmd.h"
-
-
+#include "libfrog/fsgeom.h"
+#include "libfrog/topology.h"
#define TERABYTES(count, blog) ((uint64_t)(count) << (40 - (blog)))
#define GIGABYTES(count, blog) ((uint64_t)(count) << (30 - (blog)))
* XXX: The configured block and sector sizes are defined as global variables so
* that they don't need to be passed to getnum/cvtnum().
*/
-unsigned int blocksize;
-unsigned int sectorsize;
+static unsigned int blocksize;
+static unsigned int sectorsize;
+
+/*
+ * Enums for each CLI parameter type are declared first so we can calculate the
+ * maximum array size needed to hold them automatically.
+ */
+enum {
+ B_SIZE = 0,
+ B_MAX_OPTS,
+};
+
+enum {
+ D_AGCOUNT = 0,
+ D_FILE,
+ D_NAME,
+ D_SIZE,
+ D_SUNIT,
+ D_SWIDTH,
+ D_AGSIZE,
+ D_SU,
+ D_SW,
+ D_SECTSIZE,
+ D_NOALIGN,
+ D_RTINHERIT,
+ D_PROJINHERIT,
+ D_EXTSZINHERIT,
+ D_COWEXTSIZE,
+ D_MAX_OPTS,
+};
+
+enum {
+ I_ALIGN = 0,
+ I_MAXPCT,
+ I_PERBLOCK,
+ I_SIZE,
+ I_ATTR,
+ I_PROJID32BIT,
+ I_SPINODES,
+ I_MAX_OPTS,
+};
+
+enum {
+ L_AGNUM = 0,
+ L_INTERNAL,
+ L_SIZE,
+ L_VERSION,
+ L_SUNIT,
+ L_SU,
+ L_DEV,
+ L_SECTSIZE,
+ L_FILE,
+ L_NAME,
+ L_LAZYSBCNTR,
+ L_MAX_OPTS,
+};
+
+enum {
+ N_SIZE = 0,
+ N_VERSION,
+ N_FTYPE,
+ N_MAX_OPTS,
+};
+
+enum {
+ R_EXTSIZE = 0,
+ R_SIZE,
+ R_DEV,
+ R_FILE,
+ R_NAME,
+ R_NOALIGN,
+ R_MAX_OPTS,
+};
+
+enum {
+ S_SIZE = 0,
+ S_SECTSIZE,
+ S_MAX_OPTS,
+};
+
+enum {
+ M_CRC = 0,
+ M_FINOBT,
+ M_UUID,
+ M_RMAPBT,
+ M_REFLINK,
+ M_MAX_OPTS,
+};
+
+/* Just define the max options array size manually right now */
+#define MAX_SUBOPTS D_MAX_OPTS
-#define MAX_SUBOPTS 17
#define SUBOPT_NEEDS_VAL (-1LL)
#define MAX_CONFLICTS 8
#define LAST_CONFLICT (-1)
bool str_seen;
bool convert;
bool is_power_2;
- int conflicts[MAX_CONFLICTS];
+ struct _conflict {
+ struct opt_params *opts;
+ int subopt;
+ } conflicts[MAX_CONFLICTS];
long long minval;
long long maxval;
long long defaultval;
} subopt_params[MAX_SUBOPTS];
};
-struct opt_params bopts = {
+/*
+ * The two dimensional conflict array requires some initialisations to know
+ * about tables that haven't yet been defined. Work around this ordering
+ * issue with extern definitions here.
+ */
+static struct opt_params sopts;
+
+static struct opt_params bopts = {
.name = 'b',
.subopts = {
-#define B_LOG 0
- "log",
-#define B_SIZE 1
- "size",
- NULL
+ [B_SIZE] = "size",
},
.subopt_params = {
- { .index = B_LOG,
- .conflicts = { B_SIZE,
- LAST_CONFLICT },
- .minval = XFS_MIN_BLOCKSIZE_LOG,
- .maxval = XFS_MAX_BLOCKSIZE_LOG,
- .defaultval = SUBOPT_NEEDS_VAL,
- },
{ .index = B_SIZE,
.convert = true,
.is_power_2 = true,
- .conflicts = { B_LOG,
- LAST_CONFLICT },
+ .conflicts = { { NULL, LAST_CONFLICT } },
.minval = XFS_MIN_BLOCKSIZE,
.maxval = XFS_MAX_BLOCKSIZE,
.defaultval = SUBOPT_NEEDS_VAL,
},
};
-struct opt_params dopts = {
+static struct opt_params dopts = {
.name = 'd',
.subopts = {
-#define D_AGCOUNT 0
- "agcount",
-#define D_FILE 1
- "file",
-#define D_NAME 2
- "name",
-#define D_SIZE 3
- "size",
-#define D_SUNIT 4
- "sunit",
-#define D_SWIDTH 5
- "swidth",
-#define D_AGSIZE 6
- "agsize",
-#define D_SU 7
- "su",
-#define D_SW 8
- "sw",
-#define D_SECTLOG 9
- "sectlog",
-#define D_SECTSIZE 10
- "sectsize",
-#define D_NOALIGN 11
- "noalign",
-#define D_RTINHERIT 12
- "rtinherit",
-#define D_PROJINHERIT 13
- "projinherit",
-#define D_EXTSZINHERIT 14
- "extszinherit",
-#define D_COWEXTSIZE 15
- "cowextsize",
- NULL
+ [D_AGCOUNT] = "agcount",
+ [D_FILE] = "file",
+ [D_NAME] = "name",
+ [D_SIZE] = "size",
+ [D_SUNIT] = "sunit",
+ [D_SWIDTH] = "swidth",
+ [D_AGSIZE] = "agsize",
+ [D_SU] = "su",
+ [D_SW] = "sw",
+ [D_SECTSIZE] = "sectsize",
+ [D_NOALIGN] = "noalign",
+ [D_RTINHERIT] = "rtinherit",
+ [D_PROJINHERIT] = "projinherit",
+ [D_EXTSZINHERIT] = "extszinherit",
+ [D_COWEXTSIZE] = "cowextsize",
},
.subopt_params = {
{ .index = D_AGCOUNT,
- .conflicts = { D_AGSIZE,
- LAST_CONFLICT },
+ .conflicts = { { &dopts, D_AGSIZE },
+ { NULL, LAST_CONFLICT } },
.minval = 1,
.maxval = XFS_MAX_AGNUMBER,
.defaultval = SUBOPT_NEEDS_VAL,
},
{ .index = D_FILE,
- .conflicts = { LAST_CONFLICT },
+ .conflicts = { { NULL, LAST_CONFLICT } },
.minval = 0,
.maxval = 1,
.defaultval = 1,
},
{ .index = D_NAME,
- .conflicts = { LAST_CONFLICT },
+ .conflicts = { { NULL, LAST_CONFLICT } },
.defaultval = SUBOPT_NEEDS_VAL,
},
{ .index = D_SIZE,
- .conflicts = { LAST_CONFLICT },
+ .conflicts = { { NULL, LAST_CONFLICT } },
.convert = true,
.minval = XFS_AG_MIN_BYTES,
.maxval = LLONG_MAX,
.defaultval = SUBOPT_NEEDS_VAL,
},
{ .index = D_SUNIT,
- .conflicts = { D_NOALIGN,
- D_SU,
- D_SW,
- LAST_CONFLICT },
+ .conflicts = { { &dopts, D_NOALIGN },
+ { &dopts, D_SU },
+ { &dopts, D_SW },
+ { NULL, LAST_CONFLICT } },
.minval = 0,
.maxval = UINT_MAX,
.defaultval = SUBOPT_NEEDS_VAL,
},
{ .index = D_SWIDTH,
- .conflicts = { D_NOALIGN,
- D_SU,
- D_SW,
- LAST_CONFLICT },
+ .conflicts = { { &dopts, D_NOALIGN },
+ { &dopts, D_SU },
+ { &dopts, D_SW },
+ { NULL, LAST_CONFLICT } },
.minval = 0,
.maxval = UINT_MAX,
.defaultval = SUBOPT_NEEDS_VAL,
},
{ .index = D_AGSIZE,
- .conflicts = { D_AGCOUNT,
- LAST_CONFLICT },
+ .conflicts = { { &dopts, D_AGCOUNT },
+ { NULL, LAST_CONFLICT } },
.convert = true,
.minval = XFS_AG_MIN_BYTES,
.maxval = XFS_AG_MAX_BYTES,
.defaultval = SUBOPT_NEEDS_VAL,
},
{ .index = D_SU,
- .conflicts = { D_NOALIGN,
- D_SUNIT,
- D_SWIDTH,
- LAST_CONFLICT },
+ .conflicts = { { &dopts, D_NOALIGN },
+ { &dopts, D_SUNIT },
+ { &dopts, D_SWIDTH },
+ { NULL, LAST_CONFLICT } },
.convert = true,
.minval = 0,
.maxval = UINT_MAX,
.defaultval = SUBOPT_NEEDS_VAL,
},
{ .index = D_SW,
- .conflicts = { D_NOALIGN,
- D_SUNIT,
- D_SWIDTH,
- LAST_CONFLICT },
+ .conflicts = { { &dopts, D_NOALIGN },
+ { &dopts, D_SUNIT },
+ { &dopts, D_SWIDTH },
+ { NULL, LAST_CONFLICT } },
.minval = 0,
.maxval = UINT_MAX,
.defaultval = SUBOPT_NEEDS_VAL,
},
- { .index = D_SECTLOG,
- .conflicts = { D_SECTSIZE,
- LAST_CONFLICT },
- .minval = XFS_MIN_SECTORSIZE_LOG,
- .maxval = XFS_MAX_SECTORSIZE_LOG,
- .defaultval = SUBOPT_NEEDS_VAL,
- },
{ .index = D_SECTSIZE,
- .conflicts = { D_SECTLOG,
- LAST_CONFLICT },
+ .conflicts = { { &sopts, S_SIZE },
+ { &sopts, S_SECTSIZE },
+ { NULL, LAST_CONFLICT } },
.convert = true,
.is_power_2 = true,
.minval = XFS_MIN_SECTORSIZE,
.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 = {
+static struct opt_params iopts = {
.name = 'i',
.subopts = {
-#define I_ALIGN 0
- "align",
-#define I_LOG 1
- "log",
-#define I_MAXPCT 2
- "maxpct",
-#define I_PERBLOCK 3
- "perblock",
-#define I_SIZE 4
- "size",
-#define I_ATTR 5
- "attr",
-#define I_PROJID32BIT 6
- "projid32bit",
-#define I_SPINODES 7
- "sparse",
- NULL
+ [I_ALIGN] = "align",
+ [I_MAXPCT] = "maxpct",
+ [I_PERBLOCK] = "perblock",
+ [I_SIZE] = "size",
+ [I_ATTR] = "attr",
+ [I_PROJID32BIT] = "projid32bit",
+ [I_SPINODES] = "sparse",
},
.subopt_params = {
{ .index = I_ALIGN,
- .conflicts = { LAST_CONFLICT },
+ .conflicts = { { NULL, LAST_CONFLICT } },
.minval = 0,
.maxval = 1,
.defaultval = 1,
},
- { .index = I_LOG,
- .conflicts = { I_PERBLOCK,
- I_SIZE,
- LAST_CONFLICT },
- .minval = XFS_DINODE_MIN_LOG,
- .maxval = XFS_DINODE_MAX_LOG,
- .defaultval = SUBOPT_NEEDS_VAL,
- },
{ .index = I_MAXPCT,
- .conflicts = { LAST_CONFLICT },
+ .conflicts = { { NULL, LAST_CONFLICT } },
.minval = 0,
.maxval = 100,
.defaultval = SUBOPT_NEEDS_VAL,
},
{ .index = I_PERBLOCK,
- .conflicts = { I_LOG,
- I_SIZE,
- LAST_CONFLICT },
+ .conflicts = { { &iopts, I_SIZE },
+ { NULL, LAST_CONFLICT } },
.is_power_2 = true,
.minval = XFS_MIN_INODE_PERBLOCK,
.maxval = XFS_MAX_BLOCKSIZE / XFS_DINODE_MIN_SIZE,
.defaultval = SUBOPT_NEEDS_VAL,
},
{ .index = I_SIZE,
- .conflicts = { I_PERBLOCK,
- I_LOG,
- LAST_CONFLICT },
+ .conflicts = { { &iopts, I_PERBLOCK },
+ { NULL, LAST_CONFLICT } },
.is_power_2 = true,
.minval = XFS_DINODE_MIN_SIZE,
.maxval = XFS_DINODE_MAX_SIZE,
.defaultval = SUBOPT_NEEDS_VAL,
},
{ .index = I_ATTR,
- .conflicts = { LAST_CONFLICT },
+ .conflicts = { { NULL, LAST_CONFLICT } },
.minval = 0,
.maxval = 2,
.defaultval = SUBOPT_NEEDS_VAL,
},
{ .index = I_PROJID32BIT,
- .conflicts = { LAST_CONFLICT },
+ .conflicts = { { NULL, LAST_CONFLICT } },
.minval = 0,
.maxval = 1,
.defaultval = 1,
},
{ .index = I_SPINODES,
- .conflicts = { LAST_CONFLICT },
+ .conflicts = { { NULL, LAST_CONFLICT } },
.minval = 0,
.maxval = 1,
.defaultval = 1,
},
};
-struct opt_params lopts = {
+static struct opt_params lopts = {
.name = 'l',
.subopts = {
-#define L_AGNUM 0
- "agnum",
-#define L_INTERNAL 1
- "internal",
-#define L_SIZE 2
- "size",
-#define L_VERSION 3
- "version",
-#define L_SUNIT 4
- "sunit",
-#define L_SU 5
- "su",
-#define L_DEV 6
- "logdev",
-#define L_SECTLOG 7
- "sectlog",
-#define L_SECTSIZE 8
- "sectsize",
-#define L_FILE 9
- "file",
-#define L_NAME 10
- "name",
-#define L_LAZYSBCNTR 11
- "lazy-count",
- NULL
+ [L_AGNUM] = "agnum",
+ [L_INTERNAL] = "internal",
+ [L_SIZE] = "size",
+ [L_VERSION] = "version",
+ [L_SUNIT] = "sunit",
+ [L_SU] = "su",
+ [L_DEV] = "logdev",
+ [L_SECTSIZE] = "sectsize",
+ [L_FILE] = "file",
+ [L_NAME] = "name",
+ [L_LAZYSBCNTR] = "lazy-count",
},
.subopt_params = {
{ .index = L_AGNUM,
- .conflicts = { L_DEV,
- LAST_CONFLICT },
+ .conflicts = { { &lopts, L_DEV },
+ { NULL, LAST_CONFLICT } },
.minval = 0,
.maxval = UINT_MAX,
.defaultval = SUBOPT_NEEDS_VAL,
},
{ .index = L_INTERNAL,
- .conflicts = { L_FILE,
- L_DEV,
- L_SECTLOG,
- L_SECTSIZE,
- LAST_CONFLICT },
+ .conflicts = { { &lopts, L_FILE },
+ { &lopts, L_DEV },
+ { &lopts, L_SECTSIZE },
+ { NULL, LAST_CONFLICT } },
.minval = 0,
.maxval = 1,
.defaultval = 1,
},
{ .index = L_SIZE,
- .conflicts = { LAST_CONFLICT },
+ .conflicts = { { NULL, LAST_CONFLICT } },
.convert = true,
.minval = 2 * 1024 * 1024LL, /* XXX: XFS_MIN_LOG_BYTES */
.maxval = XFS_MAX_LOG_BYTES,
.defaultval = SUBOPT_NEEDS_VAL,
},
{ .index = L_VERSION,
- .conflicts = { LAST_CONFLICT },
+ .conflicts = { { NULL, LAST_CONFLICT } },
.minval = 1,
.maxval = 2,
.defaultval = SUBOPT_NEEDS_VAL,
},
{ .index = L_SUNIT,
- .conflicts = { L_SU,
- LAST_CONFLICT },
+ .conflicts = { { &lopts, L_SU },
+ { NULL, LAST_CONFLICT } },
.minval = 1,
.maxval = BTOBB(XLOG_MAX_RECORD_BSIZE),
.defaultval = SUBOPT_NEEDS_VAL,
},
{ .index = L_SU,
- .conflicts = { L_SUNIT,
- LAST_CONFLICT },
+ .conflicts = { { &lopts, L_SUNIT },
+ { NULL, LAST_CONFLICT } },
.convert = true,
.minval = BBTOB(1),
.maxval = XLOG_MAX_RECORD_BSIZE,
.defaultval = SUBOPT_NEEDS_VAL,
},
{ .index = L_DEV,
- .conflicts = { L_AGNUM,
- L_INTERNAL,
- LAST_CONFLICT },
- .defaultval = SUBOPT_NEEDS_VAL,
- },
- { .index = L_SECTLOG,
- .conflicts = { L_SECTSIZE,
- L_INTERNAL,
- LAST_CONFLICT },
- .minval = XFS_MIN_SECTORSIZE_LOG,
- .maxval = XFS_MAX_SECTORSIZE_LOG,
+ .conflicts = { { &lopts, L_AGNUM },
+ { &lopts, L_NAME },
+ { &lopts, L_INTERNAL },
+ { NULL, LAST_CONFLICT } },
.defaultval = SUBOPT_NEEDS_VAL,
},
{ .index = L_SECTSIZE,
- .conflicts = { L_SECTLOG,
- L_INTERNAL,
- LAST_CONFLICT },
+ .conflicts = { { &lopts, L_INTERNAL },
+ { NULL, LAST_CONFLICT } },
.convert = true,
.is_power_2 = true,
.minval = XFS_MIN_SECTORSIZE,
.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 = {
+static struct opt_params nopts = {
.name = 'n',
.subopts = {
-#define N_LOG 0
- "log",
-#define N_SIZE 1
- "size",
-#define N_VERSION 2
- "version",
-#define N_FTYPE 3
- "ftype",
- NULL,
+ [N_SIZE] = "size",
+ [N_VERSION] = "version",
+ [N_FTYPE] = "ftype",
},
.subopt_params = {
- { .index = N_LOG,
- .conflicts = { N_SIZE,
- LAST_CONFLICT },
- .minval = XFS_MIN_REC_DIRSIZE,
- .maxval = XFS_MAX_BLOCKSIZE_LOG,
- .defaultval = SUBOPT_NEEDS_VAL,
- },
{ .index = N_SIZE,
- .conflicts = { N_LOG,
- LAST_CONFLICT },
+ .conflicts = { { NULL, LAST_CONFLICT } },
.convert = true,
.is_power_2 = true,
.minval = 1 << XFS_MIN_REC_DIRSIZE,
.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 = {
+static struct opt_params ropts = {
.name = 'r',
.subopts = {
-#define R_EXTSIZE 0
- "extsize",
-#define R_SIZE 1
- "size",
-#define R_DEV 2
- "rtdev",
-#define R_FILE 3
- "file",
-#define R_NAME 4
- "name",
-#define R_NOALIGN 5
- "noalign",
- NULL
+ [R_EXTSIZE] = "extsize",
+ [R_SIZE] = "size",
+ [R_DEV] = "rtdev",
+ [R_FILE] = "file",
+ [R_NAME] = "name",
+ [R_NOALIGN] = "noalign",
},
.subopt_params = {
{ .index = R_EXTSIZE,
- .conflicts = { LAST_CONFLICT },
+ .conflicts = { { NULL, LAST_CONFLICT } },
.convert = true,
.minval = XFS_MIN_RTEXTSIZE,
.maxval = XFS_MAX_RTEXTSIZE,
.defaultval = SUBOPT_NEEDS_VAL,
},
{ .index = R_SIZE,
- .conflicts = { LAST_CONFLICT },
+ .conflicts = { { NULL, LAST_CONFLICT } },
.convert = true,
.minval = 0,
.maxval = LLONG_MAX,
.defaultval = SUBOPT_NEEDS_VAL,
},
{ .index = R_DEV,
- .conflicts = { LAST_CONFLICT },
+ .conflicts = { { &ropts, R_NAME },
+ { NULL, LAST_CONFLICT } },
.defaultval = SUBOPT_NEEDS_VAL,
},
{ .index = R_FILE,
.minval = 0,
.maxval = 1,
.defaultval = 1,
- .conflicts = { LAST_CONFLICT },
+ .conflicts = { { NULL, LAST_CONFLICT } },
},
{ .index = R_NAME,
- .conflicts = { LAST_CONFLICT },
+ .conflicts = { { &ropts, R_DEV },
+ { NULL, LAST_CONFLICT } },
.defaultval = SUBOPT_NEEDS_VAL,
},
{ .index = R_NOALIGN,
.minval = 0,
.maxval = 1,
.defaultval = 1,
- .conflicts = { LAST_CONFLICT },
+ .conflicts = { { NULL, LAST_CONFLICT } },
},
},
};
-struct opt_params sopts = {
+static struct opt_params sopts = {
.name = 's',
.subopts = {
-#define S_LOG 0
- "log",
-#define S_SECTLOG 1
- "sectlog",
-#define S_SIZE 2
- "size",
-#define S_SECTSIZE 3
- "sectsize",
- NULL
+ [S_SIZE] = "size",
+ [S_SECTSIZE] = "sectsize",
},
.subopt_params = {
- { .index = S_LOG,
- .conflicts = { S_SIZE,
- S_SECTSIZE,
- LAST_CONFLICT },
- .minval = XFS_MIN_SECTORSIZE_LOG,
- .maxval = XFS_MAX_SECTORSIZE_LOG,
- .defaultval = SUBOPT_NEEDS_VAL,
- },
- { .index = S_SECTLOG,
- .conflicts = { S_SIZE,
- S_SECTSIZE,
- LAST_CONFLICT },
- .minval = XFS_MIN_SECTORSIZE_LOG,
- .maxval = XFS_MAX_SECTORSIZE_LOG,
- .defaultval = SUBOPT_NEEDS_VAL,
- },
{ .index = S_SIZE,
- .conflicts = { S_LOG,
- S_SECTLOG,
- LAST_CONFLICT },
+ .conflicts = { { &sopts, S_SECTSIZE },
+ { &dopts, D_SECTSIZE },
+ { NULL, LAST_CONFLICT } },
.convert = true,
.is_power_2 = true,
.minval = XFS_MIN_SECTORSIZE,
.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 = {
+static struct opt_params mopts = {
.name = 'm',
.subopts = {
-#define M_CRC 0
- "crc",
-#define M_FINOBT 1
- "finobt",
-#define M_UUID 2
- "uuid",
-#define M_RMAPBT 3
- "rmapbt",
-#define M_REFLINK 4
- "reflink",
- NULL
+ [M_CRC] = "crc",
+ [M_FINOBT] = "finobt",
+ [M_UUID] = "uuid",
+ [M_RMAPBT] = "rmapbt",
+ [M_REFLINK] = "reflink",
},
.subopt_params = {
{ .index = M_CRC,
- .conflicts = { LAST_CONFLICT },
+ .conflicts = { { NULL, LAST_CONFLICT } },
.minval = 0,
.maxval = 1,
.defaultval = 1,
},
{ .index = M_FINOBT,
- .conflicts = { LAST_CONFLICT },
+ .conflicts = { { NULL, LAST_CONFLICT } },
.minval = 0,
.maxval = 1,
.defaultval = 1,
},
{ .index = M_UUID,
- .conflicts = { LAST_CONFLICT },
+ .conflicts = { { NULL, LAST_CONFLICT } },
.defaultval = SUBOPT_NEEDS_VAL,
},
{ .index = M_RMAPBT,
- .conflicts = { LAST_CONFLICT },
+ .conflicts = { { NULL, LAST_CONFLICT } },
.minval = 0,
.maxval = 1,
.defaultval = 1,
},
{ .index = M_REFLINK,
- .conflicts = { LAST_CONFLICT },
+ .conflicts = { { NULL, LAST_CONFLICT } },
.minval = 0,
.maxval = 1,
.defaultval = 1,
/* parameters where 0 is not a valid value */
int64_t agcount;
- int dirblocklog;
int inodesize;
int inopblock;
int imaxpct;
usage( void )
{
fprintf(stderr, _("Usage: %s\n\
-/* blocksize */ [-b log=n|size=num]\n\
+/* blocksize */ [-b size=num]\n\
/* metadata */ [-m crc=0|1,finobt=0|1,uuid=xxx,rmapbt=0|1,reflink=0|1]\n\
/* data subvol */ [-d agcount=n,agsize=n,file,name=xxx,size=num,\n\
(sunit=value,swidth=value|su=num,sw=num|noalign),\n\
- sectlog=n|sectsize=num\n\
+ sectsize=num\n\
/* force overwrite */ [-f]\n\
-/* inode size */ [-i log=n|perblock=n|size=num,maxpct=n,attr=0|1|2,\n\
+/* inode size */ [-i perblock=n|size=num,maxpct=n,attr=0|1|2,\n\
projid32bit=0|1,sparse=0|1]\n\
/* no discard */ [-K]\n\
/* log subvol */ [-l agnum=n,internal,size=num,logdev=xxx,version=n\n\
- sunit=value|su=num,sectlog=n|sectsize=num,\n\
- lazy-count=0|1]\n\
+ sunit=value|su=num,sectsize=num,lazy-count=0|1]\n\
/* label */ [-L label (maximum 12 characters)]\n\
-/* naming */ [-n log=n|size=num,version=2|ci,ftype=0|1]\n\
+/* naming */ [-n size=num,version=2|ci,ftype=0|1]\n\
/* no-op info only */ [-N]\n\
/* prototype file */ [-p fname]\n\
/* quiet */ [-q]\n\
/* realtime subvol */ [-r extsize=num,size=num,rtdev=xxx]\n\
-/* sectorsize */ [-s log=n|size=num]\n\
+/* sectorsize */ [-s size=num]\n\
/* version */ [-V]\n\
devicename\n\
<devicename> is required unless -d name=xxx is given.\n\
static void
conflict(
- char opt,
- const char *tab[],
- int oldidx,
- int newidx)
+ struct opt_params *opts,
+ int option,
+ struct opt_params *con_opts,
+ int conflict)
{
fprintf(stderr, _("Cannot specify both -%c %s and -%c %s\n"),
- opt, tab[oldidx], opt, tab[newidx]);
+ con_opts->name, con_opts->subopts[conflict],
+ opts->name, opts->subopts[option]);
usage();
}
const char *value,
const char *opt)
{
- fprintf(stderr, _("Illegal value %s for -%s option\n"), value, opt);
+ fprintf(stderr, _("Invalid value %s for -%s option\n"), value, opt);
usage();
}
bool no_size,
bool no_name,
int *create,
- bool force_overwrite,
const char *optname)
{
struct stat statbuf;
return;
}
- if (!force_overwrite && check_overwrite(name)) {
- fprintf(stderr,
- _("%s: Use the -f option to force overwrite.\n"),
- progname);
- exit(1);
- }
-
/*
* We only want to completely truncate and recreate an existing file if
* we were specifically told it was a file. Set the create flag only in
usage();
}
+static void
+validate_overwrite(
+ const char *name,
+ bool force_overwrite)
+{
+ if (!force_overwrite && check_overwrite(name)) {
+ fprintf(stderr,
+ _("%s: Use the -f option to force overwrite.\n"),
+ progname);
+ exit(1);
+ }
+
+}
+
static void
validate_ag_geometry(
int blocklog,
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))
- cli->fsx.fsx_xflags |= XFS_DIFLAG_RTINHERIT;
+ if (getnum(value, opts, subopt))
+ cli->fsx.fsx_xflags |= FS_XFLAG_RTINHERIT;
break;
case D_PROJINHERIT:
- cli->fsx.fsx_projid = getnum(value, opts, D_PROJINHERIT);
- cli->fsx.fsx_xflags |= XFS_DIFLAG_PROJINHERIT;
+ cli->fsx.fsx_projid = getnum(value, opts, subopt);
+ cli->fsx.fsx_xflags |= FS_XFLAG_PROJINHERIT;
break;
case D_EXTSZINHERIT:
- cli->fsx.fsx_extsize = getnum(value, opts, D_EXTSZINHERIT);
- cli->fsx.fsx_xflags |= XFS_DIFLAG_EXTSZINHERIT;
+ cli->fsx.fsx_extsize = getnum(value, opts, subopt);
+ cli->fsx.fsx_xflags |= FS_XFLAG_EXTSZINHERIT;
break;
case D_COWEXTSIZE:
- cli->fsx.fsx_cowextsize = getnum(value, opts, D_COWEXTSIZE);
+ cli->fsx.fsx_cowextsize = getnum(value, opts, subopt);
cli->fsx.fsx_xflags |= FS_XFLAG_COWEXTSIZE;
break;
default:
char *value,
struct cli_params *cli)
{
- int inodelog;
-
switch (subopt) {
case I_ALIGN:
- cli->sb_feat.inode_align = getnum(value, opts, I_ALIGN);
- break;
- case I_LOG:
- inodelog = getnum(value, opts, I_LOG);
- cli->inodesize = 1 << inodelog;
+ cli->sb_feat.inode_align = getnum(value, opts, subopt);
break;
case I_MAXPCT:
- cli->imaxpct = getnum(value, opts, I_MAXPCT);
+ cli->imaxpct = getnum(value, opts, subopt);
break;
case I_PERBLOCK:
- cli->inopblock = getnum(value, opts, I_PERBLOCK);
+ cli->inopblock = getnum(value, opts, subopt);
break;
case I_SIZE:
- cli->inodesize = getnum(value, opts, I_SIZE);
+ cli->inodesize = getnum(value, opts, subopt);
break;
case I_ATTR:
- cli->sb_feat.attr_version = getnum(value, opts, I_ATTR);
+ cli->sb_feat.attr_version = getnum(value, opts, subopt);
break;
case I_PROJID32BIT:
- cli->sb_feat.projid32bit = getnum(value, opts, I_PROJID32BIT);
+ cli->sb_feat.projid32bit = getnum(value, opts, subopt);
break;
case I_SPINODES:
- cli->sb_feat.spinodes = getnum(value, opts, I_SPINODES);
+ cli->sb_feat.spinodes = getnum(value, opts, subopt);
break;
default:
return -EINVAL;
char *value,
struct cli_params *cli)
{
- int lsectorlog;
-
switch (subopt) {
case L_AGNUM:
- cli->logagno = getnum(value, opts, L_AGNUM);
+ cli->logagno = getnum(value, opts, subopt);
break;
case L_FILE:
- cli->xi->lisfile = getnum(value, opts, L_FILE);
+ cli->xi->lisfile = getnum(value, opts, subopt);
break;
case L_INTERNAL:
- cli->loginternal = getnum(value, opts, L_INTERNAL);
+ cli->loginternal = getnum(value, opts, subopt);
break;
case L_SU:
- cli->lsu = getstr(value, opts, L_SU);
+ cli->lsu = getstr(value, opts, subopt);
break;
case L_SUNIT:
- cli->lsunit = getnum(value, opts, L_SUNIT);
+ cli->lsunit = getnum(value, opts, subopt);
break;
case L_NAME:
case L_DEV:
- cli->xi->logname = getstr(value, opts, L_NAME);
+ cli->xi->logname = getstr(value, opts, subopt);
cli->loginternal = 0;
break;
case L_VERSION:
- cli->sb_feat.log_version = getnum(value, opts, L_VERSION);
+ cli->sb_feat.log_version = getnum(value, opts, subopt);
break;
case L_SIZE:
- cli->logsize = getstr(value, opts, L_SIZE);
- break;
- case L_SECTLOG:
- lsectorlog = getnum(value, opts, L_SECTLOG);
- cli->lsectorsize = 1 << lsectorlog;
+ cli->logsize = getstr(value, opts, subopt);
break;
case L_SECTSIZE:
- cli->lsectorsize = getnum(value, opts, L_SECTSIZE);
+ cli->lsectorsize = getnum(value, opts, subopt);
break;
case L_LAZYSBCNTR:
- cli->sb_feat.lazy_sb_counters = getnum(value, opts, L_LAZYSBCNTR);
+ cli->sb_feat.lazy_sb_counters = getnum(value, opts, subopt);
break;
default:
return -EINVAL;
{
switch (subopt) {
case M_CRC:
- cli->sb_feat.crcs_enabled = getnum(value, opts, M_CRC);
+ cli->sb_feat.crcs_enabled = getnum(value, opts, subopt);
if (cli->sb_feat.crcs_enabled)
cli->sb_feat.dirftype = true;
break;
case M_FINOBT:
- cli->sb_feat.finobt = getnum(value, opts, M_FINOBT);
+ cli->sb_feat.finobt = getnum(value, opts, subopt);
break;
case M_UUID:
if (!value || *value == '\0')
- reqval('m', opts->subopts, M_UUID);
+ reqval('m', opts->subopts, subopt);
if (platform_uuid_parse(value, &cli->uuid))
illegal(value, "m uuid");
break;
case M_RMAPBT:
- cli->sb_feat.rmapbt = getnum(value, opts, M_RMAPBT);
+ cli->sb_feat.rmapbt = getnum(value, opts, subopt);
break;
case M_REFLINK:
- cli->sb_feat.reflink = getnum(value, opts, M_REFLINK);
+ cli->sb_feat.reflink = getnum(value, opts, subopt);
break;
default:
return -EINVAL;
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, opts, R_EXTSIZE);
+ cli->rtextsize = getstr(value, opts, subopt);
break;
case R_FILE:
- cli->xi->risfile = getnum(value, opts, R_FILE);
+ cli->xi->risfile = getnum(value, opts, subopt);
break;
case R_NAME:
case R_DEV:
- cli->xi->rtname = getstr(value, opts, R_NAME);
+ cli->xi->rtname = getstr(value, opts, subopt);
break;
case R_SIZE:
- cli->rtsize = getstr(value, opts, R_SIZE);
+ cli->rtsize = getstr(value, opts, subopt);
break;
case R_NOALIGN:
- cli->sb_feat.nortalign = getnum(value, opts, R_NOALIGN);
+ cli->sb_feat.nortalign = getnum(value, opts, subopt);
break;
default:
return -EINVAL;
char *value,
struct cli_params *cli)
{
- int sectorlog;
-
switch (subopt) {
- case S_LOG:
- case S_SECTLOG:
- if (cli->sectorsize)
- conflict('s', opts->subopts, S_SECTSIZE, S_SECTLOG);
- sectorlog = getnum(value, opts, S_SECTLOG);
- cli->sectorsize = 1 << sectorlog;
- cli->lsectorsize = cli->sectorsize;
- break;
case S_SIZE:
case S_SECTSIZE:
- if (cli->sectorsize)
- conflict('s', opts->subopts, S_SECTLOG, S_SECTSIZE);
- cli->sectorsize = getnum(value, opts, S_SECTSIZE);
+ cli->sectorsize = getnum(value, opts, subopt);
cli->lsectorsize = cli->sectorsize;
break;
default:
return 0;
}
-struct subopts {
+static struct subopts {
char opt;
struct opt_params *opts;
- int (*parser)();
+ int (*parser)(struct opt_params *opts,
+ int subopt,
+ char *value,
+ struct cli_params *cli);
} subopt_tab[] = {
{ 'b', &bopts, block_opts_parser },
{ 'd', &dopts, data_opts_parser },
* files or block devices and set the control parameters correctly.
*/
check_device_type(dfile, &cli->xi->disfile, !cli->dsize, !dfile,
- dry_run ? NULL : &cli->xi->dcreat,
- force_overwrite, "d");
+ dry_run ? NULL : &cli->xi->dcreat, "d");
if (!cli->loginternal)
check_device_type(cli->xi->logname, &cli->xi->lisfile,
!cli->logsize, !cli->xi->logname,
- dry_run ? NULL : &cli->xi->lcreat,
- force_overwrite, "l");
+ dry_run ? NULL : &cli->xi->lcreat, "l");
if (cli->xi->rtname)
check_device_type(cli->xi->rtname, &cli->xi->risfile,
!cli->rtsize, !cli->xi->rtname,
- dry_run ? NULL : &cli->xi->rcreat,
- force_overwrite, "r");
+ dry_run ? NULL : &cli->xi->rcreat, "r");
/*
* Explicitly disable direct IO for image files so we don't error out on
/* 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();
}
/* attr2 always on */
if (!cli->sb_feat.projid32bit) {
fprintf(stderr,
-_("32 bit Project IDs always enabled on CRC enabled filesytems\n"));
+_("32 bit Project IDs always enabled on CRC enabled filesystems\n"));
usage();
}
/* ftype always on */
if (!cli->sb_feat.dirftype) {
fprintf(stderr,
-_("Directory ftype field always enabled on CRC enabled filesytems\n"));
+_("Directory ftype field always enabled on CRC enabled filesystems\n"));
usage();
}
- } else {
+ } else { /* !crcs_enabled */
/*
- * The kernel doesn't currently support crc=0,finobt=1
- * filesystems. If crcs are not enabled and the user has not
- * explicitly turned finobt on, then silently turn it off to
- * avoid an unnecessary warning.
+ * The kernel doesn't support crc=0,finobt=1 filesystems.
+ * If crcs are not enabled and the user has not explicitly
+ * turned finobt on, then silently turn it off to avoid an
+ * unnecessary warning.
* If the user explicitly tried to use crc=0,finobt=1,
* then issue an error.
- * The same is also for sparse inodes.
+ * The same is also true for sparse inodes and reflink.
*/
if (cli->sb_feat.finobt && cli_opt_set(&mopts, M_FINOBT)) {
fprintf(stderr,
}
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();
}
cli->sb_feat.rmapbt = false;
- if (cli->sb_feat.reflink) {
+ if (cli->sb_feat.reflink && cli_opt_set(&mopts, M_REFLINK)) {
fprintf(stderr,
_("reflink not supported without CRC support\n"));
usage();
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,
ASSERT(cfg->rtextblocks);
}
+/* Validate the incoming extsize hint. */
+static void
+validate_extsize_hint(
+ struct xfs_mount *mp,
+ struct cli_params *cli)
+{
+ xfs_failaddr_t fa;
+ uint16_t flags = 0;
+
+ /*
+ * First we validate the extent size inherit hint on a directory so
+ * that we know that we'll be propagating a correct hint and flag to
+ * new files on the data device.
+ */
+ if (cli->fsx.fsx_xflags & FS_XFLAG_EXTSZINHERIT)
+ flags |= XFS_DIFLAG_EXTSZINHERIT;
+
+ fa = libxfs_inode_validate_extsize(mp, cli->fsx.fsx_extsize, S_IFDIR,
+ flags);
+ if (fa) {
+ fprintf(stderr,
+_("illegal extent size hint %lld, must be less than %u.\n"),
+ (long long)cli->fsx.fsx_extsize,
+ min(MAXEXTLEN, mp->m_sb.sb_agblocks / 2));
+ usage();
+ }
+
+ /*
+ * Now we do it again with a realtime file so that we know the hint and
+ * flag that get passed on to realtime files will be correct.
+ */
+ if (mp->m_sb.sb_rextsize == 0)
+ return;
+
+ flags = XFS_DIFLAG_REALTIME;
+ if (cli->fsx.fsx_xflags & FS_XFLAG_EXTSZINHERIT)
+ flags |= XFS_DIFLAG_EXTSIZE;
+
+ fa = libxfs_inode_validate_extsize(mp, cli->fsx.fsx_extsize, S_IFREG,
+ flags);
+
+ if (fa) {
+ fprintf(stderr,
+_("illegal extent size hint %lld, must be less than %u and a multiple of %u.\n"),
+ (long long)cli->fsx.fsx_extsize,
+ min(MAXEXTLEN, mp->m_sb.sb_agblocks / 2),
+ mp->m_sb.sb_rextsize);
+ usage();
+ }
+}
+
+/* Validate the incoming CoW extsize hint. */
+static void
+validate_cowextsize_hint(
+ struct xfs_mount *mp,
+ struct cli_params *cli)
+{
+ xfs_failaddr_t fa;
+ uint64_t flags2 = 0;
+
+ /*
+ * Validate the copy on write extent size inherit hint on a directory
+ * so that we know that we'll be propagating a correct hint and flag to
+ * new files on the data device.
+ */
+ if (cli->fsx.fsx_xflags & FS_XFLAG_COWEXTSIZE)
+ flags2 |= XFS_DIFLAG2_COWEXTSIZE;
+
+ fa = libxfs_inode_validate_cowextsize(mp, cli->fsx.fsx_cowextsize,
+ S_IFDIR, 0, flags2);
+ if (fa) {
+ fprintf(stderr,
+_("illegal CoW extent size hint %lld, must be less than %u.\n"),
+ (long long)cli->fsx.fsx_cowextsize,
+ min(MAXEXTLEN, mp->m_sb.sb_agblocks / 2));
+ usage();
+ }
+}
+
/*
* Validate the configured stripe geometry, or is none is specified, pull
* the configuration from the underlying device.
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
open_devices(
struct mkfs_params *cfg,
- struct libxfs_xinit *xi,
- bool discard)
+ struct libxfs_xinit *xi)
{
uint64_t sector_mask;
* So, we reduce the size (in basic blocks) to a perfect
* multiple of the sector size, or 1024, whichever is larger.
*/
- sector_mask = (uint64_t)-1 << (MAX(cfg->sectorlog, 10) - BBSHIFT);
+ sector_mask = (uint64_t)-1 << (max(cfg->sectorlog, 10) - BBSHIFT);
xi->dsize &= sector_mask;
xi->rtsize &= sector_mask;
- xi->logBBsize &= (uint64_t)-1 << (MAX(cfg->lsectorlog, 10) - BBSHIFT);
-
+ xi->logBBsize &= (uint64_t)-1 << (max(cfg->lsectorlog, 10) - BBSHIFT);
+}
- if (!discard)
- return;
+static void
+discard_devices(
+ struct libxfs_xinit *xi)
+{
+ /*
+ *Â This function has to be called after libxfs has been initialized.
+ */
if (!xi->disfile)
discard_blocks(xi->ddev, xi->dsize);
struct xfs_mount *mp,
int sunit)
{
+ uint64_t logend;
+
/* round up log start if necessary */
if ((cfg->logstart % sunit) != 0)
cfg->logstart = ((cfg->logstart + (sunit - 1)) / sunit) * sunit;
+ /* If our log start overlaps the next AG's metadata, fail. */
+ if (XFS_FSB_TO_AGBNO(mp, cfg->logstart) <= XFS_AGFL_BLOCK(mp)) {
+ fprintf(stderr,
+_("Due to stripe alignment, the internal log start (%lld) cannot be aligned\n"
+ "within an allocation group.\n"),
+ (long long) cfg->logstart);
+ usage();
+ }
+
/* round up/down the log size now */
align_log_size(cfg, sunit);
- /* check the aligned log still fits in an AG. */
- if (cfg->logblocks > cfg->agsize - XFS_FSB_TO_AGBNO(mp, cfg->logstart)) {
+ /* check the aligned log still starts and ends in the same AG. */
+ logend = cfg->logstart + cfg->logblocks - 1;
+ if (XFS_FSB_TO_AGNO(mp, cfg->logstart) != XFS_FSB_TO_AGNO(mp, logend)) {
fprintf(stderr,
_("Due to stripe alignment, the internal log size (%lld) is too large.\n"
"Must fit within an allocation group.\n"),
}
}
-void
+static void
validate_log_size(uint64_t logblocks, int blocklog, int min_logblocks)
{
if (logblocks < min_logblocks) {
struct cli_params *cli,
struct xfs_mount *mp)
{
- struct sb_feat_args *fp = &cfg->sb_feat;
struct xfs_sb *sbp = &mp->m_sb;
int min_logblocks;
+ struct xfs_mount mount;
- min_logblocks = max_trans_res(sbp->sb_agblocks, fp->crcs_enabled,
- fp->dir_version, cfg->sectorlog,
- cfg->blocklog, cfg->inodelog,
- cfg->dirblocklog, fp->log_version,
- cfg->lsunit, fp->finobt, fp->rmapbt,
- fp->reflink, fp->inode_align);
+ /* we need a temporary mount to calculate the minimum log size. */
+ memset(&mount, 0, sizeof(mount));
+ mount.m_sb = *sbp;
+ libxfs_mount(&mount, &mp->m_sb, 0, 0, 0, 0);
+ min_logblocks = libxfs_log_calc_minimum_size(&mount);
+ libxfs_umount(&mount);
ASSERT(min_logblocks);
- min_logblocks = MAX(XFS_MIN_LOG_BLOCKS, min_logblocks);
+ min_logblocks = max(XFS_MIN_LOG_BLOCKS, min_logblocks);
/* if we have lots of blocks, check against XFS_MIN_LOG_BYTES, too */
if (!cli->logsize &&
cfg->dblocks >= (1024*1024*1024) >> cfg->blocklog)
- min_logblocks = MAX(min_logblocks,
+ min_logblocks = max(min_logblocks,
XFS_MIN_LOG_BYTES >> cfg->blocklog);
/*
* XFS_MIN_LOG_BYTES for filesystems smaller than 16G if
* at all possible, ramping up to 128MB at 256GB.
*/
- cfg->logblocks = MIN(XFS_MIN_LOG_BYTES >> cfg->blocklog,
+ cfg->logblocks = min(XFS_MIN_LOG_BYTES >> cfg->blocklog,
min_logblocks * XFS_DFL_LOG_FACTOR);
} else {
/*
}
/* Ensure the chosen size meets minimum log size requirements */
- cfg->logblocks = MAX(min_logblocks, cfg->logblocks);
+ cfg->logblocks = max(min_logblocks, cfg->logblocks);
/*
* Make sure the log fits wholly within an AG
* opened to decide what is the valid maximum size of a log in
* an AG.
*/
- cfg->logblocks = MIN(cfg->logblocks,
+ cfg->logblocks = min(cfg->logblocks,
libxfs_alloc_ag_max_usable(mp) - 1);
/* and now clamp the size to the maximum supported size */
- cfg->logblocks = MIN(cfg->logblocks, XFS_MAX_LOG_BLOCKS);
+ cfg->logblocks = min(cfg->logblocks, XFS_MAX_LOG_BLOCKS);
if ((cfg->logblocks << cfg->blocklog) > XFS_MAX_LOG_BYTES)
cfg->logblocks = XFS_MAX_LOG_BYTES >> cfg->blocklog;
}
/*
- * Set up mount and superblock with the minimum parameters required for
+ * Set up superblock with the minimum parameters required for
* the libxfs macros needed by the log sizing code to run successfully.
+ * This includes a minimum log size calculation, so we need everything
+ * that goes into that calculation to be setup here including feature
+ * flags.
*/
static void
-initialise_mount(
+start_superblock_setup(
struct mkfs_params *cfg,
struct xfs_mount *mp,
struct xfs_sb *sbp)
{
- sbp->sb_blocklog = (uint8_t)cfg->blocklog;
+ sbp->sb_magicnum = XFS_SB_MAGIC;
+ sbp->sb_sectsize = (uint16_t)cfg->sectorsize;
sbp->sb_sectlog = (uint8_t)cfg->sectorlog;
- sbp->sb_agblklog = (uint8_t)log2_roundup(cfg->agsize);
+ sbp->sb_blocksize = cfg->blocksize;
+ sbp->sb_blocklog = (uint8_t)cfg->blocklog;
+
sbp->sb_agblocks = (xfs_agblock_t)cfg->agsize;
+ sbp->sb_agblklog = (uint8_t)log2_roundup(cfg->agsize);
sbp->sb_agcount = (xfs_agnumber_t)cfg->agcount;
- mp->m_blkbb_log = sbp->sb_blocklog - BBSHIFT;
- mp->m_sectbb_log = sbp->sb_sectlog - BBSHIFT;
+
+ sbp->sb_inodesize = (uint16_t)cfg->inodesize;
+ sbp->sb_inodelog = (uint8_t)cfg->inodelog;
+ sbp->sb_inopblock = (uint16_t)(cfg->blocksize / cfg->inodesize);
+ sbp->sb_inopblog = (uint8_t)(cfg->blocklog - cfg->inodelog);
+
+ sbp->sb_dirblklog = cfg->dirblocklog - cfg->blocklog;
+
+ sb_set_features(cfg, sbp);
/*
- * sb_versionnum, finobt and rmapbt flags must be set before we use
- * libxfs_prealloc_blocks().
+ * log stripe unit is stored in bytes on disk and cannot be zero
+ * for v2 logs.
*/
- sb_set_features(cfg, sbp);
+ if (cfg->sb_feat.log_version == 2) {
+ if (cfg->lsunit)
+ sbp->sb_logsunit = XFS_FSB_TO_B(mp, cfg->lsunit);
+ else
+ sbp->sb_logsunit = 1;
+ } else
+ sbp->sb_logsunit = 0;
+
}
static void
-print_mkfs_cfg(
+initialise_mount(
struct mkfs_params *cfg,
- char *dfile,
- char *logfile,
- char *rtfile)
+ struct xfs_mount *mp,
+ struct xfs_sb *sbp)
{
- struct sb_feat_args *fp = &cfg->sb_feat;
-
- printf(_(
-"meta-data=%-22s isize=%-6d agcount=%lld, agsize=%lld blks\n"
-" =%-22s sectsz=%-5u attr=%u, projid32bit=%u\n"
-" =%-22s crc=%-8u finobt=%u, sparse=%u, rmapbt=%u, reflink=%u\n"
-"data =%-22s bsize=%-6u blocks=%llu, imaxpct=%u\n"
-" =%-22s sunit=%-6u swidth=%u blks\n"
-"naming =version %-14u bsize=%-6u ascii-ci=%d ftype=%d\n"
-"log =%-22s bsize=%-6d blocks=%lld, version=%d\n"
-" =%-22s sectsz=%-5u sunit=%d blks, lazy-count=%d\n"
-"realtime =%-22s extsz=%-6d blocks=%lld, rtextents=%lld\n"),
- dfile, cfg->inodesize, (long long)cfg->agcount,
- (long long)cfg->agsize,
- "", cfg->sectorsize, fp->attr_version, fp->projid32bit,
- "", fp->crcs_enabled, fp->finobt, fp->spinodes, fp->rmapbt,
- fp->reflink,
- "", cfg->blocksize, (long long)cfg->dblocks, cfg->imaxpct,
- "", cfg->dsunit, cfg->dswidth,
- fp->dir_version, cfg->dirblocksize, fp->nci, fp->dirftype,
- logfile, cfg->blocksize, (long long)cfg->logblocks,
- fp->log_version,
- "", cfg->lsectorsize, cfg->lsunit, fp->lazy_sb_counters,
- rtfile, (int)cfg->rtextblocks << cfg->blocklog,
- (long long)cfg->rtblocks, (long long)cfg->rtextents);
+ /* Minimum needed for libxfs_prealloc_blocks() */
+ mp->m_blkbb_log = sbp->sb_blocklog - BBSHIFT;
+ mp->m_sectbb_log = sbp->sb_sectlog - BBSHIFT;
}
/*
* copy, so no need to care about endian swapping here.
*/
static void
-setup_superblock(
+finish_superblock_setup(
struct mkfs_params *cfg,
struct xfs_mount *mp,
struct xfs_sb *sbp)
{
- if (cfg->label)
- strncpy(sbp->sb_fname, cfg->label, sizeof(sbp->sb_fname));
+ if (cfg->label) {
+ size_t label_len;
+
+ /*
+ * Labels are null terminated unless the string fits exactly
+ * in the label field, so assume sb_fname is zeroed and then
+ * do a memcpy because the destination isn't a normal C string.
+ */
+ label_len = min(sizeof(sbp->sb_fname), strlen(cfg->label));
+ memcpy(sbp->sb_fname, cfg->label, label_len);
+ }
- sbp->sb_magicnum = XFS_SB_MAGIC;
- sbp->sb_blocksize = cfg->blocksize;
sbp->sb_dblocks = cfg->dblocks;
sbp->sb_rblocks = cfg->rtblocks;
sbp->sb_rextents = cfg->rtextents;
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_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;
}
*/
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);
}
struct xfs_mount *mp,
struct xfs_sb *sbp,
xfs_agnumber_t agno,
- int *worst_freelist)
+ int *worst_freelist,
+ struct list_head *buffer_list)
{
+ struct aghdr_init_data id = {
+ .agno = agno,
+ .agsize = cfg->agsize,
+ };
struct xfs_perag *pag = libxfs_perag_get(mp, agno);
- struct xfs_agfl *agfl;
- struct xfs_agf *agf;
- struct xfs_agi *agi;
- struct xfs_buf *buf;
- struct xfs_btree_block *block;
- struct xfs_alloc_rec *arec;
- struct xfs_alloc_rec *nrec;
- int bucket;
- uint64_t agsize = cfg->agsize;
- xfs_agblock_t agblocks;
- bool is_log_ag = false;
- int c;
+ int error;
- if (cfg->loginternal && agno == cfg->logagno)
- is_log_ag = true;
-
- /*
- * Superblock.
- */
- buf = libxfs_getbuf(mp->m_ddev_targp,
- XFS_AG_DADDR(mp, agno, XFS_SB_DADDR),
- XFS_FSS_TO_BB(mp, 1));
- buf->b_ops = &xfs_sb_buf_ops;
- memset(XFS_BUF_PTR(buf), 0, cfg->sectorsize);
- libxfs_sb_to_disk((void *)XFS_BUF_PTR(buf), sbp);
- libxfs_writebuf(buf, LIBXFS_EXIT_ON_FAILURE);
-
- /*
- * AG header block: freespace
- */
- buf = libxfs_getbuf(mp->m_ddev_targp,
- XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR(mp)),
- XFS_FSS_TO_BB(mp, 1));
- buf->b_ops = &xfs_agf_buf_ops;
- agf = XFS_BUF_TO_AGF(buf);
- memset(agf, 0, cfg->sectorsize);
if (agno == cfg->agcount - 1)
- agsize = cfg->dblocks - (xfs_rfsblock_t)(agno * agsize);
- agf->agf_magicnum = cpu_to_be32(XFS_AGF_MAGIC);
- agf->agf_versionnum = cpu_to_be32(XFS_AGF_VERSION);
- agf->agf_seqno = cpu_to_be32(agno);
- agf->agf_length = cpu_to_be32(agsize);
- agf->agf_roots[XFS_BTNUM_BNOi] = cpu_to_be32(XFS_BNO_BLOCK(mp));
- agf->agf_roots[XFS_BTNUM_CNTi] = cpu_to_be32(XFS_CNT_BLOCK(mp));
- agf->agf_levels[XFS_BTNUM_BNOi] = cpu_to_be32(1);
- agf->agf_levels[XFS_BTNUM_CNTi] = cpu_to_be32(1);
- pag->pagf_levels[XFS_BTNUM_BNOi] = 1;
- pag->pagf_levels[XFS_BTNUM_CNTi] = 1;
-
- if (xfs_sb_version_hasrmapbt(sbp)) {
- agf->agf_roots[XFS_BTNUM_RMAPi] = cpu_to_be32(XFS_RMAP_BLOCK(mp));
- agf->agf_levels[XFS_BTNUM_RMAPi] = cpu_to_be32(1);
- agf->agf_rmap_blocks = cpu_to_be32(1);
- }
+ id.agsize = cfg->dblocks - (xfs_rfsblock_t)(agno * cfg->agsize);
- if (xfs_sb_version_hasreflink(sbp)) {
- agf->agf_refcount_root = cpu_to_be32(libxfs_refc_block(mp));
- agf->agf_refcount_level = cpu_to_be32(1);
- agf->agf_refcount_blocks = cpu_to_be32(1);
+ INIT_LIST_HEAD(&id.buffer_list);
+ error = -libxfs_ag_init_headers(mp, &id);
+ if (error) {
+ fprintf(stderr, _("AG header init failed, error %d\n"), error);
+ exit(1);
}
- agf->agf_flfirst = 0;
- agf->agf_fllast = cpu_to_be32(XFS_AGFL_SIZE(mp) - 1);
- agf->agf_flcount = 0;
- agblocks = (xfs_agblock_t)(agsize - libxfs_prealloc_blocks(mp));
- agf->agf_freeblks = cpu_to_be32(agblocks);
- agf->agf_longest = cpu_to_be32(agblocks);
-
- if (xfs_sb_version_hascrc(sbp))
- platform_uuid_copy(&agf->agf_uuid, &sbp->sb_uuid);
+ list_splice_tail_init(&id.buffer_list, buffer_list);
- if (is_log_ag) {
- be32_add_cpu(&agf->agf_freeblks, -(int64_t)cfg->logblocks);
- agf->agf_longest = cpu_to_be32(agsize -
- XFS_FSB_TO_AGBNO(mp, cfg->logstart) - cfg->logblocks);
- }
if (libxfs_alloc_min_freelist(mp, pag) > *worst_freelist)
*worst_freelist = libxfs_alloc_min_freelist(mp, pag);
- libxfs_writebuf(buf, LIBXFS_EXIT_ON_FAILURE);
-
- /*
- * AG freelist header block
- */
- buf = libxfs_getbuf(mp->m_ddev_targp,
- XFS_AG_DADDR(mp, agno, XFS_AGFL_DADDR(mp)),
- XFS_FSS_TO_BB(mp, 1));
- buf->b_ops = &xfs_agfl_buf_ops;
- agfl = XFS_BUF_TO_AGFL(buf);
- /* setting to 0xff results in initialisation to NULLAGBLOCK */
- memset(agfl, 0xff, cfg->sectorsize);
- if (xfs_sb_version_hascrc(sbp)) {
- agfl->agfl_magicnum = cpu_to_be32(XFS_AGFL_MAGIC);
- agfl->agfl_seqno = cpu_to_be32(agno);
- platform_uuid_copy(&agfl->agfl_uuid, &sbp->sb_uuid);
- for (bucket = 0; bucket < XFS_AGFL_SIZE(mp); bucket++)
- agfl->agfl_bno[bucket] = cpu_to_be32(NULLAGBLOCK);
- }
-
- libxfs_writebuf(buf, LIBXFS_EXIT_ON_FAILURE);
-
- /*
- * AG header block: inodes
- */
- buf = libxfs_getbuf(mp->m_ddev_targp,
- XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp)),
- XFS_FSS_TO_BB(mp, 1));
- agi = XFS_BUF_TO_AGI(buf);
- buf->b_ops = &xfs_agi_buf_ops;
- memset(agi, 0, cfg->sectorsize);
- agi->agi_magicnum = cpu_to_be32(XFS_AGI_MAGIC);
- agi->agi_versionnum = cpu_to_be32(XFS_AGI_VERSION);
- agi->agi_seqno = cpu_to_be32(agno);
- agi->agi_length = cpu_to_be32(agsize);
- agi->agi_count = 0;
- agi->agi_root = cpu_to_be32(XFS_IBT_BLOCK(mp));
- agi->agi_level = cpu_to_be32(1);
- if (xfs_sb_version_hasfinobt(sbp)) {
- agi->agi_free_root = cpu_to_be32(XFS_FIBT_BLOCK(mp));
- agi->agi_free_level = cpu_to_be32(1);
- }
- agi->agi_freecount = 0;
- agi->agi_newino = cpu_to_be32(NULLAGINO);
- agi->agi_dirino = cpu_to_be32(NULLAGINO);
- if (xfs_sb_version_hascrc(sbp))
- platform_uuid_copy(&agi->agi_uuid, &sbp->sb_uuid);
- for (c = 0; c < XFS_AGI_UNLINKED_BUCKETS; c++)
- agi->agi_unlinked[c] = cpu_to_be32(NULLAGINO);
- libxfs_writebuf(buf, LIBXFS_EXIT_ON_FAILURE);
-
- /*
- * BNO btree root block
- */
- buf = libxfs_getbuf(mp->m_ddev_targp,
- XFS_AGB_TO_DADDR(mp, agno, XFS_BNO_BLOCK(mp)),
- BTOBB(cfg->blocksize));
- buf->b_ops = &xfs_allocbt_buf_ops;
- block = XFS_BUF_TO_BLOCK(buf);
- memset(block, 0, cfg->blocksize);
- libxfs_btree_init_block(mp, buf, XFS_BTNUM_BNO, 0, 1, agno, 0);
-
- arec = XFS_ALLOC_REC_ADDR(mp, block, 1);
- arec->ar_startblock = cpu_to_be32(libxfs_prealloc_blocks(mp));
- if (is_log_ag) {
- xfs_agblock_t start = XFS_FSB_TO_AGBNO(mp, cfg->logstart);
-
- ASSERT(start >= libxfs_prealloc_blocks(mp));
- if (start != libxfs_prealloc_blocks(mp)) {
- /*
- * Modify first record to pad stripe align of log
- */
- arec->ar_blockcount = cpu_to_be32(start -
- libxfs_prealloc_blocks(mp));
- nrec = arec + 1;
- /*
- * Insert second record at start of internal log
- * which then gets trimmed.
- */
- nrec->ar_startblock = cpu_to_be32(
- be32_to_cpu(arec->ar_startblock) +
- be32_to_cpu(arec->ar_blockcount));
- arec = nrec;
- be16_add_cpu(&block->bb_numrecs, 1);
- }
- /*
- * Change record start to after the internal log
- */
- be32_add_cpu(&arec->ar_startblock, cfg->logblocks);
- }
- /*
- * Calculate the record block count and check for the case where
- * the log might have consumed all available space in the AG. If
- * so, reset the record count to 0 to avoid exposure of an invalid
- * record start block.
- */
- arec->ar_blockcount = cpu_to_be32(agsize -
- be32_to_cpu(arec->ar_startblock));
- if (!arec->ar_blockcount)
- block->bb_numrecs = 0;
-
- libxfs_writebuf(buf, LIBXFS_EXIT_ON_FAILURE);
-
- /*
- * CNT btree root block
- */
- buf = libxfs_getbuf(mp->m_ddev_targp,
- XFS_AGB_TO_DADDR(mp, agno, XFS_CNT_BLOCK(mp)),
- BTOBB(cfg->blocksize));
- buf->b_ops = &xfs_allocbt_buf_ops;
- block = XFS_BUF_TO_BLOCK(buf);
- memset(block, 0, cfg->blocksize);
- libxfs_btree_init_block(mp, buf, XFS_BTNUM_CNT, 0, 1, agno, 0);
-
- arec = XFS_ALLOC_REC_ADDR(mp, block, 1);
- arec->ar_startblock = cpu_to_be32(libxfs_prealloc_blocks(mp));
- if (is_log_ag) {
- xfs_agblock_t start = XFS_FSB_TO_AGBNO(mp, cfg->logstart);
-
- ASSERT(start >= libxfs_prealloc_blocks(mp));
- if (start != libxfs_prealloc_blocks(mp)) {
- arec->ar_blockcount = cpu_to_be32(start -
- libxfs_prealloc_blocks(mp));
- nrec = arec + 1;
- nrec->ar_startblock = cpu_to_be32(
- be32_to_cpu(arec->ar_startblock) +
- be32_to_cpu(arec->ar_blockcount));
- arec = nrec;
- be16_add_cpu(&block->bb_numrecs, 1);
- }
- be32_add_cpu(&arec->ar_startblock, cfg->logblocks);
- }
- /*
- * Calculate the record block count and check for the case where
- * the log might have consumed all available space in the AG. If
- * so, reset the record count to 0 to avoid exposure of an invalid
- * record start block.
- */
- arec->ar_blockcount = cpu_to_be32(agsize -
- be32_to_cpu(arec->ar_startblock));
- if (!arec->ar_blockcount)
- block->bb_numrecs = 0;
-
- libxfs_writebuf(buf, LIBXFS_EXIT_ON_FAILURE);
-
- /*
- * refcount btree root block
- */
- if (xfs_sb_version_hasreflink(sbp)) {
- buf = libxfs_getbuf(mp->m_ddev_targp,
- XFS_AGB_TO_DADDR(mp, agno, libxfs_refc_block(mp)),
- BTOBB(cfg->blocksize));
- buf->b_ops = &xfs_refcountbt_buf_ops;
-
- block = XFS_BUF_TO_BLOCK(buf);
- memset(block, 0, cfg->blocksize);
- libxfs_btree_init_block(mp, buf, XFS_BTNUM_REFC, 0, 0, agno, 0);
- libxfs_writebuf(buf, LIBXFS_EXIT_ON_FAILURE);
- }
-
- /*
- * INO btree root block
- */
- buf = libxfs_getbuf(mp->m_ddev_targp,
- XFS_AGB_TO_DADDR(mp, agno, XFS_IBT_BLOCK(mp)),
- BTOBB(cfg->blocksize));
- buf->b_ops = &xfs_inobt_buf_ops;
- block = XFS_BUF_TO_BLOCK(buf);
- memset(block, 0, cfg->blocksize);
- libxfs_btree_init_block(mp, buf, XFS_BTNUM_INO, 0, 0, agno, 0);
- libxfs_writebuf(buf, LIBXFS_EXIT_ON_FAILURE);
-
- /*
- * Free INO btree root block
- */
- if (xfs_sb_version_hasfinobt(sbp)) {
- buf = libxfs_getbuf(mp->m_ddev_targp,
- XFS_AGB_TO_DADDR(mp, agno, XFS_FIBT_BLOCK(mp)),
- BTOBB(cfg->blocksize));
- buf->b_ops = &xfs_inobt_buf_ops;
- block = XFS_BUF_TO_BLOCK(buf);
- memset(block, 0, cfg->blocksize);
- libxfs_btree_init_block(mp, buf, XFS_BTNUM_FINO, 0, 0, agno, 0);
- libxfs_writebuf(buf, LIBXFS_EXIT_ON_FAILURE);
- }
-
- /* RMAP btree root block */
- if (xfs_sb_version_hasrmapbt(sbp)) {
- struct xfs_rmap_rec *rrec;
-
- buf = libxfs_getbuf(mp->m_ddev_targp,
- XFS_AGB_TO_DADDR(mp, agno, XFS_RMAP_BLOCK(mp)),
- BTOBB(cfg->blocksize));
- buf->b_ops = &xfs_rmapbt_buf_ops;
- block = XFS_BUF_TO_BLOCK(buf);
- memset(block, 0, cfg->blocksize);
-
- libxfs_btree_init_block(mp, buf, XFS_BTNUM_RMAP, 0, 0, agno, 0);
-
- /*
- * mark the AG header regions as static metadata
- * The BNO btree block is the first block after the
- * headers, so it's location defines the size of region
- * the static metadata consumes.
- */
- rrec = XFS_RMAP_REC_ADDR(block, 1);
- rrec->rm_startblock = 0;
- rrec->rm_blockcount = cpu_to_be32(XFS_BNO_BLOCK(mp));
- rrec->rm_owner = cpu_to_be64(XFS_RMAP_OWN_FS);
- rrec->rm_offset = 0;
- be16_add_cpu(&block->bb_numrecs, 1);
-
- /* account freespace btree root blocks */
- rrec = XFS_RMAP_REC_ADDR(block, 2);
- rrec->rm_startblock = cpu_to_be32(XFS_BNO_BLOCK(mp));
- rrec->rm_blockcount = cpu_to_be32(2);
- rrec->rm_owner = cpu_to_be64(XFS_RMAP_OWN_AG);
- rrec->rm_offset = 0;
- be16_add_cpu(&block->bb_numrecs, 1);
-
- /* account inode btree root blocks */
- rrec = XFS_RMAP_REC_ADDR(block, 3);
- rrec->rm_startblock = cpu_to_be32(XFS_IBT_BLOCK(mp));
- rrec->rm_blockcount = cpu_to_be32(XFS_RMAP_BLOCK(mp) -
- XFS_IBT_BLOCK(mp));
- rrec->rm_owner = cpu_to_be64(XFS_RMAP_OWN_INOBT);
- rrec->rm_offset = 0;
- be16_add_cpu(&block->bb_numrecs, 1);
-
- /* account for rmap btree root */
- rrec = XFS_RMAP_REC_ADDR(block, 4);
- rrec->rm_startblock = cpu_to_be32(XFS_RMAP_BLOCK(mp));
- rrec->rm_blockcount = cpu_to_be32(1);
- rrec->rm_owner = cpu_to_be64(XFS_RMAP_OWN_AG);
- rrec->rm_offset = 0;
- be16_add_cpu(&block->bb_numrecs, 1);
-
- /* account for refcount btree root */
- if (xfs_sb_version_hasreflink(sbp)) {
- rrec = XFS_RMAP_REC_ADDR(block, 5);
- rrec->rm_startblock = cpu_to_be32(libxfs_refc_block(mp));
- rrec->rm_blockcount = cpu_to_be32(1);
- rrec->rm_owner = cpu_to_be64(XFS_RMAP_OWN_REFC);
- rrec->rm_offset = 0;
- be16_add_cpu(&block->bb_numrecs, 1);
- }
-
- /* account for the log space */
- if (is_log_ag) {
- rrec = XFS_RMAP_REC_ADDR(block,
- be16_to_cpu(block->bb_numrecs) + 1);
- rrec->rm_startblock = cpu_to_be32(
- XFS_FSB_TO_AGBNO(mp, cfg->logstart));
- rrec->rm_blockcount = cpu_to_be32(cfg->logblocks);
- rrec->rm_owner = cpu_to_be64(XFS_RMAP_OWN_LOG);
- rrec->rm_offset = 0;
- be16_add_cpu(&block->bb_numrecs, 1);
- }
-
- libxfs_writebuf(buf, LIBXFS_EXIT_ON_FAILURE);
- }
-
libxfs_perag_put(pag);
}
{
struct xfs_alloc_arg args;
struct xfs_trans *tp;
- struct xfs_trans_res tres = {0};
int c;
- c = libxfs_trans_alloc(mp, &tres, worst_freelist, 0, 0, &tp);
+ c = -libxfs_trans_alloc_rollable(mp, worst_freelist, &tp);
if (c)
res_failed(c);
libxfs_alloc_fix_freelist(&args, 0);
libxfs_perag_put(args.pag);
- libxfs_trans_commit(tp);
+ c = -libxfs_trans_commit(tp);
+ if (c) {
+ errno = c;
+ perror(_("initializing AG free space list"));
+ exit(1);
+ }
}
/*
.crcs_enabled = true,
.dirftype = true,
.finobt = true,
- .spinodes = false,
+ .spinodes = true,
.rmapbt = false,
- .reflink = false,
+ .reflink = true,
.parent_pointers = false,
.nodalign = false,
.nortalign = false,
},
};
+ struct list_head buffer_list;
+
platform_uuid_generate(&cli.uuid);
progname = basename(argv[0]);
setlocale(LC_ALL, "");
cfg.rtblocks = calc_dev_size(cli.rtsize, &cfg, &ropts, R_SIZE, "rt");
validate_rtextsize(&cfg, &cli, &ft);
- calc_stripe_factors(&cfg, &cli, &ft);
/*
* Open and validate the device configurations
*/
- open_devices(&cfg, &xi, (discard && !dry_run));
+ open_devices(&cfg, &xi);
+ validate_overwrite(dfile, force_overwrite);
validate_datadev(&cfg, &cli);
validate_logdev(&cfg, &cli, &logfile);
validate_rtdev(&cfg, &cli, &rtfile);
+ calc_stripe_factors(&cfg, &cli, &ft);
/*
* At this point when know exactly what size all the devices are,
* 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);
/*
*/
calculate_log_size(&cfg, &cli, mp);
- protostring = setup_proto(protofile);
+ finish_superblock_setup(&cfg, mp, sbp);
+ /* Validate the extent size hints now that @mp is fully set up. */
+ validate_extsize_hint(mp, &cli);
+ validate_cowextsize_hint(mp, &cli);
+
+ /* Print the intended geometry of the fs. */
if (!quiet || dry_run) {
- print_mkfs_cfg(&cfg, dfile, logfile, rtfile);
+ struct xfs_fsop_geom geo;
+
+ libxfs_fs_geometry(sbp, &geo, XFS_FS_GEOM_MAX_STRUCT_VER);
+ xfs_report_geom(&geo, dfile, logfile, rtfile);
if (dry_run)
exit(0);
}
/*
- * Finish setting up the superblock state ready for formatting.
+ * All values have been validated, discard the old device layout.
*/
- setup_superblock(&cfg, mp, sbp);
+ if (discard && !dry_run)
+ discard_devices(&xi);
/*
* we need the libxfs buffer cache from here on in.
/*
* Initialise all the static on disk metadata.
*/
- for (agno = 0; agno < cfg.agcount; agno++)
- initialise_ag_headers(&cfg, mp, sbp, agno, &worst_freelist);
+ INIT_LIST_HEAD(&buffer_list);
+ for (agno = 0; agno < cfg.agcount; agno++) {
+ initialise_ag_headers(&cfg, mp, sbp, agno, &worst_freelist,
+ &buffer_list);
+
+ if (agno % 16)
+ continue;
+
+ if (libxfs_buf_delwri_submit(&buffer_list)) {
+ fprintf(stderr, _("%s: writing AG headers failed\n"),
+ progname);
+ exit(1);
+ }
+ }
+
+ if (libxfs_buf_delwri_submit(&buffer_list)) {
+ fprintf(stderr, _("%s: writing AG headers failed\n"),
+ progname);
+ exit(1);
+ }
/*
* Initialise the freespace freelists (i.e. AGFLs) in each AG.
/*
* Mark the filesystem ok.
*/
- buf = libxfs_getsb(mp, LIBXFS_EXIT_ON_FAILURE);
+ buf = libxfs_getsb(mp);
+ if (!buf || buf->b_error)
+ exit(1);
(XFS_BUF_TO_SBP(buf))->sb_inprogress = 0;
libxfs_writebuf(buf, LIBXFS_EXIT_ON_FAILURE);
if (xi.logdev && xi.logdev != xi.ddev)
libxfs_device_close(xi.logdev);
libxfs_device_close(xi.ddev);
+ libxfs_destroy();
return 0;
}