]>
Commit | Line | Data |
---|---|---|
959ef981 | 1 | // SPDX-License-Identifier: GPL-2.0 |
2bd0ea18 | 2 | /* |
da23017d NS |
3 | * Copyright (c) 2000-2005 Silicon Graphics, Inc. |
4 | * All Rights Reserved. | |
2bd0ea18 | 5 | */ |
660b5d96 | 6 | #include "libfrog/util.h" |
6b803e5a | 7 | #include "libxfs.h" |
e4da9941 | 8 | #include <ctype.h> |
4a32b9e9 | 9 | #include "xfs_multidisk.h" |
82c3a179 | 10 | #include "libxcmd.h" |
fee68490 | 11 | #include "libfrog/fsgeom.h" |
105041e6 | 12 | #include "libfrog/convert.h" |
ca14a570 | 13 | #include "libfrog/crc32cselftest.h" |
b9d29568 | 14 | #include "libfrog/dahashselftest.h" |
ec4e15fd | 15 | #include "proto.h" |
33c62516 | 16 | #include <ini.h> |
4eee66c5 DC |
17 | |
18 | #define TERABYTES(count, blog) ((uint64_t)(count) << (40 - (blog))) | |
19 | #define GIGABYTES(count, blog) ((uint64_t)(count) << (30 - (blog))) | |
20 | #define MEGABYTES(count, blog) ((uint64_t)(count) << (20 - (blog))) | |
21 | ||
cdfa467e ES |
22 | /* |
23 | * Realistically, the log should never be smaller than 64MB. Studies by the | |
24 | * kernel maintainer in early 2022 have shown a dramatic reduction in long tail | |
25 | * latency of the xlog grant head waitqueue when running a heavy metadata | |
26 | * update workload when the log size is at least 64MB. | |
27 | */ | |
28 | #define XFS_MIN_REALISTIC_LOG_BLOCKS(blog) (MEGABYTES(64, (blog))) | |
29 | ||
4eee66c5 DC |
30 | /* |
31 | * Use this macro before we have superblock and mount structure to | |
32 | * convert from basic blocks to filesystem blocks. | |
33 | */ | |
34 | #define DTOBT(d, bl) ((xfs_rfsblock_t)((d) >> ((bl) - BBSHIFT))) | |
35 | ||
36 | /* | |
37 | * amount (in bytes) we zero at the beginning and end of the device to | |
38 | * remove traces of other filesystems, raid superblocks, etc. | |
39 | */ | |
40 | #define WHACK_SIZE (128 * 1024) | |
41 | ||
627e74fd | 42 | /* |
b449c79e DC |
43 | * XXX: The configured block and sector sizes are defined as global variables so |
44 | * that they don't need to be passed to getnum/cvtnum(). | |
627e74fd | 45 | */ |
00ff2b10 ES |
46 | static unsigned int blocksize; |
47 | static unsigned int sectorsize; | |
627e74fd | 48 | |
64e924dd DC |
49 | /* |
50 | * Enums for each CLI parameter type are declared first so we can calculate the | |
51 | * maximum array size needed to hold them automatically. | |
52 | */ | |
53 | enum { | |
2cf637cf | 54 | B_SIZE = 0, |
64e924dd DC |
55 | B_MAX_OPTS, |
56 | }; | |
57 | ||
33c62516 DC |
58 | enum { |
59 | C_OPTFILE = 0, | |
60 | C_MAX_OPTS, | |
61 | }; | |
62 | ||
64e924dd DC |
63 | enum { |
64 | D_AGCOUNT = 0, | |
65 | D_FILE, | |
66 | D_NAME, | |
67 | D_SIZE, | |
68 | D_SUNIT, | |
69 | D_SWIDTH, | |
70 | D_AGSIZE, | |
71 | D_SU, | |
72 | D_SW, | |
64e924dd DC |
73 | D_SECTSIZE, |
74 | D_NOALIGN, | |
75 | D_RTINHERIT, | |
76 | D_PROJINHERIT, | |
77 | D_EXTSZINHERIT, | |
78 | D_COWEXTSIZE, | |
64989ff3 | 79 | D_DAXINHERIT, |
64e924dd DC |
80 | D_MAX_OPTS, |
81 | }; | |
82 | ||
83 | enum { | |
84 | I_ALIGN = 0, | |
64e924dd DC |
85 | I_MAXPCT, |
86 | I_PERBLOCK, | |
87 | I_SIZE, | |
88 | I_ATTR, | |
89 | I_PROJID32BIT, | |
90 | I_SPINODES, | |
69e72722 | 91 | I_NREXT64, |
64e924dd DC |
92 | I_MAX_OPTS, |
93 | }; | |
94 | ||
95 | enum { | |
96 | L_AGNUM = 0, | |
97 | L_INTERNAL, | |
98 | L_SIZE, | |
99 | L_VERSION, | |
100 | L_SUNIT, | |
101 | L_SU, | |
102 | L_DEV, | |
64e924dd DC |
103 | L_SECTSIZE, |
104 | L_FILE, | |
105 | L_NAME, | |
106 | L_LAZYSBCNTR, | |
107 | L_MAX_OPTS, | |
108 | }; | |
109 | ||
110 | enum { | |
2cf637cf | 111 | N_SIZE = 0, |
64e924dd DC |
112 | N_VERSION, |
113 | N_FTYPE, | |
114 | N_MAX_OPTS, | |
115 | }; | |
116 | ||
fb22e1b1 DW |
117 | enum { |
118 | P_FILE = 0, | |
e0aeb058 | 119 | P_SLASHES, |
fb22e1b1 DW |
120 | P_MAX_OPTS, |
121 | }; | |
122 | ||
64e924dd DC |
123 | enum { |
124 | R_EXTSIZE = 0, | |
125 | R_SIZE, | |
126 | R_DEV, | |
127 | R_FILE, | |
128 | R_NAME, | |
129 | R_NOALIGN, | |
130 | R_MAX_OPTS, | |
131 | }; | |
132 | ||
133 | enum { | |
2cf637cf | 134 | S_SIZE = 0, |
64e924dd DC |
135 | S_SECTSIZE, |
136 | S_MAX_OPTS, | |
137 | }; | |
138 | ||
139 | enum { | |
140 | M_CRC = 0, | |
141 | M_FINOBT, | |
142 | M_UUID, | |
143 | M_RMAPBT, | |
144 | M_REFLINK, | |
9eb0d6eb | 145 | M_INOBTCNT, |
e9601810 | 146 | M_BIGTIME, |
64e924dd DC |
147 | M_MAX_OPTS, |
148 | }; | |
149 | ||
50dba818 DW |
150 | /* |
151 | * Just define the max options array size manually to the largest | |
152 | * enum right now, leaving room for a NULL terminator at the end | |
153 | */ | |
154 | #define MAX_SUBOPTS (D_MAX_OPTS + 1) | |
64e924dd | 155 | |
56e4d368 | 156 | #define SUBOPT_NEEDS_VAL (-1LL) |
3ec1956a DC |
157 | #define MAX_CONFLICTS 8 |
158 | #define LAST_CONFLICT (-1) | |
159 | ||
2bd0ea18 | 160 | /* |
a9dad670 DC |
161 | * Table for parsing mkfs parameters. |
162 | * | |
163 | * Description of the structure members follows: | |
164 | * | |
165 | * name MANDATORY | |
166 | * Name is a single char, e.g., for '-d file', name is 'd'. | |
167 | * | |
ab2eef12 DC |
168 | * ini_section MANDATORY |
169 | * This field is required to connect each opt_params (that is to say, each | |
170 | * option class) to a section in the config file. The only option class this | |
171 | * is not required for is the config file specification class itself. | |
172 | * The section name is a string, not longer than MAX_INI_NAME_LEN. | |
173 | * | |
a9dad670 DC |
174 | * subopts MANDATORY |
175 | * Subopts is a list of strings naming suboptions. In the example above, | |
176 | * it would contain "file". The last entry of this list has to be NULL. | |
177 | * | |
178 | * subopt_params MANDATORY | |
179 | * This is a list of structs tied with subopts. For each entry in subopts, | |
180 | * a corresponding entry has to be defined: | |
181 | * | |
182 | * subopt_params struct: | |
183 | * index MANDATORY | |
184 | * This number, starting from zero, denotes which item in subopt_params | |
185 | * it is. The index has to be the same as is the order in subopts list, | |
186 | * so we can access the right item both in subopt_param and subopts. | |
187 | * | |
9090e187 DC |
188 | * seen INTERNAL |
189 | * Do not set this flag when definning a subopt. It is used to remeber that | |
190 | * this subopt was already seen, for example for conflicts detection. | |
191 | * | |
27ae3a59 DC |
192 | * str_seen INTERNAL |
193 | * Do not set. It is used internally for respecification, when some options | |
194 | * has to be parsed twice - at first as a string, then later as a number. | |
195 | * | |
627e74fd DC |
196 | * convert OPTIONAL |
197 | * A flag signalling whether the user-given value can use suffixes. | |
198 | * If you want to allow the use of user-friendly values like 13k, 42G, | |
199 | * set it to true. | |
200 | * | |
201 | * is_power_2 OPTIONAL | |
202 | * An optional flag for subopts where the given value has to be a power | |
203 | * of two. | |
204 | * | |
3ec1956a DC |
205 | * conflicts MANDATORY |
206 | * If your subopt is in a conflict with some other option, specify it. | |
207 | * Accepts the .index values of the conflicting subopts and the last | |
208 | * member of this list has to be LAST_CONFLICT. | |
209 | * | |
a9dad670 DC |
210 | * minval, maxval OPTIONAL |
211 | * These options are used for automatic range check and they have to be | |
212 | * always used together in pair. If you don't want to limit the max value, | |
213 | * use something like UINT_MAX. If no value is given, then you must either | |
214 | * supply your own validation, or refuse any value in the 'case | |
215 | * X_SOMETHING' block. If you forget to define the min and max value, but | |
216 | * call a standard function for validating user's value, it will cause an | |
217 | * error message notifying you about this issue. | |
218 | * | |
219 | * (Said in another way, you can't have minval and maxval both equal | |
220 | * to zero. But if one value is different: minval=0 and maxval=1, | |
221 | * then it is OK.) | |
56e4d368 DC |
222 | * |
223 | * defaultval MANDATORY | |
224 | * The value used if user specifies the subopt, but no value. | |
225 | * If the subopt accepts some values (-d file=[1|0]), then this | |
226 | * sets what is used with simple specifying the subopt (-d file). | |
227 | * A special SUBOPT_NEEDS_VAL can be used to require a user-given | |
228 | * value in any case. | |
2bd0ea18 | 229 | */ |
a9dad670 DC |
230 | struct opt_params { |
231 | const char name; | |
ab2eef12 DC |
232 | #define MAX_INI_NAME_LEN 32 |
233 | const char ini_section[MAX_INI_NAME_LEN]; | |
a9dad670 | 234 | const char *subopts[MAX_SUBOPTS]; |
9090e187 | 235 | |
a9dad670 DC |
236 | struct subopt_param { |
237 | int index; | |
9090e187 | 238 | bool seen; |
27ae3a59 | 239 | bool str_seen; |
627e74fd DC |
240 | bool convert; |
241 | bool is_power_2; | |
cedf1c43 DC |
242 | struct _conflict { |
243 | struct opt_params *opts; | |
244 | int subopt; | |
245 | } conflicts[MAX_CONFLICTS]; | |
a9dad670 DC |
246 | long long minval; |
247 | long long maxval; | |
56e4d368 | 248 | long long defaultval; |
a9dad670 DC |
249 | } subopt_params[MAX_SUBOPTS]; |
250 | }; | |
251 | ||
6c75555e DC |
252 | /* |
253 | * The two dimensional conflict array requires some initialisations to know | |
254 | * about tables that haven't yet been defined. Work around this ordering | |
255 | * issue with extern definitions here. | |
256 | */ | |
00ff2b10 | 257 | static struct opt_params sopts; |
6c75555e | 258 | |
00ff2b10 | 259 | static struct opt_params bopts = { |
a9dad670 | 260 | .name = 'b', |
ab2eef12 | 261 | .ini_section = "block", |
a9dad670 | 262 | .subopts = { |
64e924dd | 263 | [B_SIZE] = "size", |
50dba818 | 264 | [B_MAX_OPTS] = NULL, |
a9dad670 DC |
265 | }, |
266 | .subopt_params = { | |
a9dad670 | 267 | { .index = B_SIZE, |
627e74fd DC |
268 | .convert = true, |
269 | .is_power_2 = true, | |
2cf637cf | 270 | .conflicts = { { NULL, LAST_CONFLICT } }, |
a9dad670 DC |
271 | .minval = XFS_MIN_BLOCKSIZE, |
272 | .maxval = XFS_MAX_BLOCKSIZE, | |
56e4d368 | 273 | .defaultval = SUBOPT_NEEDS_VAL, |
a9dad670 DC |
274 | }, |
275 | }, | |
2bd0ea18 NS |
276 | }; |
277 | ||
33c62516 DC |
278 | /* |
279 | * Config file specification. Usage is: | |
280 | * | |
281 | * mkfs.xfs -c options=<name> | |
282 | * | |
283 | * A subopt is used for the filename so in future we can extend the behaviour | |
284 | * of the config file (e.g. specified defaults rather than options) if we ever | |
285 | * have a need to do that sort of thing. | |
286 | */ | |
287 | static struct opt_params copts = { | |
288 | .name = 'c', | |
289 | .subopts = { | |
290 | [C_OPTFILE] = "options", | |
50dba818 | 291 | [C_MAX_OPTS] = NULL, |
33c62516 DC |
292 | }, |
293 | .subopt_params = { | |
294 | { .index = C_OPTFILE, | |
295 | .conflicts = { { NULL, LAST_CONFLICT } }, | |
296 | .defaultval = SUBOPT_NEEDS_VAL, | |
297 | }, | |
298 | }, | |
299 | }; | |
300 | ||
00ff2b10 | 301 | static struct opt_params dopts = { |
a9dad670 | 302 | .name = 'd', |
ab2eef12 | 303 | .ini_section = "data", |
a9dad670 | 304 | .subopts = { |
64e924dd DC |
305 | [D_AGCOUNT] = "agcount", |
306 | [D_FILE] = "file", | |
307 | [D_NAME] = "name", | |
308 | [D_SIZE] = "size", | |
309 | [D_SUNIT] = "sunit", | |
310 | [D_SWIDTH] = "swidth", | |
311 | [D_AGSIZE] = "agsize", | |
312 | [D_SU] = "su", | |
313 | [D_SW] = "sw", | |
64e924dd DC |
314 | [D_SECTSIZE] = "sectsize", |
315 | [D_NOALIGN] = "noalign", | |
316 | [D_RTINHERIT] = "rtinherit", | |
317 | [D_PROJINHERIT] = "projinherit", | |
318 | [D_EXTSZINHERIT] = "extszinherit", | |
319 | [D_COWEXTSIZE] = "cowextsize", | |
64989ff3 | 320 | [D_DAXINHERIT] = "daxinherit", |
50dba818 | 321 | [D_MAX_OPTS] = NULL, |
a9dad670 DC |
322 | }, |
323 | .subopt_params = { | |
324 | { .index = D_AGCOUNT, | |
cedf1c43 DC |
325 | .conflicts = { { &dopts, D_AGSIZE }, |
326 | { NULL, LAST_CONFLICT } }, | |
1974d3f1 DC |
327 | .minval = 1, |
328 | .maxval = XFS_MAX_AGNUMBER, | |
56e4d368 | 329 | .defaultval = SUBOPT_NEEDS_VAL, |
a9dad670 DC |
330 | }, |
331 | { .index = D_FILE, | |
cedf1c43 | 332 | .conflicts = { { NULL, LAST_CONFLICT } }, |
56e4d368 DC |
333 | .minval = 0, |
334 | .maxval = 1, | |
335 | .defaultval = 1, | |
a9dad670 DC |
336 | }, |
337 | { .index = D_NAME, | |
cedf1c43 | 338 | .conflicts = { { NULL, LAST_CONFLICT } }, |
56e4d368 | 339 | .defaultval = SUBOPT_NEEDS_VAL, |
a9dad670 DC |
340 | }, |
341 | { .index = D_SIZE, | |
cedf1c43 | 342 | .conflicts = { { NULL, LAST_CONFLICT } }, |
627e74fd DC |
343 | .convert = true, |
344 | .minval = XFS_AG_MIN_BYTES, | |
345 | .maxval = LLONG_MAX, | |
56e4d368 | 346 | .defaultval = SUBOPT_NEEDS_VAL, |
a9dad670 DC |
347 | }, |
348 | { .index = D_SUNIT, | |
cedf1c43 DC |
349 | .conflicts = { { &dopts, D_NOALIGN }, |
350 | { &dopts, D_SU }, | |
351 | { &dopts, D_SW }, | |
352 | { NULL, LAST_CONFLICT } }, | |
1974d3f1 DC |
353 | .minval = 0, |
354 | .maxval = UINT_MAX, | |
56e4d368 | 355 | .defaultval = SUBOPT_NEEDS_VAL, |
a9dad670 DC |
356 | }, |
357 | { .index = D_SWIDTH, | |
cedf1c43 DC |
358 | .conflicts = { { &dopts, D_NOALIGN }, |
359 | { &dopts, D_SU }, | |
360 | { &dopts, D_SW }, | |
361 | { NULL, LAST_CONFLICT } }, | |
1974d3f1 DC |
362 | .minval = 0, |
363 | .maxval = UINT_MAX, | |
56e4d368 | 364 | .defaultval = SUBOPT_NEEDS_VAL, |
a9dad670 DC |
365 | }, |
366 | { .index = D_AGSIZE, | |
cedf1c43 DC |
367 | .conflicts = { { &dopts, D_AGCOUNT }, |
368 | { NULL, LAST_CONFLICT } }, | |
627e74fd | 369 | .convert = true, |
1974d3f1 DC |
370 | .minval = XFS_AG_MIN_BYTES, |
371 | .maxval = XFS_AG_MAX_BYTES, | |
56e4d368 | 372 | .defaultval = SUBOPT_NEEDS_VAL, |
a9dad670 DC |
373 | }, |
374 | { .index = D_SU, | |
cedf1c43 DC |
375 | .conflicts = { { &dopts, D_NOALIGN }, |
376 | { &dopts, D_SUNIT }, | |
377 | { &dopts, D_SWIDTH }, | |
378 | { NULL, LAST_CONFLICT } }, | |
627e74fd DC |
379 | .convert = true, |
380 | .minval = 0, | |
381 | .maxval = UINT_MAX, | |
56e4d368 | 382 | .defaultval = SUBOPT_NEEDS_VAL, |
a9dad670 DC |
383 | }, |
384 | { .index = D_SW, | |
cedf1c43 DC |
385 | .conflicts = { { &dopts, D_NOALIGN }, |
386 | { &dopts, D_SUNIT }, | |
387 | { &dopts, D_SWIDTH }, | |
388 | { NULL, LAST_CONFLICT } }, | |
1974d3f1 DC |
389 | .minval = 0, |
390 | .maxval = UINT_MAX, | |
56e4d368 | 391 | .defaultval = SUBOPT_NEEDS_VAL, |
a9dad670 | 392 | }, |
a9dad670 | 393 | { .index = D_SECTSIZE, |
2cf637cf | 394 | .conflicts = { { &sopts, S_SIZE }, |
6c75555e | 395 | { &sopts, S_SECTSIZE }, |
cedf1c43 | 396 | { NULL, LAST_CONFLICT } }, |
627e74fd DC |
397 | .convert = true, |
398 | .is_power_2 = true, | |
a9dad670 DC |
399 | .minval = XFS_MIN_SECTORSIZE, |
400 | .maxval = XFS_MAX_SECTORSIZE, | |
56e4d368 | 401 | .defaultval = SUBOPT_NEEDS_VAL, |
a9dad670 DC |
402 | }, |
403 | { .index = D_NOALIGN, | |
cedf1c43 DC |
404 | .conflicts = { { &dopts, D_SU }, |
405 | { &dopts, D_SW }, | |
406 | { &dopts, D_SUNIT }, | |
407 | { &dopts, D_SWIDTH }, | |
408 | { NULL, LAST_CONFLICT } }, | |
56e4d368 DC |
409 | .minval = 0, |
410 | .maxval = 1, | |
411 | .defaultval = 1, | |
a9dad670 DC |
412 | }, |
413 | { .index = D_RTINHERIT, | |
cedf1c43 | 414 | .conflicts = { { NULL, LAST_CONFLICT } }, |
9c7e941b | 415 | .minval = 0, |
1974d3f1 DC |
416 | .maxval = 1, |
417 | .defaultval = 1, | |
a9dad670 DC |
418 | }, |
419 | { .index = D_PROJINHERIT, | |
cedf1c43 | 420 | .conflicts = { { NULL, LAST_CONFLICT } }, |
1974d3f1 DC |
421 | .minval = 0, |
422 | .maxval = UINT_MAX, | |
56e4d368 | 423 | .defaultval = SUBOPT_NEEDS_VAL, |
a9dad670 DC |
424 | }, |
425 | { .index = D_EXTSZINHERIT, | |
cedf1c43 | 426 | .conflicts = { { NULL, LAST_CONFLICT } }, |
1974d3f1 DC |
427 | .minval = 0, |
428 | .maxval = UINT_MAX, | |
56e4d368 | 429 | .defaultval = SUBOPT_NEEDS_VAL, |
a9dad670 | 430 | }, |
06b80354 | 431 | { .index = D_COWEXTSIZE, |
cedf1c43 | 432 | .conflicts = { { NULL, LAST_CONFLICT } }, |
06b80354 DW |
433 | .minval = 0, |
434 | .maxval = UINT_MAX, | |
435 | .defaultval = SUBOPT_NEEDS_VAL, | |
436 | }, | |
64989ff3 DW |
437 | { .index = D_DAXINHERIT, |
438 | .conflicts = { { NULL, LAST_CONFLICT } }, | |
439 | .minval = 0, | |
440 | .maxval = 1, | |
441 | .defaultval = 1, | |
442 | }, | |
a9dad670 | 443 | }, |
2bd0ea18 NS |
444 | }; |
445 | ||
a9dad670 | 446 | |
00ff2b10 | 447 | static struct opt_params iopts = { |
a9dad670 | 448 | .name = 'i', |
ab2eef12 | 449 | .ini_section = "inode", |
a9dad670 | 450 | .subopts = { |
64e924dd | 451 | [I_ALIGN] = "align", |
64e924dd DC |
452 | [I_MAXPCT] = "maxpct", |
453 | [I_PERBLOCK] = "perblock", | |
454 | [I_SIZE] = "size", | |
455 | [I_ATTR] = "attr", | |
456 | [I_PROJID32BIT] = "projid32bit", | |
457 | [I_SPINODES] = "sparse", | |
69e72722 | 458 | [I_NREXT64] = "nrext64", |
50dba818 | 459 | [I_MAX_OPTS] = NULL, |
a9dad670 DC |
460 | }, |
461 | .subopt_params = { | |
462 | { .index = I_ALIGN, | |
cedf1c43 | 463 | .conflicts = { { NULL, LAST_CONFLICT } }, |
56e4d368 DC |
464 | .minval = 0, |
465 | .maxval = 1, | |
466 | .defaultval = 1, | |
a9dad670 | 467 | }, |
a9dad670 | 468 | { .index = I_MAXPCT, |
cedf1c43 | 469 | .conflicts = { { NULL, LAST_CONFLICT } }, |
1974d3f1 DC |
470 | .minval = 0, |
471 | .maxval = 100, | |
56e4d368 | 472 | .defaultval = SUBOPT_NEEDS_VAL, |
a9dad670 DC |
473 | }, |
474 | { .index = I_PERBLOCK, | |
2cf637cf | 475 | .conflicts = { { &iopts, I_SIZE }, |
cedf1c43 | 476 | { NULL, LAST_CONFLICT } }, |
627e74fd | 477 | .is_power_2 = true, |
1974d3f1 DC |
478 | .minval = XFS_MIN_INODE_PERBLOCK, |
479 | .maxval = XFS_MAX_BLOCKSIZE / XFS_DINODE_MIN_SIZE, | |
56e4d368 | 480 | .defaultval = SUBOPT_NEEDS_VAL, |
a9dad670 DC |
481 | }, |
482 | { .index = I_SIZE, | |
cedf1c43 | 483 | .conflicts = { { &iopts, I_PERBLOCK }, |
cedf1c43 | 484 | { NULL, LAST_CONFLICT } }, |
627e74fd | 485 | .is_power_2 = true, |
1974d3f1 DC |
486 | .minval = XFS_DINODE_MIN_SIZE, |
487 | .maxval = XFS_DINODE_MAX_SIZE, | |
56e4d368 | 488 | .defaultval = SUBOPT_NEEDS_VAL, |
a9dad670 DC |
489 | }, |
490 | { .index = I_ATTR, | |
cedf1c43 | 491 | .conflicts = { { NULL, LAST_CONFLICT } }, |
1974d3f1 DC |
492 | .minval = 0, |
493 | .maxval = 2, | |
56e4d368 | 494 | .defaultval = SUBOPT_NEEDS_VAL, |
a9dad670 DC |
495 | }, |
496 | { .index = I_PROJID32BIT, | |
cedf1c43 | 497 | .conflicts = { { NULL, LAST_CONFLICT } }, |
56e4d368 DC |
498 | .minval = 0, |
499 | .maxval = 1, | |
500 | .defaultval = 1, | |
a9dad670 DC |
501 | }, |
502 | { .index = I_SPINODES, | |
cedf1c43 | 503 | .conflicts = { { NULL, LAST_CONFLICT } }, |
56e4d368 DC |
504 | .minval = 0, |
505 | .maxval = 1, | |
506 | .defaultval = 1, | |
a9dad670 | 507 | }, |
69e72722 CB |
508 | { .index = I_NREXT64, |
509 | .conflicts = { { NULL, LAST_CONFLICT } }, | |
510 | .minval = 0, | |
511 | .maxval = 1, | |
512 | .defaultval = 1, | |
513 | } | |
a9dad670 | 514 | }, |
2bd0ea18 NS |
515 | }; |
516 | ||
00ff2b10 | 517 | static struct opt_params lopts = { |
a9dad670 | 518 | .name = 'l', |
ab2eef12 | 519 | .ini_section = "log", |
a9dad670 | 520 | .subopts = { |
64e924dd DC |
521 | [L_AGNUM] = "agnum", |
522 | [L_INTERNAL] = "internal", | |
523 | [L_SIZE] = "size", | |
524 | [L_VERSION] = "version", | |
525 | [L_SUNIT] = "sunit", | |
526 | [L_SU] = "su", | |
527 | [L_DEV] = "logdev", | |
64e924dd DC |
528 | [L_SECTSIZE] = "sectsize", |
529 | [L_FILE] = "file", | |
530 | [L_NAME] = "name", | |
531 | [L_LAZYSBCNTR] = "lazy-count", | |
50dba818 | 532 | [L_MAX_OPTS] = NULL, |
a9dad670 DC |
533 | }, |
534 | .subopt_params = { | |
535 | { .index = L_AGNUM, | |
cedf1c43 DC |
536 | .conflicts = { { &lopts, L_DEV }, |
537 | { NULL, LAST_CONFLICT } }, | |
1974d3f1 DC |
538 | .minval = 0, |
539 | .maxval = UINT_MAX, | |
56e4d368 | 540 | .defaultval = SUBOPT_NEEDS_VAL, |
a9dad670 DC |
541 | }, |
542 | { .index = L_INTERNAL, | |
cedf1c43 DC |
543 | .conflicts = { { &lopts, L_FILE }, |
544 | { &lopts, L_DEV }, | |
cedf1c43 DC |
545 | { &lopts, L_SECTSIZE }, |
546 | { NULL, LAST_CONFLICT } }, | |
56e4d368 DC |
547 | .minval = 0, |
548 | .maxval = 1, | |
549 | .defaultval = 1, | |
a9dad670 DC |
550 | }, |
551 | { .index = L_SIZE, | |
cedf1c43 | 552 | .conflicts = { { NULL, LAST_CONFLICT } }, |
627e74fd DC |
553 | .convert = true, |
554 | .minval = 2 * 1024 * 1024LL, /* XXX: XFS_MIN_LOG_BYTES */ | |
555 | .maxval = XFS_MAX_LOG_BYTES, | |
56e4d368 | 556 | .defaultval = SUBOPT_NEEDS_VAL, |
a9dad670 DC |
557 | }, |
558 | { .index = L_VERSION, | |
cedf1c43 | 559 | .conflicts = { { NULL, LAST_CONFLICT } }, |
1974d3f1 DC |
560 | .minval = 1, |
561 | .maxval = 2, | |
56e4d368 | 562 | .defaultval = SUBOPT_NEEDS_VAL, |
a9dad670 DC |
563 | }, |
564 | { .index = L_SUNIT, | |
cedf1c43 DC |
565 | .conflicts = { { &lopts, L_SU }, |
566 | { NULL, LAST_CONFLICT } }, | |
2942ff49 | 567 | .minval = 1, |
1974d3f1 | 568 | .maxval = BTOBB(XLOG_MAX_RECORD_BSIZE), |
56e4d368 | 569 | .defaultval = SUBOPT_NEEDS_VAL, |
a9dad670 DC |
570 | }, |
571 | { .index = L_SU, | |
cedf1c43 DC |
572 | .conflicts = { { &lopts, L_SUNIT }, |
573 | { NULL, LAST_CONFLICT } }, | |
627e74fd | 574 | .convert = true, |
2942ff49 | 575 | .minval = BBTOB(1), |
627e74fd | 576 | .maxval = XLOG_MAX_RECORD_BSIZE, |
56e4d368 | 577 | .defaultval = SUBOPT_NEEDS_VAL, |
a9dad670 DC |
578 | }, |
579 | { .index = L_DEV, | |
cedf1c43 | 580 | .conflicts = { { &lopts, L_AGNUM }, |
9502da21 | 581 | { &lopts, L_NAME }, |
cedf1c43 DC |
582 | { &lopts, L_INTERNAL }, |
583 | { NULL, LAST_CONFLICT } }, | |
56e4d368 | 584 | .defaultval = SUBOPT_NEEDS_VAL, |
a9dad670 | 585 | }, |
a9dad670 | 586 | { .index = L_SECTSIZE, |
2cf637cf | 587 | .conflicts = { { &lopts, L_INTERNAL }, |
cedf1c43 | 588 | { NULL, LAST_CONFLICT } }, |
627e74fd DC |
589 | .convert = true, |
590 | .is_power_2 = true, | |
a9dad670 DC |
591 | .minval = XFS_MIN_SECTORSIZE, |
592 | .maxval = XFS_MAX_SECTORSIZE, | |
56e4d368 | 593 | .defaultval = SUBOPT_NEEDS_VAL, |
a9dad670 DC |
594 | }, |
595 | { .index = L_FILE, | |
cedf1c43 DC |
596 | .conflicts = { { &lopts, L_INTERNAL }, |
597 | { NULL, LAST_CONFLICT } }, | |
56e4d368 DC |
598 | .minval = 0, |
599 | .maxval = 1, | |
600 | .defaultval = 1, | |
a9dad670 DC |
601 | }, |
602 | { .index = L_NAME, | |
cedf1c43 | 603 | .conflicts = { { &lopts, L_AGNUM }, |
9502da21 | 604 | { &lopts, L_DEV }, |
cedf1c43 DC |
605 | { &lopts, L_INTERNAL }, |
606 | { NULL, LAST_CONFLICT } }, | |
56e4d368 | 607 | .defaultval = SUBOPT_NEEDS_VAL, |
a9dad670 DC |
608 | }, |
609 | { .index = L_LAZYSBCNTR, | |
cedf1c43 | 610 | .conflicts = { { NULL, LAST_CONFLICT } }, |
56e4d368 DC |
611 | .minval = 0, |
612 | .maxval = 1, | |
613 | .defaultval = 1, | |
a9dad670 DC |
614 | }, |
615 | }, | |
2bd0ea18 NS |
616 | }; |
617 | ||
00ff2b10 | 618 | static struct opt_params nopts = { |
a9dad670 | 619 | .name = 'n', |
ab2eef12 | 620 | .ini_section = "naming", |
a9dad670 | 621 | .subopts = { |
64e924dd DC |
622 | [N_SIZE] = "size", |
623 | [N_VERSION] = "version", | |
624 | [N_FTYPE] = "ftype", | |
50dba818 | 625 | [N_MAX_OPTS] = NULL, |
a9dad670 DC |
626 | }, |
627 | .subopt_params = { | |
a9dad670 | 628 | { .index = N_SIZE, |
2cf637cf | 629 | .conflicts = { { NULL, LAST_CONFLICT } }, |
627e74fd DC |
630 | .convert = true, |
631 | .is_power_2 = true, | |
a9dad670 DC |
632 | .minval = 1 << XFS_MIN_REC_DIRSIZE, |
633 | .maxval = XFS_MAX_BLOCKSIZE, | |
56e4d368 | 634 | .defaultval = SUBOPT_NEEDS_VAL, |
a9dad670 DC |
635 | }, |
636 | { .index = N_VERSION, | |
cedf1c43 | 637 | .conflicts = { { NULL, LAST_CONFLICT } }, |
1974d3f1 DC |
638 | .minval = 2, |
639 | .maxval = 2, | |
56e4d368 | 640 | .defaultval = SUBOPT_NEEDS_VAL, |
a9dad670 DC |
641 | }, |
642 | { .index = N_FTYPE, | |
cedf1c43 | 643 | .conflicts = { { NULL, LAST_CONFLICT } }, |
56e4d368 DC |
644 | .minval = 0, |
645 | .maxval = 1, | |
646 | .defaultval = 1, | |
a9dad670 DC |
647 | }, |
648 | }, | |
2bd0ea18 NS |
649 | }; |
650 | ||
fb22e1b1 DW |
651 | static struct opt_params popts = { |
652 | .name = 'p', | |
653 | .ini_section = "proto", | |
654 | .subopts = { | |
655 | [P_FILE] = "file", | |
e0aeb058 | 656 | [P_SLASHES] = "slashes_are_spaces", |
fb22e1b1 DW |
657 | [P_MAX_OPTS] = NULL, |
658 | }, | |
659 | .subopt_params = { | |
660 | { .index = P_FILE, | |
661 | .conflicts = { { NULL, LAST_CONFLICT } }, | |
662 | .defaultval = SUBOPT_NEEDS_VAL, | |
663 | }, | |
e0aeb058 DW |
664 | { .index = P_SLASHES, |
665 | .conflicts = { { NULL, LAST_CONFLICT } }, | |
666 | .minval = 0, | |
667 | .maxval = 1, | |
668 | .defaultval = 1, | |
669 | }, | |
fb22e1b1 DW |
670 | }, |
671 | }; | |
672 | ||
00ff2b10 | 673 | static struct opt_params ropts = { |
a9dad670 | 674 | .name = 'r', |
ab2eef12 | 675 | .ini_section = "realtime", |
a9dad670 | 676 | .subopts = { |
64e924dd DC |
677 | [R_EXTSIZE] = "extsize", |
678 | [R_SIZE] = "size", | |
679 | [R_DEV] = "rtdev", | |
680 | [R_FILE] = "file", | |
681 | [R_NAME] = "name", | |
682 | [R_NOALIGN] = "noalign", | |
50dba818 | 683 | [R_MAX_OPTS] = NULL, |
a9dad670 DC |
684 | }, |
685 | .subopt_params = { | |
686 | { .index = R_EXTSIZE, | |
cedf1c43 | 687 | .conflicts = { { NULL, LAST_CONFLICT } }, |
627e74fd DC |
688 | .convert = true, |
689 | .minval = XFS_MIN_RTEXTSIZE, | |
690 | .maxval = XFS_MAX_RTEXTSIZE, | |
56e4d368 | 691 | .defaultval = SUBOPT_NEEDS_VAL, |
a9dad670 DC |
692 | }, |
693 | { .index = R_SIZE, | |
cedf1c43 | 694 | .conflicts = { { NULL, LAST_CONFLICT } }, |
627e74fd DC |
695 | .convert = true, |
696 | .minval = 0, | |
697 | .maxval = LLONG_MAX, | |
56e4d368 | 698 | .defaultval = SUBOPT_NEEDS_VAL, |
a9dad670 DC |
699 | }, |
700 | { .index = R_DEV, | |
9502da21 ES |
701 | .conflicts = { { &ropts, R_NAME }, |
702 | { NULL, LAST_CONFLICT } }, | |
56e4d368 | 703 | .defaultval = SUBOPT_NEEDS_VAL, |
a9dad670 DC |
704 | }, |
705 | { .index = R_FILE, | |
56e4d368 DC |
706 | .minval = 0, |
707 | .maxval = 1, | |
708 | .defaultval = 1, | |
cedf1c43 | 709 | .conflicts = { { NULL, LAST_CONFLICT } }, |
a9dad670 DC |
710 | }, |
711 | { .index = R_NAME, | |
9502da21 ES |
712 | .conflicts = { { &ropts, R_DEV }, |
713 | { NULL, LAST_CONFLICT } }, | |
56e4d368 | 714 | .defaultval = SUBOPT_NEEDS_VAL, |
a9dad670 DC |
715 | }, |
716 | { .index = R_NOALIGN, | |
56e4d368 DC |
717 | .minval = 0, |
718 | .maxval = 1, | |
719 | .defaultval = 1, | |
cedf1c43 | 720 | .conflicts = { { NULL, LAST_CONFLICT } }, |
a9dad670 DC |
721 | }, |
722 | }, | |
2bd0ea18 NS |
723 | }; |
724 | ||
00ff2b10 | 725 | static struct opt_params sopts = { |
a9dad670 | 726 | .name = 's', |
ab2eef12 | 727 | .ini_section = "sector", |
a9dad670 | 728 | .subopts = { |
64e924dd DC |
729 | [S_SIZE] = "size", |
730 | [S_SECTSIZE] = "sectsize", | |
50dba818 | 731 | [S_MAX_OPTS] = NULL, |
a9dad670 DC |
732 | }, |
733 | .subopt_params = { | |
a9dad670 | 734 | { .index = S_SIZE, |
2cf637cf | 735 | .conflicts = { { &sopts, S_SECTSIZE }, |
6c75555e | 736 | { &dopts, D_SECTSIZE }, |
cedf1c43 | 737 | { NULL, LAST_CONFLICT } }, |
627e74fd DC |
738 | .convert = true, |
739 | .is_power_2 = true, | |
a9dad670 DC |
740 | .minval = XFS_MIN_SECTORSIZE, |
741 | .maxval = XFS_MAX_SECTORSIZE, | |
56e4d368 | 742 | .defaultval = SUBOPT_NEEDS_VAL, |
a9dad670 DC |
743 | }, |
744 | { .index = S_SECTSIZE, | |
2cf637cf | 745 | .conflicts = { { &sopts, S_SIZE }, |
6c75555e | 746 | { &dopts, D_SECTSIZE }, |
cedf1c43 | 747 | { NULL, LAST_CONFLICT } }, |
627e74fd DC |
748 | .convert = true, |
749 | .is_power_2 = true, | |
a9dad670 DC |
750 | .minval = XFS_MIN_SECTORSIZE, |
751 | .maxval = XFS_MAX_SECTORSIZE, | |
56e4d368 | 752 | .defaultval = SUBOPT_NEEDS_VAL, |
a9dad670 DC |
753 | }, |
754 | }, | |
2bd0ea18 NS |
755 | }; |
756 | ||
00ff2b10 | 757 | static struct opt_params mopts = { |
a9dad670 | 758 | .name = 'm', |
ab2eef12 | 759 | .ini_section = "metadata", |
a9dad670 | 760 | .subopts = { |
64e924dd DC |
761 | [M_CRC] = "crc", |
762 | [M_FINOBT] = "finobt", | |
763 | [M_UUID] = "uuid", | |
764 | [M_RMAPBT] = "rmapbt", | |
765 | [M_REFLINK] = "reflink", | |
9eb0d6eb | 766 | [M_INOBTCNT] = "inobtcount", |
e9601810 | 767 | [M_BIGTIME] = "bigtime", |
50dba818 | 768 | [M_MAX_OPTS] = NULL, |
a9dad670 DC |
769 | }, |
770 | .subopt_params = { | |
771 | { .index = M_CRC, | |
cedf1c43 | 772 | .conflicts = { { NULL, LAST_CONFLICT } }, |
56e4d368 DC |
773 | .minval = 0, |
774 | .maxval = 1, | |
775 | .defaultval = 1, | |
776 | }, | |
777 | { .index = M_FINOBT, | |
cedf1c43 | 778 | .conflicts = { { NULL, LAST_CONFLICT } }, |
56e4d368 DC |
779 | .minval = 0, |
780 | .maxval = 1, | |
781 | .defaultval = 1, | |
782 | }, | |
783 | { .index = M_UUID, | |
cedf1c43 | 784 | .conflicts = { { NULL, LAST_CONFLICT } }, |
56e4d368 | 785 | .defaultval = SUBOPT_NEEDS_VAL, |
a9dad670 | 786 | }, |
c563396a | 787 | { .index = M_RMAPBT, |
cedf1c43 | 788 | .conflicts = { { NULL, LAST_CONFLICT } }, |
c563396a DW |
789 | .minval = 0, |
790 | .maxval = 1, | |
23069a93 | 791 | .defaultval = 1, |
c563396a | 792 | }, |
a5132d9b | 793 | { .index = M_REFLINK, |
cedf1c43 | 794 | .conflicts = { { NULL, LAST_CONFLICT } }, |
a5132d9b DW |
795 | .minval = 0, |
796 | .maxval = 1, | |
23069a93 | 797 | .defaultval = 1, |
a5132d9b | 798 | }, |
9eb0d6eb DW |
799 | { .index = M_INOBTCNT, |
800 | .conflicts = { { NULL, LAST_CONFLICT } }, | |
801 | .minval = 0, | |
802 | .maxval = 1, | |
803 | .defaultval = 1, | |
804 | }, | |
e9601810 DW |
805 | { .index = M_BIGTIME, |
806 | .conflicts = { { NULL, LAST_CONFLICT } }, | |
807 | .minval = 0, | |
808 | .maxval = 1, | |
809 | .defaultval = 1, | |
810 | }, | |
a9dad670 | 811 | }, |
f7b80291 DC |
812 | }; |
813 | ||
cf627f3c DC |
814 | /* quick way of checking if a parameter was set on the CLI */ |
815 | static bool | |
816 | cli_opt_set( | |
817 | struct opt_params *opts, | |
818 | int subopt) | |
819 | { | |
820 | return opts->subopt_params[subopt].seen || | |
821 | opts->subopt_params[subopt].str_seen; | |
822 | } | |
823 | ||
824 | /* | |
825 | * Options configured on the command line. | |
826 | * | |
827 | * This stores all the specific config parameters the user sets on the command | |
828 | * line. We do not use these values directly - they are inputs to the mkfs | |
829 | * geometry validation and override any default configuration value we have. | |
830 | * | |
831 | * We don't keep flags to indicate what parameters are set - if we need to check | |
4ab08e3b | 832 | * if an option was set on the command line, we check the relevant entry in the |
cf627f3c DC |
833 | * option table which records whether it was specified in the .seen and |
834 | * .str_seen variables in the table. | |
835 | * | |
836 | * Some parameters are stored as strings for post-parsing after their dependent | |
837 | * options have been resolved (e.g. block size and sector size have been parsed | |
838 | * and validated). | |
839 | * | |
840 | * This allows us to check that values have been set without needing separate | |
841 | * flags for each value, and hence avoids needing to record and check for each | |
842 | * specific option that can set the value later on in the code. In the cases | |
843 | * where we don't have a cli_params structure around, the above cli_opt_set() | |
844 | * function can be used. | |
845 | */ | |
846 | struct sb_feat_args { | |
847 | int log_version; | |
848 | int attr_version; | |
849 | int dir_version; | |
852b3258 ES |
850 | bool inode_align; /* XFS_SB_VERSION_ALIGNBIT */ |
851 | bool nci; /* XFS_SB_VERSION_BORGBIT */ | |
852 | bool lazy_sb_counters; /* XFS_SB_VERSION2_LAZYSBCOUNTBIT */ | |
853 | bool parent_pointers; /* XFS_SB_VERSION2_PARENTBIT */ | |
854 | bool projid32bit; /* XFS_SB_VERSION2_PROJID32BIT */ | |
855 | bool crcs_enabled; /* XFS_SB_VERSION2_CRCBIT */ | |
856 | bool dirftype; /* XFS_SB_VERSION2_FTYPE */ | |
857 | bool finobt; /* XFS_SB_FEAT_RO_COMPAT_FINOBT */ | |
858 | bool spinodes; /* XFS_SB_FEAT_INCOMPAT_SPINODES */ | |
859 | bool rmapbt; /* XFS_SB_FEAT_RO_COMPAT_RMAPBT */ | |
860 | bool reflink; /* XFS_SB_FEAT_RO_COMPAT_REFLINK */ | |
9eb0d6eb | 861 | bool inobtcnt; /* XFS_SB_FEAT_RO_COMPAT_INOBTCNT */ |
e9601810 | 862 | bool bigtime; /* XFS_SB_FEAT_INCOMPAT_BIGTIME */ |
cf627f3c DC |
863 | bool nodalign; |
864 | bool nortalign; | |
69e72722 | 865 | bool nrext64; |
cf627f3c DC |
866 | }; |
867 | ||
868 | struct cli_params { | |
869 | int sectorsize; | |
870 | int blocksize; | |
871 | ||
33c62516 | 872 | char *cfgfile; |
fb22e1b1 | 873 | char *protofile; |
33c62516 | 874 | |
cf627f3c DC |
875 | /* parameters that depend on sector/block size being validated. */ |
876 | char *dsize; | |
877 | char *agsize; | |
878 | char *dsu; | |
879 | char *dirblocksize; | |
880 | char *logsize; | |
881 | char *lsu; | |
882 | char *rtextsize; | |
883 | char *rtsize; | |
884 | ||
885 | /* parameters where 0 is a valid CLI value */ | |
886 | int dsunit; | |
887 | int dswidth; | |
888 | int dsw; | |
889 | int64_t logagno; | |
890 | int loginternal; | |
891 | int lsunit; | |
6e0ed3d1 | 892 | int is_supported; |
e0aeb058 | 893 | int proto_slashes_are_spaces; |
cf627f3c DC |
894 | |
895 | /* parameters where 0 is not a valid value */ | |
896 | int64_t agcount; | |
cf627f3c DC |
897 | int inodesize; |
898 | int inopblock; | |
899 | int imaxpct; | |
900 | int lsectorsize; | |
901 | uuid_t uuid; | |
902 | ||
903 | /* feature flags that are set */ | |
904 | struct sb_feat_args sb_feat; | |
905 | ||
906 | /* root inode characteristics */ | |
907 | struct fsxattr fsx; | |
908 | ||
909 | /* libxfs device setup */ | |
910 | struct libxfs_xinit *xi; | |
911 | }; | |
912 | ||
4ab08e3b DC |
913 | /* |
914 | * Calculated filesystem feature and geometry information. | |
915 | * | |
916 | * This structure contains the information we will use to create the on-disk | |
917 | * filesystem from. The validation and calculation code uses it to store all the | |
918 | * temporary and final config state for the filesystem. | |
919 | * | |
920 | * The information in this structure will contain a mix of validated CLI input | |
921 | * variables, default feature state and calculated values that are needed to | |
922 | * construct the superblock and other on disk features. These are all in one | |
923 | * place so that we don't have to pass handfuls of seemingly arbitrary variables | |
924 | * around to different functions to do the work we need to do. | |
925 | */ | |
926 | struct mkfs_params { | |
927 | int blocksize; | |
928 | int blocklog; | |
929 | int sectorsize; | |
930 | int sectorlog; | |
931 | int lsectorsize; | |
932 | int lsectorlog; | |
933 | int dirblocksize; | |
934 | int dirblocklog; | |
935 | int inodesize; | |
936 | int inodelog; | |
937 | int inopblock; | |
938 | ||
939 | uint64_t dblocks; | |
940 | uint64_t logblocks; | |
941 | uint64_t rtblocks; | |
942 | uint64_t rtextblocks; | |
943 | uint64_t rtextents; | |
944 | uint64_t rtbmblocks; /* rt bitmap blocks */ | |
945 | ||
946 | int dsunit; /* in FSBs */ | |
947 | int dswidth; /* in FSBs */ | |
948 | int lsunit; /* in FSBs */ | |
949 | ||
950 | uint64_t agsize; | |
951 | uint64_t agcount; | |
952 | ||
953 | int imaxpct; | |
954 | ||
955 | bool loginternal; | |
956 | uint64_t logstart; | |
957 | uint64_t logagno; | |
958 | ||
959 | uuid_t uuid; | |
960 | char *label; | |
961 | ||
962 | struct sb_feat_args sb_feat; | |
963 | }; | |
964 | ||
68344ba0 DC |
965 | /* |
966 | * Default filesystem features and configuration values | |
967 | * | |
968 | * This structure contains the default mkfs values that are to be used when | |
969 | * a user does not specify the option on the command line. We do not use these | |
970 | * values directly - they are inputs to the mkfs geometry validation and | |
971 | * calculations. | |
972 | */ | |
973 | struct mkfs_default_params { | |
974 | char *source; /* where the defaults came from */ | |
975 | ||
976 | int sectorsize; | |
977 | int blocksize; | |
978 | ||
979 | /* feature flags that are set */ | |
980 | struct sb_feat_args sb_feat; | |
981 | ||
982 | /* root inode characteristics */ | |
983 | struct fsxattr fsx; | |
984 | }; | |
985 | ||
dafb318d DC |
986 | static void __attribute__((noreturn)) |
987 | usage( void ) | |
988 | { | |
989 | fprintf(stderr, _("Usage: %s\n\ | |
c66bd30e | 990 | /* blocksize */ [-b size=num]\n\ |
33c62516 | 991 | /* config file */ [-c options=xxx]\n\ |
9eb0d6eb | 992 | /* metadata */ [-m crc=0|1,finobt=0|1,uuid=xxx,rmapbt=0|1,reflink=0|1,\n\ |
2c40c5a7 | 993 | inobtcount=0|1,bigtime=0|1]\n\ |
dafb318d DC |
994 | /* data subvol */ [-d agcount=n,agsize=n,file,name=xxx,size=num,\n\ |
995 | (sunit=value,swidth=value|su=num,sw=num|noalign),\n\ | |
c66bd30e | 996 | sectsize=num\n\ |
dafb318d | 997 | /* force overwrite */ [-f]\n\ |
b68e2558 | 998 | /* inode size */ [-i perblock=n|size=num,maxpct=n,attr=0|1|2,\n\ |
42efbb99 | 999 | projid32bit=0|1,sparse=0|1,nrext64=0|1]\n\ |
dafb318d DC |
1000 | /* no discard */ [-K]\n\ |
1001 | /* log subvol */ [-l agnum=n,internal,size=num,logdev=xxx,version=n\n\ | |
c66bd30e | 1002 | sunit=value|su=num,sectsize=num,lazy-count=0|1]\n\ |
dafb318d | 1003 | /* label */ [-L label (maximum 12 characters)]\n\ |
c66bd30e | 1004 | /* naming */ [-n size=num,version=2|ci,ftype=0|1]\n\ |
dafb318d DC |
1005 | /* no-op info only */ [-N]\n\ |
1006 | /* prototype file */ [-p fname]\n\ | |
1007 | /* quiet */ [-q]\n\ | |
1008 | /* realtime subvol */ [-r extsize=num,size=num,rtdev=xxx]\n\ | |
c66bd30e | 1009 | /* sectorsize */ [-s size=num]\n\ |
dafb318d DC |
1010 | /* version */ [-V]\n\ |
1011 | devicename\n\ | |
1012 | <devicename> is required unless -d name=xxx is given.\n\ | |
1013 | <num> is xxx (bytes), xxxs (sectors), xxxb (fs blocks), xxxk (xxx KiB),\n\ | |
1014 | xxxm (xxx MiB), xxxg (xxx GiB), xxxt (xxx TiB) or xxxp (xxx PiB).\n\ | |
1015 | <value> is xxx (512 byte blocks).\n"), | |
1016 | progname); | |
1017 | exit(1); | |
1018 | } | |
1019 | ||
1020 | static void | |
1021 | conflict( | |
cedf1c43 DC |
1022 | struct opt_params *opts, |
1023 | int option, | |
1024 | struct opt_params *con_opts, | |
1025 | int conflict) | |
dafb318d DC |
1026 | { |
1027 | fprintf(stderr, _("Cannot specify both -%c %s and -%c %s\n"), | |
6c75555e DC |
1028 | con_opts->name, con_opts->subopts[conflict], |
1029 | opts->name, opts->subopts[option]); | |
dafb318d DC |
1030 | usage(); |
1031 | } | |
1032 | ||
1033 | ||
1034 | static void | |
1035 | illegal( | |
1036 | const char *value, | |
1037 | const char *opt) | |
1038 | { | |
0b1cf8bb | 1039 | fprintf(stderr, _("Invalid value %s for -%s option\n"), value, opt); |
dafb318d DC |
1040 | usage(); |
1041 | } | |
1042 | ||
1043 | static int | |
1044 | ispow2( | |
1045 | unsigned int i) | |
1046 | { | |
1047 | return (i & (i - 1)) == 0; | |
1048 | } | |
1049 | ||
1050 | static void __attribute__((noreturn)) | |
1051 | reqval( | |
1052 | char opt, | |
1053 | const char *tab[], | |
1054 | int idx) | |
1055 | { | |
1056 | fprintf(stderr, _("-%c %s option requires a value\n"), opt, tab[idx]); | |
1057 | usage(); | |
1058 | } | |
1059 | ||
1060 | static void | |
1061 | respec( | |
1062 | char opt, | |
1063 | const char *tab[], | |
1064 | int idx) | |
1065 | { | |
1066 | fprintf(stderr, "-%c ", opt); | |
1067 | if (tab) | |
1068 | fprintf(stderr, "%s ", tab[idx]); | |
1069 | fprintf(stderr, _("option respecified\n")); | |
1070 | usage(); | |
1071 | } | |
1072 | ||
1073 | static void | |
1074 | unknown( | |
9c2b30c8 DC |
1075 | const char opt, |
1076 | const char *s) | |
dafb318d DC |
1077 | { |
1078 | fprintf(stderr, _("unknown option -%c %s\n"), opt, s); | |
1079 | usage(); | |
1080 | } | |
1081 | ||
ab2eef12 DC |
1082 | static void |
1083 | invalid_cfgfile_opt( | |
1084 | const char *filename, | |
1085 | const char *section, | |
1086 | const char *name, | |
1087 | const char *value) | |
1088 | { | |
1089 | fprintf(stderr, _("%s: invalid config file option: [%s]: %s=%s\n"), | |
1090 | filename, section, name, value); | |
1091 | } | |
1092 | ||
06ac92fd DC |
1093 | static void |
1094 | check_device_type( | |
1095 | const char *name, | |
1096 | int *isfile, | |
1097 | bool no_size, | |
1098 | bool no_name, | |
1099 | int *create, | |
06ac92fd DC |
1100 | const char *optname) |
1101 | { | |
f594a0d1 | 1102 | struct stat statbuf; |
06ac92fd DC |
1103 | |
1104 | if (*isfile && (no_size || no_name)) { | |
1105 | fprintf(stderr, | |
1106 | _("if -%s file then -%s name and -%s size are required\n"), | |
1107 | optname, optname, optname); | |
1108 | usage(); | |
1109 | } | |
1110 | ||
1111 | if (!name) { | |
1112 | fprintf(stderr, _("No device name specified\n")); | |
1113 | usage(); | |
1114 | } | |
1115 | ||
f594a0d1 | 1116 | if (stat(name, &statbuf)) { |
06ac92fd DC |
1117 | if (errno == ENOENT && *isfile) { |
1118 | if (create) | |
1119 | *create = 1; | |
1120 | return; | |
1121 | } | |
1122 | ||
1123 | fprintf(stderr, | |
1124 | _("Error accessing specified device %s: %s\n"), | |
1125 | name, strerror(errno)); | |
1126 | usage(); | |
1127 | return; | |
1128 | } | |
1129 | ||
06ac92fd DC |
1130 | /* |
1131 | * We only want to completely truncate and recreate an existing file if | |
1132 | * we were specifically told it was a file. Set the create flag only in | |
1133 | * this case to trigger that behaviour. | |
1134 | */ | |
1135 | if (S_ISREG(statbuf.st_mode)) { | |
1136 | if (!*isfile) | |
1137 | *isfile = 1; | |
1138 | else if (create) | |
1139 | *create = 1; | |
1140 | return; | |
1141 | } | |
1142 | ||
1143 | if (S_ISBLK(statbuf.st_mode)) { | |
1144 | if (*isfile) { | |
1145 | fprintf(stderr, | |
1146 | _("specified \"-%s file\" on a block device %s\n"), | |
1147 | optname, name); | |
1148 | usage(); | |
1149 | } | |
1150 | return; | |
1151 | } | |
1152 | ||
1153 | fprintf(stderr, | |
1154 | _("specified device %s not a file or block device\n"), | |
1155 | name); | |
1156 | usage(); | |
1157 | } | |
1158 | ||
cb46aab2 JT |
1159 | static void |
1160 | validate_overwrite( | |
1161 | const char *name, | |
1162 | bool force_overwrite) | |
1163 | { | |
1164 | if (!force_overwrite && check_overwrite(name)) { | |
1165 | fprintf(stderr, | |
1166 | _("%s: Use the -f option to force overwrite.\n"), | |
1167 | progname); | |
1168 | exit(1); | |
1169 | } | |
1170 | ||
1171 | } | |
1172 | ||
1f1b8be7 NS |
1173 | static void |
1174 | validate_ag_geometry( | |
1175 | int blocklog, | |
14f8b681 DW |
1176 | uint64_t dblocks, |
1177 | uint64_t agsize, | |
1178 | uint64_t agcount) | |
1f1b8be7 NS |
1179 | { |
1180 | if (agsize < XFS_AG_MIN_BLOCKS(blocklog)) { | |
1181 | fprintf(stderr, | |
ddf12ea5 | 1182 | _("agsize (%lld blocks) too small, need at least %lld blocks\n"), |
1f1b8be7 NS |
1183 | (long long)agsize, |
1184 | (long long)XFS_AG_MIN_BLOCKS(blocklog)); | |
1185 | usage(); | |
1186 | } | |
1187 | ||
1188 | if (agsize > XFS_AG_MAX_BLOCKS(blocklog)) { | |
1189 | fprintf(stderr, | |
ddf12ea5 | 1190 | _("agsize (%lld blocks) too big, maximum is %lld blocks\n"), |
1f1b8be7 NS |
1191 | (long long)agsize, |
1192 | (long long)XFS_AG_MAX_BLOCKS(blocklog)); | |
1193 | usage(); | |
1194 | } | |
1195 | ||
1196 | if (agsize > dblocks) { | |
1197 | fprintf(stderr, | |
ddf12ea5 | 1198 | _("agsize (%lld blocks) too big, data area is %lld blocks\n"), |
1f1b8be7 NS |
1199 | (long long)agsize, (long long)dblocks); |
1200 | usage(); | |
1201 | } | |
1202 | ||
1203 | if (agsize < XFS_AG_MIN_BLOCKS(blocklog)) { | |
1204 | fprintf(stderr, | |
1205 | _("too many allocation groups for size = %lld\n"), | |
1206 | (long long)agsize); | |
1207 | fprintf(stderr, _("need at most %lld allocation groups\n"), | |
1208 | (long long)(dblocks / XFS_AG_MIN_BLOCKS(blocklog) + | |
1209 | (dblocks % XFS_AG_MIN_BLOCKS(blocklog) != 0))); | |
1210 | usage(); | |
1211 | } | |
1212 | ||
1213 | if (agsize > XFS_AG_MAX_BLOCKS(blocklog)) { | |
1214 | fprintf(stderr, | |
1215 | _("too few allocation groups for size = %lld\n"), (long long)agsize); | |
1216 | fprintf(stderr, | |
1217 | _("need at least %lld allocation groups\n"), | |
1e945ba2 | 1218 | (long long)(dblocks / XFS_AG_MAX_BLOCKS(blocklog) + |
1f1b8be7 NS |
1219 | (dblocks % XFS_AG_MAX_BLOCKS(blocklog) != 0))); |
1220 | usage(); | |
1221 | } | |
1222 | ||
1223 | /* | |
1224 | * If the last AG is too small, reduce the filesystem size | |
1225 | * and drop the blocks. | |
1226 | */ | |
1227 | if ( dblocks % agsize != 0 && | |
1228 | (dblocks % agsize < XFS_AG_MIN_BLOCKS(blocklog))) { | |
1229 | fprintf(stderr, | |
1230 | _("last AG size %lld blocks too small, minimum size is %lld blocks\n"), | |
1231 | (long long)(dblocks % agsize), | |
1232 | (long long)XFS_AG_MIN_BLOCKS(blocklog)); | |
1233 | usage(); | |
1234 | } | |
1235 | ||
1236 | /* | |
1237 | * If agcount is too large, make it smaller. | |
1238 | */ | |
1239 | if (agcount > XFS_MAX_AGNUMBER + 1) { | |
1240 | fprintf(stderr, | |
1241 | _("%lld allocation groups is too many, maximum is %lld\n"), | |
1242 | (long long)agcount, (long long)XFS_MAX_AGNUMBER + 1); | |
1243 | usage(); | |
1244 | } | |
1245 | } | |
1246 | ||
1e945ba2 BN |
1247 | static void |
1248 | zero_old_xfs_structures( | |
1249 | libxfs_init_t *xi, | |
1250 | xfs_sb_t *new_sb) | |
1251 | { | |
1252 | void *buf; | |
1253 | xfs_sb_t sb; | |
14f8b681 | 1254 | uint32_t bsize; |
1e945ba2 BN |
1255 | int i; |
1256 | xfs_off_t off; | |
31daa90b BF |
1257 | |
1258 | /* | |
1259 | * We open regular files with O_TRUNC|O_CREAT. Nothing to do here... | |
1260 | */ | |
1261 | if (xi->disfile && xi->dcreat) | |
1262 | return; | |
1e945ba2 BN |
1263 | |
1264 | /* | |
ff1f79a7 | 1265 | * read in existing filesystem superblock, use its geometry |
1e945ba2 BN |
1266 | * settings and zero the existing secondary superblocks. |
1267 | */ | |
1268 | buf = memalign(libxfs_device_alignment(), new_sb->sb_sectsize); | |
1269 | if (!buf) { | |
1270 | fprintf(stderr, | |
1271 | _("error reading existing superblock -- failed to memalign buffer\n")); | |
1272 | return; | |
1273 | } | |
dab9b8d6 | 1274 | memset(buf, 0, new_sb->sb_sectsize); |
1e945ba2 | 1275 | |
06ac92fd DC |
1276 | /* |
1277 | * If we are creating an image file, it might be of zero length at this | |
1278 | * point in time. Hence reading the existing superblock is going to | |
1279 | * return zero bytes. It's not a failure we need to warn about in this | |
1280 | * case. | |
1281 | */ | |
1282 | off = pread(xi->dfd, buf, new_sb->sb_sectsize, 0); | |
1283 | if (off != new_sb->sb_sectsize) { | |
1284 | if (!xi->disfile) | |
1285 | fprintf(stderr, | |
1286 | _("error reading existing superblock: %s\n"), | |
1287 | strerror(errno)); | |
31daa90b | 1288 | goto done; |
1e945ba2 | 1289 | } |
5e656dbb | 1290 | libxfs_sb_from_disk(&sb, buf); |
1e945ba2 BN |
1291 | |
1292 | /* | |
1293 | * perform same basic superblock validation to make sure we | |
1294 | * actually zero secondary blocks | |
1295 | */ | |
1296 | if (sb.sb_magicnum != XFS_SB_MAGIC || sb.sb_blocksize == 0) | |
1297 | goto done; | |
1298 | ||
1299 | for (bsize = 1, i = 0; bsize < sb.sb_blocksize && | |
1300 | i < sizeof(sb.sb_blocksize) * NBBY; i++) | |
1301 | bsize <<= 1; | |
1302 | ||
1303 | if (i < XFS_MIN_BLOCKSIZE_LOG || i > XFS_MAX_BLOCKSIZE_LOG || | |
1304 | i != sb.sb_blocklog) | |
1305 | goto done; | |
1306 | ||
14f8b681 DW |
1307 | if (sb.sb_dblocks > ((uint64_t)sb.sb_agcount * sb.sb_agblocks) || |
1308 | sb.sb_dblocks < ((uint64_t)(sb.sb_agcount - 1) * | |
1e945ba2 BN |
1309 | sb.sb_agblocks + XFS_MIN_AG_BLOCKS)) |
1310 | goto done; | |
1311 | ||
1312 | /* | |
c93b0a22 | 1313 | * block size and basic geometry seems alright, zero the secondaries. |
1e945ba2 | 1314 | */ |
dab9b8d6 | 1315 | memset(buf, 0, new_sb->sb_sectsize); |
1e945ba2 BN |
1316 | off = 0; |
1317 | for (i = 1; i < sb.sb_agcount; i++) { | |
1318 | off += sb.sb_agblocks; | |
2f9a125c | 1319 | if (pwrite(xi->dfd, buf, new_sb->sb_sectsize, |
1e945ba2 BN |
1320 | off << sb.sb_blocklog) == -1) |
1321 | break; | |
1322 | } | |
1323 | done: | |
1324 | free(buf); | |
1325 | } | |
1326 | ||
ad136b33 | 1327 | static void |
7e8a6edb | 1328 | discard_blocks(dev_t dev, uint64_t nsectors, int quiet) |
ad136b33 | 1329 | { |
7e8a6edb PR |
1330 | int fd; |
1331 | uint64_t offset = 0; | |
1332 | /* Discard the device 2G at a time */ | |
1333 | const uint64_t step = 2ULL << 30; | |
1334 | const uint64_t count = BBTOB(nsectors); | |
ad136b33 | 1335 | |
ad136b33 | 1336 | fd = libxfs_device_to_fd(dev); |
7e8a6edb PR |
1337 | if (fd <= 0) |
1338 | return; | |
7e8a6edb PR |
1339 | |
1340 | /* The block discarding happens in smaller batches so it can be | |
1341 | * interrupted prematurely | |
1342 | */ | |
1343 | while (offset < count) { | |
1344 | uint64_t tmp_step = min(step, count - offset); | |
1345 | ||
1346 | /* | |
1347 | * We intentionally ignore errors from the discard ioctl. It is | |
1348 | * not necessary for the mkfs functionality but just an | |
1349 | * optimization. However we should stop on error. | |
1350 | */ | |
2383d7c5 ES |
1351 | if (platform_discard_blocks(fd, offset, tmp_step) == 0) { |
1352 | if (offset == 0 && !quiet) { | |
1353 | printf("Discarding blocks..."); | |
1354 | fflush(stdout); | |
1355 | } | |
1356 | } else { | |
1357 | if (offset > 0 && !quiet) | |
1358 | printf("\n"); | |
7e8a6edb | 1359 | return; |
2383d7c5 | 1360 | } |
7e8a6edb PR |
1361 | |
1362 | offset += tmp_step; | |
1363 | } | |
2383d7c5 | 1364 | if (offset > 0 && !quiet) |
7e8a6edb | 1365 | printf("Done.\n"); |
ad136b33 CH |
1366 | } |
1367 | ||
a9dad670 DC |
1368 | static __attribute__((noreturn)) void |
1369 | illegal_option( | |
aa3034d4 | 1370 | const char *value, |
a9dad670 | 1371 | struct opt_params *opts, |
aa3034d4 JT |
1372 | int index, |
1373 | const char *reason) | |
a9dad670 DC |
1374 | { |
1375 | fprintf(stderr, | |
0b1cf8bb | 1376 | _("Invalid value %s for -%c %s option. %s\n"), |
aa3034d4 | 1377 | value, opts->name, opts->subopts[index], |
7d25f65f | 1378 | reason); |
a9dad670 DC |
1379 | usage(); |
1380 | } | |
1381 | ||
27ae3a59 DC |
1382 | /* |
1383 | * Check for conflicts and option respecification. | |
1384 | */ | |
1385 | static void | |
1386 | check_opt( | |
a9dad670 | 1387 | struct opt_params *opts, |
27ae3a59 DC |
1388 | int index, |
1389 | bool str_seen) | |
147e0f31 | 1390 | { |
27ae3a59 DC |
1391 | struct subopt_param *sp = &opts->subopt_params[index]; |
1392 | int i; | |
147e0f31 | 1393 | |
56e4d368 DC |
1394 | if (sp->index != index) { |
1395 | fprintf(stderr, | |
02c3e106 | 1396 | _("Developer screwed up option parsing (%d/%d)! Please report!\n"), |
56e4d368 | 1397 | sp->index, index); |
05abf43d | 1398 | reqval(opts->name, opts->subopts, index); |
56e4d368 DC |
1399 | } |
1400 | ||
27ae3a59 DC |
1401 | /* |
1402 | * Check for respecification of the option. This is more complex than it | |
1403 | * seems because some options are parsed twice - once as a string during | |
1404 | * input parsing, then later the string is passed to getnum for | |
1405 | * conversion into a number and bounds checking. Hence the two variables | |
1406 | * used to track the different uses based on the @str parameter passed | |
1407 | * to us. | |
1408 | */ | |
1409 | if (!str_seen) { | |
1410 | if (sp->seen) | |
05abf43d | 1411 | respec(opts->name, opts->subopts, index); |
27ae3a59 DC |
1412 | sp->seen = true; |
1413 | } else { | |
1414 | if (sp->str_seen) | |
05abf43d | 1415 | respec(opts->name, opts->subopts, index); |
27ae3a59 DC |
1416 | sp->str_seen = true; |
1417 | } | |
9090e187 | 1418 | |
3ec1956a | 1419 | /* check for conflicts with the option */ |
27ae3a59 | 1420 | for (i = 0; i < MAX_CONFLICTS; i++) { |
cedf1c43 | 1421 | struct _conflict *con = &sp->conflicts[i]; |
3ec1956a | 1422 | |
cedf1c43 | 1423 | if (con->subopt == LAST_CONFLICT) |
3ec1956a | 1424 | break; |
cedf1c43 DC |
1425 | if (con->opts->subopt_params[con->subopt].seen || |
1426 | con->opts->subopt_params[con->subopt].str_seen) | |
1427 | conflict(opts, index, con->opts, con->subopt); | |
3ec1956a | 1428 | } |
27ae3a59 | 1429 | } |
3ec1956a | 1430 | |
27ae3a59 DC |
1431 | static long long |
1432 | getnum( | |
1433 | const char *str, | |
1434 | struct opt_params *opts, | |
1435 | int index) | |
1436 | { | |
1437 | struct subopt_param *sp = &opts->subopt_params[index]; | |
1438 | long long c; | |
1439 | ||
1440 | check_opt(opts, index, false); | |
6c855628 | 1441 | /* empty strings might just return a default value */ |
56e4d368 DC |
1442 | if (!str || *str == '\0') { |
1443 | if (sp->defaultval == SUBOPT_NEEDS_VAL) | |
05abf43d | 1444 | reqval(opts->name, opts->subopts, index); |
56e4d368 DC |
1445 | return sp->defaultval; |
1446 | } | |
a9dad670 | 1447 | |
56e4d368 | 1448 | if (sp->minval == 0 && sp->maxval == 0) { |
a9dad670 DC |
1449 | fprintf(stderr, |
1450 | _("Option -%c %s has undefined minval/maxval." | |
1451 | "Can't verify value range. This is a bug.\n"), | |
1452 | opts->name, opts->subopts[index]); | |
1453 | exit(1); | |
1454 | } | |
147e0f31 | 1455 | |
6c855628 DC |
1456 | /* |
1457 | * Some values are pure numbers, others can have suffixes that define | |
1458 | * the units of the number. Those get passed to cvtnum(), otherwise we | |
1459 | * convert it ourselves to guarantee there is no trailing garbage in the | |
1460 | * number. | |
1461 | */ | |
105041e6 | 1462 | if (sp->convert) { |
6c855628 | 1463 | c = cvtnum(blocksize, sectorsize, str); |
105041e6 DC |
1464 | if (c == -1LL) { |
1465 | illegal_option(str, opts, index, | |
1466 | _("Not a valid value or illegal suffix")); | |
1467 | } | |
1468 | } else { | |
6c855628 DC |
1469 | char *str_end; |
1470 | ||
1471 | c = strtoll(str, &str_end, 0); | |
1472 | if (c == 0 && str_end == str) | |
7d25f65f DW |
1473 | illegal_option(str, opts, index, |
1474 | _("Value not recognized as number.")); | |
6c855628 | 1475 | if (*str_end != '\0') |
7d25f65f DW |
1476 | illegal_option(str, opts, index, |
1477 | _("Unit suffixes are not allowed.")); | |
6c855628 DC |
1478 | } |
1479 | ||
1480 | /* Validity check the result. */ | |
aa3034d4 | 1481 | if (c < sp->minval) |
7d25f65f | 1482 | illegal_option(str, opts, index, _("Value is too small.")); |
aa3034d4 | 1483 | else if (c > sp->maxval) |
7d25f65f | 1484 | illegal_option(str, opts, index, _("Value is too large.")); |
627e74fd | 1485 | if (sp->is_power_2 && !ispow2(c)) |
7d25f65f | 1486 | illegal_option(str, opts, index, _("Value must be a power of 2.")); |
147e0f31 DC |
1487 | return c; |
1488 | } | |
1489 | ||
27ae3a59 DC |
1490 | /* |
1491 | * Option is a string - do all the option table work, and check there | |
1492 | * is actually an option string. Otherwise we don't do anything with the string | |
1493 | * here - validation will be done later when the string is converted to a value | |
1494 | * or used as a file/device path. | |
1495 | */ | |
1496 | static char * | |
1497 | getstr( | |
9c2b30c8 | 1498 | const char *str, |
27ae3a59 DC |
1499 | struct opt_params *opts, |
1500 | int index) | |
1501 | { | |
99c78777 DW |
1502 | char *ret; |
1503 | ||
27ae3a59 DC |
1504 | check_opt(opts, index, true); |
1505 | ||
1506 | /* empty strings for string options are not valid */ | |
1507 | if (!str || *str == '\0') | |
05abf43d | 1508 | reqval(opts->name, opts->subopts, index); |
99c78777 DW |
1509 | |
1510 | ret = strdup(str); | |
1511 | if (!ret) { | |
1512 | fprintf(stderr, _("Out of memory while saving suboptions.\n")); | |
1513 | exit(1); | |
1514 | } | |
1515 | ||
1516 | return ret; | |
27ae3a59 DC |
1517 | } |
1518 | ||
a350bbc1 DC |
1519 | static int |
1520 | block_opts_parser( | |
1521 | struct opt_params *opts, | |
1522 | int subopt, | |
9c2b30c8 | 1523 | const char *value, |
a350bbc1 DC |
1524 | struct cli_params *cli) |
1525 | { | |
85d6f03d | 1526 | switch (subopt) { |
85d6f03d | 1527 | case B_SIZE: |
e5e612ae | 1528 | cli->blocksize = getnum(value, opts, subopt); |
85d6f03d DC |
1529 | break; |
1530 | default: | |
1531 | return -EINVAL; | |
1532 | } | |
a350bbc1 DC |
1533 | return 0; |
1534 | } | |
1535 | ||
33c62516 DC |
1536 | static int |
1537 | cfgfile_opts_parser( | |
1538 | struct opt_params *opts, | |
1539 | int subopt, | |
9c2b30c8 | 1540 | const char *value, |
33c62516 DC |
1541 | struct cli_params *cli) |
1542 | { | |
1543 | switch (subopt) { | |
1544 | case C_OPTFILE: | |
1545 | cli->cfgfile = getstr(value, opts, subopt); | |
1546 | break; | |
1547 | default: | |
1548 | return -EINVAL; | |
1549 | } | |
1550 | return 0; | |
1551 | } | |
1552 | ||
a350bbc1 DC |
1553 | static int |
1554 | data_opts_parser( | |
1555 | struct opt_params *opts, | |
1556 | int subopt, | |
9c2b30c8 | 1557 | const char *value, |
a350bbc1 DC |
1558 | struct cli_params *cli) |
1559 | { | |
a1273b7c DC |
1560 | switch (subopt) { |
1561 | case D_AGCOUNT: | |
e5e612ae | 1562 | cli->agcount = getnum(value, opts, subopt); |
a1273b7c DC |
1563 | break; |
1564 | case D_AGSIZE: | |
e5e612ae | 1565 | cli->agsize = getstr(value, opts, subopt); |
a1273b7c DC |
1566 | break; |
1567 | case D_FILE: | |
e5e612ae | 1568 | cli->xi->disfile = getnum(value, opts, subopt); |
a1273b7c DC |
1569 | break; |
1570 | case D_NAME: | |
e5e612ae | 1571 | cli->xi->dname = getstr(value, opts, subopt); |
a1273b7c DC |
1572 | break; |
1573 | case D_SIZE: | |
e5e612ae | 1574 | cli->dsize = getstr(value, opts, subopt); |
a1273b7c DC |
1575 | break; |
1576 | case D_SUNIT: | |
e5e612ae | 1577 | cli->dsunit = getnum(value, opts, subopt); |
a1273b7c DC |
1578 | break; |
1579 | case D_SWIDTH: | |
e5e612ae | 1580 | cli->dswidth = getnum(value, opts, subopt); |
a1273b7c DC |
1581 | break; |
1582 | case D_SU: | |
e5e612ae | 1583 | cli->dsu = getstr(value, opts, subopt); |
a1273b7c DC |
1584 | break; |
1585 | case D_SW: | |
e5e612ae | 1586 | cli->dsw = getnum(value, opts, subopt); |
a1273b7c DC |
1587 | break; |
1588 | case D_NOALIGN: | |
e5e612ae | 1589 | cli->sb_feat.nodalign = getnum(value, opts, subopt); |
a1273b7c | 1590 | break; |
a1273b7c | 1591 | case D_SECTSIZE: |
e5e612ae | 1592 | cli->sectorsize = getnum(value, opts, subopt); |
a1273b7c DC |
1593 | break; |
1594 | case D_RTINHERIT: | |
e5e612ae | 1595 | if (getnum(value, opts, subopt)) |
00d139f1 | 1596 | cli->fsx.fsx_xflags |= FS_XFLAG_RTINHERIT; |
9c7e941b DW |
1597 | else |
1598 | cli->fsx.fsx_xflags &= ~FS_XFLAG_RTINHERIT; | |
a1273b7c DC |
1599 | break; |
1600 | case D_PROJINHERIT: | |
e5e612ae | 1601 | cli->fsx.fsx_projid = getnum(value, opts, subopt); |
00d139f1 | 1602 | cli->fsx.fsx_xflags |= FS_XFLAG_PROJINHERIT; |
a1273b7c DC |
1603 | break; |
1604 | case D_EXTSZINHERIT: | |
e5e612ae | 1605 | cli->fsx.fsx_extsize = getnum(value, opts, subopt); |
dc2cfca7 DW |
1606 | if (cli->fsx.fsx_extsize) |
1607 | cli->fsx.fsx_xflags |= FS_XFLAG_EXTSZINHERIT; | |
1608 | else | |
1609 | cli->fsx.fsx_xflags &= ~FS_XFLAG_EXTSZINHERIT; | |
a1273b7c DC |
1610 | break; |
1611 | case D_COWEXTSIZE: | |
e5e612ae | 1612 | cli->fsx.fsx_cowextsize = getnum(value, opts, subopt); |
dc2cfca7 DW |
1613 | if (cli->fsx.fsx_cowextsize) |
1614 | cli->fsx.fsx_xflags |= FS_XFLAG_COWEXTSIZE; | |
1615 | else | |
1616 | cli->fsx.fsx_xflags &= ~FS_XFLAG_COWEXTSIZE; | |
a1273b7c | 1617 | break; |
64989ff3 DW |
1618 | case D_DAXINHERIT: |
1619 | if (getnum(value, opts, subopt)) | |
1620 | cli->fsx.fsx_xflags |= FS_XFLAG_DAX; | |
1621 | else | |
1622 | cli->fsx.fsx_xflags &= ~FS_XFLAG_DAX; | |
1623 | break; | |
a1273b7c DC |
1624 | default: |
1625 | return -EINVAL; | |
1626 | } | |
a350bbc1 DC |
1627 | return 0; |
1628 | } | |
1629 | ||
1630 | static int | |
1631 | inode_opts_parser( | |
1632 | struct opt_params *opts, | |
1633 | int subopt, | |
9c2b30c8 | 1634 | const char *value, |
a350bbc1 DC |
1635 | struct cli_params *cli) |
1636 | { | |
a3ac5af1 DC |
1637 | switch (subopt) { |
1638 | case I_ALIGN: | |
e5e612ae | 1639 | cli->sb_feat.inode_align = getnum(value, opts, subopt); |
a3ac5af1 | 1640 | break; |
a3ac5af1 | 1641 | case I_MAXPCT: |
e5e612ae | 1642 | cli->imaxpct = getnum(value, opts, subopt); |
a3ac5af1 DC |
1643 | break; |
1644 | case I_PERBLOCK: | |
e5e612ae | 1645 | cli->inopblock = getnum(value, opts, subopt); |
a3ac5af1 DC |
1646 | break; |
1647 | case I_SIZE: | |
e5e612ae | 1648 | cli->inodesize = getnum(value, opts, subopt); |
a3ac5af1 DC |
1649 | break; |
1650 | case I_ATTR: | |
e5e612ae | 1651 | cli->sb_feat.attr_version = getnum(value, opts, subopt); |
a3ac5af1 DC |
1652 | break; |
1653 | case I_PROJID32BIT: | |
e5e612ae | 1654 | cli->sb_feat.projid32bit = getnum(value, opts, subopt); |
a3ac5af1 DC |
1655 | break; |
1656 | case I_SPINODES: | |
e5e612ae | 1657 | cli->sb_feat.spinodes = getnum(value, opts, subopt); |
a3ac5af1 | 1658 | break; |
69e72722 CB |
1659 | case I_NREXT64: |
1660 | cli->sb_feat.nrext64 = getnum(value, opts, subopt); | |
1661 | break; | |
a3ac5af1 DC |
1662 | default: |
1663 | return -EINVAL; | |
1664 | } | |
a350bbc1 DC |
1665 | return 0; |
1666 | } | |
1667 | ||
1668 | static int | |
1669 | log_opts_parser( | |
1670 | struct opt_params *opts, | |
1671 | int subopt, | |
9c2b30c8 | 1672 | const char *value, |
a350bbc1 DC |
1673 | struct cli_params *cli) |
1674 | { | |
f3bc91a4 DC |
1675 | switch (subopt) { |
1676 | case L_AGNUM: | |
e5e612ae | 1677 | cli->logagno = getnum(value, opts, subopt); |
f3bc91a4 DC |
1678 | break; |
1679 | case L_FILE: | |
e5e612ae | 1680 | cli->xi->lisfile = getnum(value, opts, subopt); |
f3bc91a4 DC |
1681 | break; |
1682 | case L_INTERNAL: | |
e5e612ae | 1683 | cli->loginternal = getnum(value, opts, subopt); |
f3bc91a4 DC |
1684 | break; |
1685 | case L_SU: | |
e5e612ae | 1686 | cli->lsu = getstr(value, opts, subopt); |
f3bc91a4 DC |
1687 | break; |
1688 | case L_SUNIT: | |
e5e612ae | 1689 | cli->lsunit = getnum(value, opts, subopt); |
f3bc91a4 DC |
1690 | break; |
1691 | case L_NAME: | |
1692 | case L_DEV: | |
e5e612ae | 1693 | cli->xi->logname = getstr(value, opts, subopt); |
f3bc91a4 DC |
1694 | cli->loginternal = 0; |
1695 | break; | |
1696 | case L_VERSION: | |
e5e612ae | 1697 | cli->sb_feat.log_version = getnum(value, opts, subopt); |
f3bc91a4 DC |
1698 | break; |
1699 | case L_SIZE: | |
e5e612ae | 1700 | cli->logsize = getstr(value, opts, subopt); |
f3bc91a4 | 1701 | break; |
f3bc91a4 | 1702 | case L_SECTSIZE: |
e5e612ae | 1703 | cli->lsectorsize = getnum(value, opts, subopt); |
f3bc91a4 DC |
1704 | break; |
1705 | case L_LAZYSBCNTR: | |
e5e612ae | 1706 | cli->sb_feat.lazy_sb_counters = getnum(value, opts, subopt); |
f3bc91a4 DC |
1707 | break; |
1708 | default: | |
1709 | return -EINVAL; | |
1710 | } | |
a350bbc1 DC |
1711 | return 0; |
1712 | } | |
1713 | ||
1714 | static int | |
1715 | meta_opts_parser( | |
1716 | struct opt_params *opts, | |
1717 | int subopt, | |
9c2b30c8 | 1718 | const char *value, |
a350bbc1 DC |
1719 | struct cli_params *cli) |
1720 | { | |
997136c6 DC |
1721 | switch (subopt) { |
1722 | case M_CRC: | |
e5e612ae | 1723 | cli->sb_feat.crcs_enabled = getnum(value, opts, subopt); |
997136c6 DC |
1724 | if (cli->sb_feat.crcs_enabled) |
1725 | cli->sb_feat.dirftype = true; | |
1726 | break; | |
1727 | case M_FINOBT: | |
e5e612ae | 1728 | cli->sb_feat.finobt = getnum(value, opts, subopt); |
997136c6 DC |
1729 | break; |
1730 | case M_UUID: | |
1731 | if (!value || *value == '\0') | |
e5e612ae | 1732 | reqval('m', opts->subopts, subopt); |
997136c6 DC |
1733 | if (platform_uuid_parse(value, &cli->uuid)) |
1734 | illegal(value, "m uuid"); | |
1735 | break; | |
1736 | case M_RMAPBT: | |
e5e612ae | 1737 | cli->sb_feat.rmapbt = getnum(value, opts, subopt); |
997136c6 DC |
1738 | break; |
1739 | case M_REFLINK: | |
e5e612ae | 1740 | cli->sb_feat.reflink = getnum(value, opts, subopt); |
997136c6 | 1741 | break; |
9eb0d6eb DW |
1742 | case M_INOBTCNT: |
1743 | cli->sb_feat.inobtcnt = getnum(value, opts, subopt); | |
1744 | break; | |
e9601810 DW |
1745 | case M_BIGTIME: |
1746 | cli->sb_feat.bigtime = getnum(value, opts, subopt); | |
1747 | break; | |
997136c6 DC |
1748 | default: |
1749 | return -EINVAL; | |
1750 | } | |
a350bbc1 DC |
1751 | return 0; |
1752 | } | |
1753 | ||
1754 | static int | |
1755 | naming_opts_parser( | |
1756 | struct opt_params *opts, | |
1757 | int subopt, | |
9c2b30c8 | 1758 | const char *value, |
a350bbc1 DC |
1759 | struct cli_params *cli) |
1760 | { | |
98d40922 | 1761 | switch (subopt) { |
98d40922 | 1762 | case N_SIZE: |
e5e612ae | 1763 | cli->dirblocksize = getstr(value, opts, subopt); |
98d40922 DC |
1764 | break; |
1765 | case N_VERSION: | |
e5e612ae | 1766 | value = getstr(value, &nopts, subopt); |
98d40922 DC |
1767 | if (!strcasecmp(value, "ci")) { |
1768 | /* ASCII CI mode */ | |
1769 | cli->sb_feat.nci = true; | |
1770 | } else { | |
e5e612ae | 1771 | cli->sb_feat.dir_version = getnum(value, opts, subopt); |
98d40922 | 1772 | } |
8b4002e0 | 1773 | free((char *)value); |
98d40922 DC |
1774 | break; |
1775 | case N_FTYPE: | |
e5e612ae | 1776 | cli->sb_feat.dirftype = getnum(value, opts, subopt); |
98d40922 DC |
1777 | break; |
1778 | default: | |
1779 | return -EINVAL; | |
1780 | } | |
a350bbc1 DC |
1781 | return 0; |
1782 | } | |
1783 | ||
fb22e1b1 DW |
1784 | static int |
1785 | proto_opts_parser( | |
1786 | struct opt_params *opts, | |
1787 | int subopt, | |
1788 | const char *value, | |
1789 | struct cli_params *cli) | |
1790 | { | |
1791 | switch (subopt) { | |
e0aeb058 DW |
1792 | case P_SLASHES: |
1793 | cli->proto_slashes_are_spaces = getnum(value, opts, subopt); | |
1794 | break; | |
fb22e1b1 DW |
1795 | case P_FILE: |
1796 | fallthrough; | |
1797 | default: | |
1798 | if (cli->protofile) { | |
1799 | if (subopt < 0) | |
1800 | subopt = P_FILE; | |
1801 | respec(opts->name, opts->subopts, subopt); | |
1802 | } | |
1803 | cli->protofile = strdup(value); | |
1804 | if (!cli->protofile) { | |
1805 | fprintf(stderr, | |
1806 | _("Out of memory while saving protofile option.\n")); | |
1807 | exit(1); | |
1808 | } | |
1809 | break; | |
1810 | } | |
1811 | return 0; | |
1812 | } | |
1813 | ||
a350bbc1 DC |
1814 | static int |
1815 | rtdev_opts_parser( | |
1816 | struct opt_params *opts, | |
1817 | int subopt, | |
9c2b30c8 | 1818 | const char *value, |
a350bbc1 DC |
1819 | struct cli_params *cli) |
1820 | { | |
d145f69d DC |
1821 | switch (subopt) { |
1822 | case R_EXTSIZE: | |
e5e612ae | 1823 | cli->rtextsize = getstr(value, opts, subopt); |
d145f69d DC |
1824 | break; |
1825 | case R_FILE: | |
e5e612ae | 1826 | cli->xi->risfile = getnum(value, opts, subopt); |
d145f69d DC |
1827 | break; |
1828 | case R_NAME: | |
1829 | case R_DEV: | |
e5e612ae | 1830 | cli->xi->rtname = getstr(value, opts, subopt); |
d145f69d DC |
1831 | break; |
1832 | case R_SIZE: | |
e5e612ae | 1833 | cli->rtsize = getstr(value, opts, subopt); |
d145f69d DC |
1834 | break; |
1835 | case R_NOALIGN: | |
e5e612ae | 1836 | cli->sb_feat.nortalign = getnum(value, opts, subopt); |
d145f69d DC |
1837 | break; |
1838 | default: | |
1839 | return -EINVAL; | |
1840 | } | |
a350bbc1 DC |
1841 | return 0; |
1842 | } | |
1843 | ||
1844 | static int | |
1845 | sector_opts_parser( | |
1846 | struct opt_params *opts, | |
1847 | int subopt, | |
9c2b30c8 | 1848 | const char *value, |
a350bbc1 DC |
1849 | struct cli_params *cli) |
1850 | { | |
f948f00a | 1851 | switch (subopt) { |
f948f00a DC |
1852 | case S_SIZE: |
1853 | case S_SECTSIZE: | |
6c75555e | 1854 | cli->sectorsize = getnum(value, opts, subopt); |
f948f00a DC |
1855 | cli->lsectorsize = cli->sectorsize; |
1856 | break; | |
1857 | default: | |
1858 | return -EINVAL; | |
1859 | } | |
a350bbc1 DC |
1860 | return 0; |
1861 | } | |
1862 | ||
00ff2b10 | 1863 | static struct subopts { |
a350bbc1 | 1864 | struct opt_params *opts; |
33dc45c6 ES |
1865 | int (*parser)(struct opt_params *opts, |
1866 | int subopt, | |
9c2b30c8 | 1867 | const char *value, |
33dc45c6 | 1868 | struct cli_params *cli); |
a350bbc1 | 1869 | } subopt_tab[] = { |
ab2eef12 DC |
1870 | { &bopts, block_opts_parser }, |
1871 | { &copts, cfgfile_opts_parser }, | |
1872 | { &dopts, data_opts_parser }, | |
1873 | { &iopts, inode_opts_parser }, | |
1874 | { &lopts, log_opts_parser }, | |
1875 | { &mopts, meta_opts_parser }, | |
1876 | { &nopts, naming_opts_parser }, | |
fb22e1b1 | 1877 | { &popts, proto_opts_parser }, |
ab2eef12 DC |
1878 | { &ropts, rtdev_opts_parser }, |
1879 | { &sopts, sector_opts_parser }, | |
1880 | { NULL, NULL }, | |
a350bbc1 DC |
1881 | }; |
1882 | ||
1883 | static void | |
1884 | parse_subopts( | |
1885 | char opt, | |
1886 | char *arg, | |
1887 | struct cli_params *cli) | |
1888 | { | |
1889 | struct subopts *sop = &subopt_tab[0]; | |
1890 | char *p; | |
1891 | int ret = 0; | |
1892 | ||
1893 | while (sop->opts) { | |
ab2eef12 | 1894 | if (sop->opts->name == opt) |
a350bbc1 DC |
1895 | break; |
1896 | sop++; | |
1897 | } | |
1898 | ||
1899 | /* should never happen */ | |
1900 | if (!sop->opts) | |
1901 | return; | |
1902 | ||
1903 | p = arg; | |
1904 | while (*p != '\0') { | |
1905 | char **subopts = (char **)sop->opts->subopts; | |
1906 | char *value; | |
1907 | int subopt; | |
1908 | ||
1909 | subopt = getsubopt(&p, subopts, &value); | |
1910 | ||
1911 | ret = (sop->parser)(sop->opts, subopt, value, cli); | |
1912 | if (ret) | |
1913 | unknown(opt, value); | |
1914 | } | |
1915 | } | |
1916 | ||
ab2eef12 DC |
1917 | static bool |
1918 | parse_cfgopt( | |
1919 | const char *section, | |
1920 | const char *name, | |
1921 | const char *value, | |
1922 | struct cli_params *cli) | |
1923 | { | |
1924 | struct subopts *sop = &subopt_tab[0]; | |
1925 | char **subopts; | |
1926 | int ret = 0; | |
1927 | int i; | |
1928 | ||
1929 | while (sop->opts) { | |
1930 | if (sop->opts->ini_section[0] != '\0' && | |
1931 | strcasecmp(section, sop->opts->ini_section) == 0) | |
1932 | break; | |
1933 | sop++; | |
1934 | } | |
1935 | ||
1936 | /* Config files with unknown sections get caught here. */ | |
1937 | if (!sop->opts) | |
1938 | goto invalid_opt; | |
1939 | ||
1940 | subopts = (char **)sop->opts->subopts; | |
1941 | for (i = 0; i < MAX_SUBOPTS; i++) { | |
1942 | if (!subopts[i]) | |
1943 | break; | |
1944 | if (strcasecmp(name, subopts[i]) == 0) { | |
1945 | ret = (sop->parser)(sop->opts, i, value, cli); | |
1946 | if (ret) | |
1947 | goto invalid_opt; | |
1948 | return true; | |
1949 | } | |
1950 | } | |
1951 | invalid_opt: | |
1952 | invalid_cfgfile_opt(cli->cfgfile, section, name, value); | |
1953 | return false; | |
1954 | } | |
1955 | ||
585f41bb DC |
1956 | static void |
1957 | validate_sectorsize( | |
1958 | struct mkfs_params *cfg, | |
1959 | struct cli_params *cli, | |
1960 | struct mkfs_default_params *dft, | |
1961 | struct fs_topology *ft, | |
585f41bb DC |
1962 | int dry_run, |
1963 | int force_overwrite) | |
1964 | { | |
585f41bb DC |
1965 | /* |
1966 | * Before anything else, verify that we are correctly operating on | |
1967 | * files or block devices and set the control parameters correctly. | |
1968 | */ | |
732f5b90 CH |
1969 | check_device_type(cli->xi->dname, &cli->xi->disfile, |
1970 | !cli->dsize, !cli->xi->dname, | |
cb46aab2 | 1971 | dry_run ? NULL : &cli->xi->dcreat, "d"); |
585f41bb DC |
1972 | if (!cli->loginternal) |
1973 | check_device_type(cli->xi->logname, &cli->xi->lisfile, | |
1974 | !cli->logsize, !cli->xi->logname, | |
cb46aab2 | 1975 | dry_run ? NULL : &cli->xi->lcreat, "l"); |
585f41bb DC |
1976 | if (cli->xi->rtname) |
1977 | check_device_type(cli->xi->rtname, &cli->xi->risfile, | |
1978 | !cli->rtsize, !cli->xi->rtname, | |
cb46aab2 | 1979 | dry_run ? NULL : &cli->xi->rcreat, "r"); |
585f41bb DC |
1980 | |
1981 | /* | |
1982 | * Explicitly disable direct IO for image files so we don't error out on | |
1983 | * sector size mismatches between the new filesystem and the underlying | |
1984 | * host filesystem. | |
1985 | */ | |
1986 | if (cli->xi->disfile || cli->xi->lisfile || cli->xi->risfile) | |
1987 | cli->xi->isdirect = 0; | |
1988 | ||
1989 | memset(ft, 0, sizeof(*ft)); | |
1990 | get_topology(cli->xi, ft, force_overwrite); | |
1991 | ||
9f9ee751 | 1992 | /* set configured sector sizes in preparation for checks */ |
585f41bb DC |
1993 | if (!cli->sectorsize) { |
1994 | /* | |
1995 | * Unless specified manually on the command line use the | |
1996 | * advertised sector size of the device. We use the physical | |
1997 | * sector size unless the requested block size is smaller | |
1998 | * than that, then we can use logical, but warn about the | |
1999 | * inefficiency. | |
2000 | * | |
2001 | * Set the topology sectors if they were not probed to the | |
2002 | * minimum supported sector size. | |
2003 | */ | |
585f41bb | 2004 | if (!ft->lsectorsize) |
9f9ee751 | 2005 | ft->lsectorsize = dft->sectorsize; |
585f41bb | 2006 | |
92abc149 JM |
2007 | /* |
2008 | * Older kernels may not have physical/logical distinction. | |
2009 | * | |
2010 | * Some architectures have a page size > XFS_MAX_SECTORSIZE. | |
2011 | * In that case, a ramdisk or persistent memory device may | |
2012 | * advertise a physical sector size that is too big to use. | |
2013 | */ | |
2014 | if (!ft->psectorsize || ft->psectorsize > XFS_MAX_SECTORSIZE) | |
585f41bb DC |
2015 | ft->psectorsize = ft->lsectorsize; |
2016 | ||
2017 | cfg->sectorsize = ft->psectorsize; | |
2018 | if (cfg->blocksize < cfg->sectorsize && | |
2019 | cfg->blocksize >= ft->lsectorsize) { | |
2020 | fprintf(stderr, | |
2021 | _("specified blocksize %d is less than device physical sector size %d\n" | |
2022 | "switching to logical sector size %d\n"), | |
2023 | cfg->blocksize, ft->psectorsize, | |
2024 | ft->lsectorsize); | |
2025 | cfg->sectorsize = ft->lsectorsize; | |
2026 | } | |
9f9ee751 KX |
2027 | } else |
2028 | cfg->sectorsize = cli->sectorsize; | |
585f41bb | 2029 | |
9f9ee751 | 2030 | cfg->sectorlog = libxfs_highbit32(cfg->sectorsize); |
585f41bb DC |
2031 | |
2032 | /* validate specified/probed sector size */ | |
2033 | if (cfg->sectorsize < XFS_MIN_SECTORSIZE || | |
2034 | cfg->sectorsize > XFS_MAX_SECTORSIZE) { | |
2035 | fprintf(stderr, _("illegal sector size %d\n"), cfg->sectorsize); | |
2036 | usage(); | |
2037 | } | |
2038 | ||
2039 | if (cfg->blocksize < cfg->sectorsize) { | |
2040 | fprintf(stderr, | |
2041 | _("block size %d cannot be smaller than sector size %d\n"), | |
2042 | cfg->blocksize, cfg->sectorsize); | |
2043 | usage(); | |
2044 | } | |
2045 | ||
2046 | if (cfg->sectorsize < ft->lsectorsize) { | |
2047 | fprintf(stderr, _("illegal sector size %d; hw sector is %d\n"), | |
2048 | cfg->sectorsize, ft->lsectorsize); | |
2049 | usage(); | |
2050 | } | |
2051 | } | |
2052 | ||
b1b8e54e DC |
2053 | static void |
2054 | validate_blocksize( | |
2055 | struct mkfs_params *cfg, | |
2056 | struct cli_params *cli, | |
2057 | struct mkfs_default_params *dft) | |
2058 | { | |
2059 | /* | |
2060 | * Blocksize and sectorsize first, other things depend on them | |
2061 | * For RAID4/5/6 we want to align sector size and block size, | |
2062 | * so we need to start with the device geometry extraction too. | |
2063 | */ | |
2064 | if (!cli->blocksize) | |
2065 | cfg->blocksize = dft->blocksize; | |
2066 | else | |
2067 | cfg->blocksize = cli->blocksize; | |
2068 | cfg->blocklog = libxfs_highbit32(cfg->blocksize); | |
2069 | ||
2070 | /* validate block sizes are in range */ | |
2071 | if (cfg->blocksize < XFS_MIN_BLOCKSIZE || | |
2072 | cfg->blocksize > XFS_MAX_BLOCKSIZE) { | |
2073 | fprintf(stderr, _("illegal block size %d\n"), cfg->blocksize); | |
2074 | usage(); | |
2075 | } | |
2076 | ||
2077 | if (cli->sb_feat.crcs_enabled && | |
2078 | cfg->blocksize < XFS_MIN_CRC_BLOCKSIZE) { | |
2079 | fprintf(stderr, | |
2080 | _("Minimum block size for CRC enabled filesystems is %d bytes.\n"), | |
2081 | XFS_MIN_CRC_BLOCKSIZE); | |
2082 | usage(); | |
2083 | } | |
2084 | ||
2085 | } | |
2086 | ||
22319b56 DC |
2087 | /* |
2088 | * Grab log sector size and validate. | |
2089 | * | |
2090 | * XXX: should we probe sector size on external log device rather than using | |
2091 | * the data device sector size? | |
2092 | */ | |
2093 | static void | |
2094 | validate_log_sectorsize( | |
2095 | struct mkfs_params *cfg, | |
2096 | struct cli_params *cli, | |
2097 | struct mkfs_default_params *dft) | |
2098 | { | |
2099 | ||
2100 | if (cli->loginternal && cli->lsectorsize && | |
2101 | cli->lsectorsize != cfg->sectorsize) { | |
2102 | fprintf(stderr, | |
2103 | _("Can't change sector size on internal log!\n")); | |
2104 | usage(); | |
2105 | } | |
2106 | ||
2107 | if (cli->lsectorsize) | |
2108 | cfg->lsectorsize = cli->lsectorsize; | |
2109 | else if (cli->loginternal) | |
2110 | cfg->lsectorsize = cfg->sectorsize; | |
2111 | else | |
2112 | cfg->lsectorsize = dft->sectorsize; | |
2113 | cfg->lsectorlog = libxfs_highbit32(cfg->lsectorsize); | |
2114 | ||
2115 | if (cfg->lsectorsize < XFS_MIN_SECTORSIZE || | |
2116 | cfg->lsectorsize > XFS_MAX_SECTORSIZE || | |
2117 | cfg->lsectorsize > cfg->blocksize) { | |
2118 | fprintf(stderr, _("illegal log sector size %d\n"), | |
2119 | cfg->lsectorsize); | |
2120 | usage(); | |
2121 | } | |
2122 | if (cfg->lsectorsize > XFS_MIN_SECTORSIZE) { | |
2123 | if (cli->sb_feat.log_version < 2) { | |
2124 | /* user specified non-default log version */ | |
2125 | fprintf(stderr, | |
2126 | _("Version 1 logs do not support sector size %d\n"), | |
2127 | cfg->lsectorsize); | |
2128 | usage(); | |
2129 | } | |
2130 | } | |
2131 | ||
2132 | /* if lsu or lsunit was specified, automatically use v2 logs */ | |
2133 | if ((cli_opt_set(&lopts, L_SU) || cli_opt_set(&lopts, L_SUNIT)) && | |
2134 | cli->sb_feat.log_version == 1) { | |
2135 | fprintf(stderr, | |
2136 | _("log stripe unit specified, using v2 logs\n")); | |
2137 | cli->sb_feat.log_version = 2; | |
2138 | } | |
2139 | ||
2140 | } | |
2141 | ||
a43e656b DC |
2142 | /* |
2143 | * Check that the incoming features make sense. The CLI structure was | |
2144 | * initialised with the default values before parsing, so we can just | |
2145 | * check it and copy it straight across to the cfg structure if it | |
2146 | * checks out. | |
2147 | */ | |
2148 | static void | |
2149 | validate_sb_features( | |
2150 | struct mkfs_params *cfg, | |
2151 | struct cli_params *cli) | |
2152 | { | |
6a5285ec DW |
2153 | if (cli->sb_feat.nci) { |
2154 | /* | |
2155 | * The ascii-ci feature is deprecated in the upstream Linux | |
2156 | * kernel. In September 2025 it will be turned off by default | |
2157 | * in the kernel and in September 2030 support will be removed | |
2158 | * entirely. | |
2159 | */ | |
2160 | fprintf(stdout, | |
2161 | _("ascii-ci filesystems are deprecated and will not be supported by future versions.\n")); | |
2162 | } | |
2163 | ||
a43e656b DC |
2164 | /* |
2165 | * Now we have blocks and sector sizes set up, check parameters that are | |
2166 | * no longer optional for CRC enabled filesystems. Catch them up front | |
2167 | * here before doing anything else. | |
2168 | */ | |
2169 | if (cli->sb_feat.crcs_enabled) { | |
2170 | /* minimum inode size is 512 bytes, rest checked later */ | |
2171 | if (cli->inodesize && | |
2172 | cli->inodesize < (1 << XFS_DINODE_DFL_CRC_LOG)) { | |
2173 | fprintf(stderr, | |
2174 | _("Minimum inode size for CRCs is %d bytes\n"), | |
2175 | 1 << XFS_DINODE_DFL_CRC_LOG); | |
2176 | usage(); | |
2177 | } | |
2178 | ||
2179 | /* inodes always aligned */ | |
2180 | if (!cli->sb_feat.inode_align) { | |
2181 | fprintf(stderr, | |
9ae168bb | 2182 | _("Inodes always aligned for CRC enabled filesystems\n")); |
a43e656b DC |
2183 | usage(); |
2184 | } | |
2185 | ||
2186 | /* lazy sb counters always on */ | |
2187 | if (!cli->sb_feat.lazy_sb_counters) { | |
2188 | fprintf(stderr, | |
9393ba67 | 2189 | _("Lazy superblock counters always enabled for CRC enabled filesystems\n")); |
a43e656b DC |
2190 | usage(); |
2191 | } | |
2192 | ||
2193 | /* version 2 logs always on */ | |
2194 | if (cli->sb_feat.log_version != 2) { | |
2195 | fprintf(stderr, | |
9ae168bb | 2196 | _("V2 logs always enabled for CRC enabled filesystems\n")); |
a43e656b DC |
2197 | usage(); |
2198 | } | |
2199 | ||
2200 | /* attr2 always on */ | |
2201 | if (cli->sb_feat.attr_version != 2) { | |
2202 | fprintf(stderr, | |
9ae168bb | 2203 | _("V2 attribute format always enabled on CRC enabled filesystems\n")); |
a43e656b DC |
2204 | usage(); |
2205 | } | |
2206 | ||
2207 | /* 32 bit project quota always on */ | |
2208 | /* attr2 always on */ | |
639d0b0b | 2209 | if (!cli->sb_feat.projid32bit) { |
a43e656b | 2210 | fprintf(stderr, |
9ae168bb | 2211 | _("32 bit Project IDs always enabled on CRC enabled filesystems\n")); |
a43e656b DC |
2212 | usage(); |
2213 | } | |
2214 | ||
2215 | /* ftype always on */ | |
2216 | if (!cli->sb_feat.dirftype) { | |
2217 | fprintf(stderr, | |
9ae168bb | 2218 | _("Directory ftype field always enabled on CRC enabled filesystems\n")); |
a43e656b DC |
2219 | usage(); |
2220 | } | |
2221 | ||
ec1b42e6 | 2222 | } else { /* !crcs_enabled */ |
fc239bcb DW |
2223 | /* |
2224 | * The V4 filesystem format is deprecated in the upstream Linux | |
2225 | * kernel. In September 2025 it will be turned off by default | |
2226 | * in the kernel and in September 2030 support will be removed | |
2227 | * entirely. | |
2228 | */ | |
2229 | fprintf(stdout, | |
2230 | _("V4 filesystems are deprecated and will not be supported by future versions.\n")); | |
2231 | ||
a43e656b | 2232 | /* |
ec1b42e6 DW |
2233 | * The kernel doesn't support crc=0,finobt=1 filesystems. |
2234 | * If crcs are not enabled and the user has not explicitly | |
2235 | * turned finobt on, then silently turn it off to avoid an | |
2236 | * unnecessary warning. | |
a43e656b DC |
2237 | * If the user explicitly tried to use crc=0,finobt=1, |
2238 | * then issue an error. | |
ec1b42e6 | 2239 | * The same is also true for sparse inodes and reflink. |
a43e656b DC |
2240 | */ |
2241 | if (cli->sb_feat.finobt && cli_opt_set(&mopts, M_FINOBT)) { | |
2242 | fprintf(stderr, | |
2243 | _("finobt not supported without CRC support\n")); | |
2244 | usage(); | |
2245 | } | |
2246 | cli->sb_feat.finobt = false; | |
2247 | ||
9cf846b5 | 2248 | if (cli->sb_feat.spinodes && cli_opt_set(&iopts, I_SPINODES)) { |
a43e656b DC |
2249 | fprintf(stderr, |
2250 | _("sparse inodes not supported without CRC support\n")); | |
2251 | usage(); | |
2252 | } | |
2253 | cli->sb_feat.spinodes = false; | |
2254 | ||
4e568074 | 2255 | if (cli->sb_feat.rmapbt && cli_opt_set(&mopts, M_RMAPBT)) { |
a43e656b DC |
2256 | fprintf(stderr, |
2257 | _("rmapbt not supported without CRC support\n")); | |
2258 | usage(); | |
2259 | } | |
2260 | cli->sb_feat.rmapbt = false; | |
2261 | ||
ec1b42e6 | 2262 | if (cli->sb_feat.reflink && cli_opt_set(&mopts, M_REFLINK)) { |
a43e656b DC |
2263 | fprintf(stderr, |
2264 | _("reflink not supported without CRC support\n")); | |
2265 | usage(); | |
2266 | } | |
2267 | cli->sb_feat.reflink = false; | |
9eb0d6eb DW |
2268 | |
2269 | if (cli->sb_feat.inobtcnt && cli_opt_set(&mopts, M_INOBTCNT)) { | |
2270 | fprintf(stderr, | |
2271 | _("inode btree counters not supported without CRC support\n")); | |
2272 | usage(); | |
2273 | } | |
2274 | cli->sb_feat.inobtcnt = false; | |
e9601810 DW |
2275 | |
2276 | if (cli->sb_feat.bigtime && cli_opt_set(&mopts, M_BIGTIME)) { | |
2277 | fprintf(stderr, | |
2278 | _("timestamps later than 2038 not supported without CRC support\n")); | |
2279 | usage(); | |
2280 | } | |
2281 | cli->sb_feat.bigtime = false; | |
69e72722 CB |
2282 | |
2283 | if (cli->sb_feat.nrext64 && | |
2284 | cli_opt_set(&iopts, I_NREXT64)) { | |
2285 | fprintf(stderr, | |
2286 | _("64 bit extent count not supported without CRC support\n")); | |
2287 | usage(); | |
2288 | } | |
2289 | cli->sb_feat.nrext64 = false; | |
9eb0d6eb DW |
2290 | } |
2291 | ||
2292 | if (!cli->sb_feat.finobt) { | |
2293 | if (cli->sb_feat.inobtcnt && cli_opt_set(&mopts, M_INOBTCNT)) { | |
2294 | fprintf(stderr, | |
2295 | _("inode btree counters not supported without finobt support\n")); | |
2296 | usage(); | |
2297 | } | |
2298 | cli->sb_feat.inobtcnt = false; | |
a43e656b DC |
2299 | } |
2300 | ||
4e568074 DW |
2301 | if (cli->xi->rtname) { |
2302 | if (cli->sb_feat.reflink && cli_opt_set(&mopts, M_REFLINK)) { | |
2303 | fprintf(stderr, | |
bfa66ecd | 2304 | _("reflink not supported with realtime devices\n")); |
4e568074 DW |
2305 | usage(); |
2306 | } | |
bfa66ecd | 2307 | cli->sb_feat.reflink = false; |
bfa66ecd | 2308 | |
4e568074 DW |
2309 | if (cli->sb_feat.rmapbt && cli_opt_set(&mopts, M_RMAPBT)) { |
2310 | fprintf(stderr, | |
a43e656b | 2311 | _("rmapbt not supported with realtime devices\n")); |
4e568074 DW |
2312 | usage(); |
2313 | } | |
a43e656b DC |
2314 | cli->sb_feat.rmapbt = false; |
2315 | } | |
2316 | ||
28927ccb DW |
2317 | if ((cli->fsx.fsx_xflags & FS_XFLAG_COWEXTSIZE) && |
2318 | !cli->sb_feat.reflink) { | |
2319 | fprintf(stderr, | |
2320 | _("cowextsize not supported without reflink support\n")); | |
2321 | usage(); | |
2322 | } | |
2323 | ||
a43e656b DC |
2324 | /* |
2325 | * Copy features across to config structure now. | |
2326 | */ | |
2327 | cfg->sb_feat = cli->sb_feat; | |
2328 | if (!platform_uuid_is_null(&cli->uuid)) | |
2329 | platform_uuid_copy(&cfg->uuid, &cli->uuid); | |
2330 | } | |
2331 | ||
fdea8fbc DC |
2332 | static void |
2333 | validate_dirblocksize( | |
2334 | struct mkfs_params *cfg, | |
2335 | struct cli_params *cli) | |
2336 | { | |
2337 | ||
2338 | if (cli->dirblocksize) | |
2339 | cfg->dirblocksize = getnum(cli->dirblocksize, &nopts, N_SIZE); | |
fdea8fbc DC |
2340 | |
2341 | if (cfg->dirblocksize) { | |
2342 | if (cfg->dirblocksize < cfg->blocksize || | |
2343 | cfg->dirblocksize > XFS_MAX_BLOCKSIZE) { | |
2344 | fprintf(stderr, _("illegal directory block size %d\n"), | |
2345 | cfg->dirblocksize); | |
2346 | usage(); | |
2347 | } | |
2348 | cfg->dirblocklog = libxfs_highbit32(cfg->dirblocksize); | |
2349 | return; | |
2350 | } | |
2351 | ||
2352 | /* use default size based on current block size */ | |
2353 | if (cfg->blocksize < (1 << XFS_MIN_REC_DIRSIZE)) | |
2354 | cfg->dirblocklog = XFS_MIN_REC_DIRSIZE; | |
2355 | else | |
2356 | cfg->dirblocklog = cfg->blocklog; | |
2357 | cfg->dirblocksize = 1 << cfg->dirblocklog; | |
2358 | } | |
2359 | ||
8fe29028 DC |
2360 | static void |
2361 | validate_inodesize( | |
2362 | struct mkfs_params *cfg, | |
2363 | struct cli_params *cli) | |
2364 | { | |
2365 | ||
2366 | if (cli->inopblock) | |
2367 | cfg->inodelog = cfg->blocklog - libxfs_highbit32(cli->inopblock); | |
2368 | else if (cli->inodesize) | |
2369 | cfg->inodelog = libxfs_highbit32(cli->inodesize); | |
2370 | else if (cfg->sb_feat.crcs_enabled) | |
2371 | cfg->inodelog = XFS_DINODE_DFL_CRC_LOG; | |
2372 | else | |
2373 | cfg->inodelog = XFS_DINODE_DFL_LOG; | |
2374 | ||
2375 | cfg->inodesize = 1 << cfg->inodelog; | |
2376 | cfg->inopblock = cfg->blocksize / cfg->inodesize; | |
2377 | ||
2378 | /* input parsing has already validated non-crc inode size range */ | |
2379 | if (cfg->sb_feat.crcs_enabled && | |
2380 | cfg->inodelog < XFS_DINODE_DFL_CRC_LOG) { | |
2381 | fprintf(stderr, | |
2382 | _("Minimum inode size for CRCs is %d bytes\n"), | |
2383 | 1 << XFS_DINODE_DFL_CRC_LOG); | |
2384 | usage(); | |
2385 | } | |
2386 | ||
2387 | if (cfg->inodesize > cfg->blocksize / XFS_MIN_INODE_PERBLOCK || | |
2388 | cfg->inopblock < XFS_MIN_INODE_PERBLOCK || | |
2389 | cfg->inodesize < XFS_DINODE_MIN_SIZE || | |
2390 | cfg->inodesize > XFS_DINODE_MAX_SIZE) { | |
2391 | int maxsz; | |
2392 | ||
2393 | fprintf(stderr, _("illegal inode size %d\n"), cfg->inodesize); | |
68d16907 | 2394 | maxsz = min(cfg->blocksize / XFS_MIN_INODE_PERBLOCK, |
8fe29028 DC |
2395 | XFS_DINODE_MAX_SIZE); |
2396 | if (XFS_DINODE_MIN_SIZE == maxsz) | |
2397 | fprintf(stderr, | |
2398 | _("allowable inode size with %d byte blocks is %d\n"), | |
2399 | cfg->blocksize, XFS_DINODE_MIN_SIZE); | |
2400 | else | |
2401 | fprintf(stderr, | |
2402 | _("allowable inode size with %d byte blocks is between %d and %d\n"), | |
2403 | cfg->blocksize, XFS_DINODE_MIN_SIZE, maxsz); | |
2404 | exit(1); | |
2405 | } | |
2406 | } | |
2407 | ||
e24dfa22 DC |
2408 | static xfs_rfsblock_t |
2409 | calc_dev_size( | |
2410 | char *size, | |
2411 | struct mkfs_params *cfg, | |
2412 | struct opt_params *opts, | |
2413 | int sizeopt, | |
2414 | char *type) | |
2415 | { | |
2416 | uint64_t dbytes; | |
2417 | xfs_rfsblock_t dblocks; | |
2418 | ||
2419 | if (!size) | |
2420 | return 0; | |
2421 | ||
2422 | dbytes = getnum(size, opts, sizeopt); | |
2423 | if (dbytes % XFS_MIN_BLOCKSIZE) { | |
2424 | fprintf(stderr, | |
2425 | _("illegal %s length %lld, not a multiple of %d\n"), | |
2426 | type, (long long)dbytes, XFS_MIN_BLOCKSIZE); | |
2427 | usage(); | |
2428 | } | |
2429 | dblocks = (xfs_rfsblock_t)(dbytes >> cfg->blocklog); | |
2430 | if (dbytes % cfg->blocksize) { | |
2431 | fprintf(stderr, | |
2432 | _("warning: %s length %lld not a multiple of %d, truncated to %lld\n"), | |
2433 | type, (long long)dbytes, cfg->blocksize, | |
2434 | (long long)(dblocks << cfg->blocklog)); | |
2435 | } | |
2436 | return dblocks; | |
2437 | } | |
2438 | ||
80b154f7 DC |
2439 | static void |
2440 | validate_rtextsize( | |
2441 | struct mkfs_params *cfg, | |
2442 | struct cli_params *cli, | |
2443 | struct fs_topology *ft) | |
2444 | { | |
2445 | uint64_t rtextbytes; | |
2446 | ||
2447 | /* | |
2448 | * If specified, check rt extent size against its constraints. | |
2449 | */ | |
2450 | if (cli->rtextsize) { | |
2451 | ||
2452 | rtextbytes = getnum(cli->rtextsize, &ropts, R_EXTSIZE); | |
2453 | if (rtextbytes % cfg->blocksize) { | |
2454 | fprintf(stderr, | |
2455 | _("illegal rt extent size %lld, not a multiple of %d\n"), | |
2456 | (long long)rtextbytes, cfg->blocksize); | |
2457 | usage(); | |
2458 | } | |
2459 | cfg->rtextblocks = (xfs_extlen_t)(rtextbytes >> cfg->blocklog); | |
2460 | } else { | |
2461 | /* | |
2462 | * If realtime extsize has not been specified by the user, | |
2463 | * and the underlying volume is striped, then set rtextblocks | |
2464 | * to the stripe width. | |
2465 | */ | |
2466 | uint64_t rswidth; | |
2467 | ||
2468 | if (!cfg->sb_feat.nortalign && !cli->xi->risfile && | |
2469 | !(!cli->rtsize && cli->xi->disfile)) | |
2470 | rswidth = ft->rtswidth; | |
2471 | else | |
2472 | rswidth = 0; | |
2473 | ||
2474 | /* check that rswidth is a multiple of fs blocksize */ | |
2475 | if (!cfg->sb_feat.nortalign && rswidth && | |
2476 | !(BBTOB(rswidth) % cfg->blocksize)) { | |
2477 | rswidth = DTOBT(rswidth, cfg->blocklog); | |
2478 | rtextbytes = rswidth << cfg->blocklog; | |
2479 | if (rtextbytes > XFS_MIN_RTEXTSIZE && | |
2480 | rtextbytes <= XFS_MAX_RTEXTSIZE) { | |
2481 | cfg->rtextblocks = rswidth; | |
2482 | } | |
2483 | } | |
2484 | if (!cfg->rtextblocks) { | |
2485 | cfg->rtextblocks = (cfg->blocksize < XFS_MIN_RTEXTSIZE) | |
2486 | ? XFS_MIN_RTEXTSIZE >> cfg->blocklog | |
2487 | : 1; | |
2488 | } | |
2489 | } | |
2490 | ASSERT(cfg->rtextblocks); | |
2491 | } | |
2492 | ||
9cfe71ba DW |
2493 | /* Validate the incoming extsize hint. */ |
2494 | static void | |
2495 | validate_extsize_hint( | |
2496 | struct xfs_mount *mp, | |
2497 | struct cli_params *cli) | |
2498 | { | |
2499 | xfs_failaddr_t fa; | |
2500 | uint16_t flags = 0; | |
2501 | ||
2502 | /* | |
2503 | * First we validate the extent size inherit hint on a directory so | |
2504 | * that we know that we'll be propagating a correct hint and flag to | |
2505 | * new files on the data device. | |
2506 | */ | |
00d139f1 | 2507 | if (cli->fsx.fsx_xflags & FS_XFLAG_EXTSZINHERIT) |
9cfe71ba DW |
2508 | flags |= XFS_DIFLAG_EXTSZINHERIT; |
2509 | ||
2510 | fa = libxfs_inode_validate_extsize(mp, cli->fsx.fsx_extsize, S_IFDIR, | |
2511 | flags); | |
2512 | if (fa) { | |
2513 | fprintf(stderr, | |
2514 | _("illegal extent size hint %lld, must be less than %u.\n"), | |
2515 | (long long)cli->fsx.fsx_extsize, | |
d3e0c71f | 2516 | min(XFS_MAX_BMBT_EXTLEN, mp->m_sb.sb_agblocks / 2)); |
9cfe71ba DW |
2517 | usage(); |
2518 | } | |
2519 | ||
2520 | /* | |
1e8afffb DW |
2521 | * If the value is to be passed on to realtime files, revalidate with |
2522 | * a realtime file so that we know the hint and flag that get passed on | |
2523 | * to realtime files will be correct. | |
9cfe71ba | 2524 | */ |
1e8afffb | 2525 | if (!(cli->fsx.fsx_xflags & FS_XFLAG_RTINHERIT)) |
9cfe71ba DW |
2526 | return; |
2527 | ||
2528 | flags = XFS_DIFLAG_REALTIME; | |
00d139f1 | 2529 | if (cli->fsx.fsx_xflags & FS_XFLAG_EXTSZINHERIT) |
9cfe71ba DW |
2530 | flags |= XFS_DIFLAG_EXTSIZE; |
2531 | ||
2532 | fa = libxfs_inode_validate_extsize(mp, cli->fsx.fsx_extsize, S_IFREG, | |
2533 | flags); | |
2534 | ||
2535 | if (fa) { | |
2536 | fprintf(stderr, | |
2537 | _("illegal extent size hint %lld, must be less than %u and a multiple of %u.\n"), | |
2538 | (long long)cli->fsx.fsx_extsize, | |
d3e0c71f | 2539 | min(XFS_MAX_BMBT_EXTLEN, mp->m_sb.sb_agblocks / 2), |
9cfe71ba DW |
2540 | mp->m_sb.sb_rextsize); |
2541 | usage(); | |
2542 | } | |
2543 | } | |
2544 | ||
2545 | /* Validate the incoming CoW extsize hint. */ | |
2546 | static void | |
2547 | validate_cowextsize_hint( | |
2548 | struct xfs_mount *mp, | |
2549 | struct cli_params *cli) | |
2550 | { | |
2551 | xfs_failaddr_t fa; | |
2552 | uint64_t flags2 = 0; | |
2553 | ||
2554 | /* | |
2555 | * Validate the copy on write extent size inherit hint on a directory | |
2556 | * so that we know that we'll be propagating a correct hint and flag to | |
2557 | * new files on the data device. | |
2558 | */ | |
2559 | if (cli->fsx.fsx_xflags & FS_XFLAG_COWEXTSIZE) | |
2560 | flags2 |= XFS_DIFLAG2_COWEXTSIZE; | |
2561 | ||
2562 | fa = libxfs_inode_validate_cowextsize(mp, cli->fsx.fsx_cowextsize, | |
2563 | S_IFDIR, 0, flags2); | |
2564 | if (fa) { | |
2565 | fprintf(stderr, | |
2566 | _("illegal CoW extent size hint %lld, must be less than %u.\n"), | |
2567 | (long long)cli->fsx.fsx_cowextsize, | |
d3e0c71f | 2568 | min(XFS_MAX_BMBT_EXTLEN, mp->m_sb.sb_agblocks / 2)); |
9cfe71ba DW |
2569 | usage(); |
2570 | } | |
2571 | } | |
2572 | ||
6e0ed3d1 DW |
2573 | /* Complain if this filesystem is not a supported configuration. */ |
2574 | static void | |
2575 | validate_supported( | |
2576 | struct xfs_mount *mp, | |
2577 | struct cli_params *cli) | |
2578 | { | |
2579 | /* Undocumented option to enable unsupported tiny filesystems. */ | |
2580 | if (!cli->is_supported) { | |
2581 | printf( | |
2582 | _("Filesystems formatted with --unsupported are not supported!!\n")); | |
2583 | return; | |
2584 | } | |
2585 | ||
2586 | /* | |
2587 | * fstests has a large number of tests that create tiny filesystems to | |
2588 | * perform specific regression and resource depletion tests in a | |
2589 | * controlled environment. Avoid breaking fstests by allowing | |
2590 | * unsupported configurations if TEST_DIR, TEST_DEV, and QA_CHECK_FS | |
2591 | * are all set. | |
2592 | */ | |
2593 | if (getenv("TEST_DIR") && getenv("TEST_DEV") && getenv("QA_CHECK_FS")) | |
2594 | return; | |
2595 | ||
2596 | /* | |
2597 | * We don't support filesystems smaller than 300MB anymore. Tiny | |
2598 | * filesystems have never been XFS' design target. This limit has been | |
2599 | * carefully calculated to prevent formatting with a log smaller than | |
2600 | * the "realistic" size. | |
2601 | * | |
2602 | * If the realistic log size is 64MB, there are four AGs, and the log | |
2603 | * AG should be at least 1/8 free after formatting, this gives us: | |
2604 | * | |
2605 | * 64MB * (8 / 7) * 4 = 293MB | |
2606 | */ | |
2607 | if (mp->m_sb.sb_dblocks < MEGABYTES(300, mp->m_sb.sb_blocklog)) { | |
2608 | fprintf(stderr, | |
2609 | _("Filesystem must be larger than 300MB.\n")); | |
2610 | usage(); | |
2611 | } | |
2612 | ||
2613 | /* | |
2614 | * For best performance, we don't allow unrealistically small logs. | |
2615 | * See the comment for XFS_MIN_REALISTIC_LOG_BLOCKS. | |
2616 | */ | |
2617 | if (mp->m_sb.sb_logblocks < | |
2618 | XFS_MIN_REALISTIC_LOG_BLOCKS(mp->m_sb.sb_blocklog)) { | |
2619 | fprintf(stderr, | |
2620 | _("Log size must be at least 64MB.\n")); | |
2621 | usage(); | |
2622 | } | |
2623 | ||
2624 | /* | |
2625 | * Filesystems should not have fewer than two AGs, because we need to | |
2626 | * have redundant superblocks. | |
2627 | */ | |
2628 | if (mp->m_sb.sb_agcount < 2) { | |
2629 | fprintf(stderr, | |
2630 | _("Filesystem must have at least 2 superblocks for redundancy!\n")); | |
2631 | usage(); | |
2632 | } | |
2633 | } | |
2634 | ||
2f44b1b0 DC |
2635 | /* |
2636 | * Validate the configured stripe geometry, or is none is specified, pull | |
2637 | * the configuration from the underlying device. | |
2638 | * | |
2639 | * CLI parameters come in as different units, go out as filesystem blocks. | |
2640 | */ | |
2641 | static void | |
2642 | calc_stripe_factors( | |
2643 | struct mkfs_params *cfg, | |
2644 | struct cli_params *cli, | |
2645 | struct fs_topology *ft) | |
2646 | { | |
91c7d131 | 2647 | long long int big_dswidth; |
2f44b1b0 DC |
2648 | int dsunit = 0; |
2649 | int dswidth = 0; | |
2650 | int lsunit = 0; | |
2651 | int dsu = 0; | |
2652 | int dsw = 0; | |
2653 | int lsu = 0; | |
2654 | bool use_dev = false; | |
2655 | ||
2656 | if (cli_opt_set(&dopts, D_SUNIT)) | |
2657 | dsunit = cli->dsunit; | |
2658 | if (cli_opt_set(&dopts, D_SWIDTH)) | |
2659 | dswidth = cli->dswidth; | |
2660 | ||
2661 | if (cli_opt_set(&dopts, D_SU)) | |
2662 | dsu = getnum(cli->dsu, &dopts, D_SU); | |
2663 | if (cli_opt_set(&dopts, D_SW)) | |
2664 | dsw = cli->dsw; | |
2665 | ||
2666 | /* data sunit/swidth options */ | |
16adcb88 | 2667 | if (cli_opt_set(&dopts, D_SUNIT) != cli_opt_set(&dopts, D_SWIDTH)) { |
2f44b1b0 DC |
2668 | fprintf(stderr, |
2669 | _("both data sunit and data swidth options must be specified\n")); | |
2670 | usage(); | |
2671 | } | |
2672 | ||
2673 | /* convert dsu/dsw to dsunit/dswidth and use them from now on */ | |
2674 | if (dsu || dsw) { | |
16adcb88 | 2675 | if (cli_opt_set(&dopts, D_SU) != cli_opt_set(&dopts, D_SW)) { |
2f44b1b0 DC |
2676 | fprintf(stderr, |
2677 | _("both data su and data sw options must be specified\n")); | |
2678 | usage(); | |
2679 | } | |
2680 | ||
060ea87a GX |
2681 | big_dswidth = (long long int)dsu * dsw; |
2682 | if (BTOBBT(big_dswidth) > INT_MAX) { | |
2f44b1b0 | 2683 | fprintf(stderr, |
060ea87a GX |
2684 | _("data stripe width (%lld) is too large of a multiple of the data stripe unit (%d)\n"), |
2685 | big_dswidth, dsu); | |
2f44b1b0 DC |
2686 | usage(); |
2687 | } | |
2688 | ||
060ea87a GX |
2689 | if (!libxfs_validate_stripe_geometry(NULL, dsu, big_dswidth, |
2690 | cfg->sectorsize, false)) | |
91c7d131 | 2691 | usage(); |
2f44b1b0 | 2692 | |
060ea87a GX |
2693 | dsunit = BTOBBT(dsu); |
2694 | dswidth = BTOBBT(big_dswidth); | |
2695 | } else if (!libxfs_validate_stripe_geometry(NULL, BBTOB(dsunit), | |
2696 | BBTOB(dswidth), cfg->sectorsize, false)) { | |
2f44b1b0 DC |
2697 | usage(); |
2698 | } | |
2699 | ||
2700 | /* If sunit & swidth were manually specified as 0, same as noalign */ | |
2701 | if ((cli_opt_set(&dopts, D_SUNIT) || cli_opt_set(&dopts, D_SU)) && | |
2702 | !dsunit && !dswidth) | |
2703 | cfg->sb_feat.nodalign = true; | |
2704 | ||
2705 | /* if we are not using alignment, don't apply device defaults */ | |
2706 | if (cfg->sb_feat.nodalign) { | |
2707 | cfg->dsunit = 0; | |
2708 | cfg->dswidth = 0; | |
2709 | goto check_lsunit; | |
2710 | } | |
2711 | ||
2712 | /* if no stripe config set, use the device default */ | |
2713 | if (!dsunit) { | |
060ea87a GX |
2714 | /* Ignore nonsense from device report. */ |
2715 | if (!libxfs_validate_stripe_geometry(NULL, BBTOB(ft->dsunit), | |
2716 | BBTOB(ft->dswidth), 0, true)) { | |
99a3f52e | 2717 | fprintf(stderr, |
060ea87a GX |
2718 | _("%s: Volume reports invalid stripe unit (%d) and stripe width (%d), ignoring.\n"), |
2719 | progname, BBTOB(ft->dsunit), BBTOB(ft->dswidth)); | |
99a3f52e JM |
2720 | ft->dsunit = 0; |
2721 | ft->dswidth = 0; | |
42371fb3 DW |
2722 | } else if (cfg->dblocks < GIGABYTES(1, cfg->blocklog)) { |
2723 | /* | |
2724 | * Don't use automatic stripe detection if the device | |
2725 | * size is less than 1GB because the performance gains | |
2726 | * on such a small system are not worth the risk that | |
2727 | * we'll end up with an undersized log. | |
2728 | */ | |
2729 | if (ft->dsunit || ft->dswidth) | |
2730 | fprintf(stderr, | |
2731 | _("%s: small data volume, ignoring data volume stripe unit %d and stripe width %d\n"), | |
2732 | progname, ft->dsunit, | |
2733 | ft->dswidth); | |
2734 | ft->dsunit = 0; | |
2735 | ft->dswidth = 0; | |
99a3f52e JM |
2736 | } else { |
2737 | dsunit = ft->dsunit; | |
2738 | dswidth = ft->dswidth; | |
2739 | use_dev = true; | |
2740 | } | |
2f44b1b0 | 2741 | } else { |
99a3f52e | 2742 | /* check and warn if user-specified alignment is sub-optimal */ |
2f44b1b0 DC |
2743 | if (ft->dsunit && ft->dsunit != dsunit) { |
2744 | fprintf(stderr, | |
2745 | _("%s: Specified data stripe unit %d is not the same as the volume stripe unit %d\n"), | |
2746 | progname, dsunit, ft->dsunit); | |
2747 | } | |
2748 | if (ft->dswidth && ft->dswidth != dswidth) { | |
2749 | fprintf(stderr, | |
2750 | _("%s: Specified data stripe width %d is not the same as the volume stripe width %d\n"), | |
2751 | progname, dswidth, ft->dswidth); | |
2752 | } | |
2753 | } | |
2754 | ||
2755 | /* | |
2756 | * now we have our stripe config, check it's a multiple of block | |
2757 | * size. | |
2758 | */ | |
2759 | if ((BBTOB(dsunit) % cfg->blocksize) || | |
2760 | (BBTOB(dswidth) % cfg->blocksize)) { | |
2761 | /* | |
2762 | * If we are using device defaults, just clear them and we're | |
2763 | * good to go. Otherwise bail out with an error. | |
2764 | */ | |
2765 | if (!use_dev) { | |
2766 | fprintf(stderr, | |
2767 | _("%s: Stripe unit(%d) or stripe width(%d) is not a multiple of the block size(%d)\n"), | |
2768 | progname, BBTOB(dsunit), BBTOB(dswidth), | |
2769 | cfg->blocksize); | |
2770 | exit(1); | |
2771 | } | |
2772 | dsunit = 0; | |
2773 | dswidth = 0; | |
2774 | cfg->sb_feat.nodalign = true; | |
2775 | } | |
2776 | ||
2777 | /* convert from 512 byte blocks to fs blocksize */ | |
2778 | cfg->dsunit = DTOBT(dsunit, cfg->blocklog); | |
2779 | cfg->dswidth = DTOBT(dswidth, cfg->blocklog); | |
2780 | ||
2781 | check_lsunit: | |
2782 | /* log sunit options */ | |
2783 | if (cli_opt_set(&lopts, L_SUNIT)) | |
2784 | lsunit = cli->lsunit; | |
2785 | else if (cli_opt_set(&lopts, L_SU)) | |
2786 | lsu = getnum(cli->lsu, &lopts, L_SU); | |
2787 | else if (cfg->lsectorsize > XLOG_HEADER_SIZE) | |
2788 | lsu = cfg->blocksize; /* lsunit matches filesystem block size */ | |
2789 | ||
2790 | if (lsu) { | |
2791 | /* verify if lsu is a multiple block size */ | |
2792 | if (lsu % cfg->blocksize != 0) { | |
2793 | fprintf(stderr, | |
2794 | _("log stripe unit (%d) must be a multiple of the block size (%d)\n"), | |
2795 | lsu, cfg->blocksize); | |
2796 | usage(); | |
2797 | } | |
2798 | lsunit = (int)BTOBBT(lsu); | |
2799 | } | |
2800 | if (BBTOB(lsunit) % cfg->blocksize != 0) { | |
2801 | fprintf(stderr, | |
2802 | _("log stripe unit (%d) must be a multiple of the block size (%d)\n"), | |
2803 | BBTOB(lsunit), cfg->blocksize); | |
2804 | usage(); | |
2805 | } | |
2806 | ||
2807 | /* | |
2808 | * check that log sunit is modulo fsblksize or default it to dsunit. | |
2809 | */ | |
2810 | if (lsunit) { | |
2811 | /* convert from 512 byte blocks to fs blocks */ | |
2812 | cfg->lsunit = DTOBT(lsunit, cfg->blocklog); | |
2813 | } else if (cfg->sb_feat.log_version == 2 && | |
2814 | cfg->loginternal && cfg->dsunit) { | |
2815 | /* lsunit and dsunit now in fs blocks */ | |
2816 | cfg->lsunit = cfg->dsunit; | |
2817 | } | |
2818 | ||
2819 | if (cfg->sb_feat.log_version == 2 && | |
2820 | cfg->lsunit * cfg->blocksize > 256 * 1024) { | |
2821 | /* Warn only if specified on commandline */ | |
2822 | if (cli->lsu || cli->lsunit != -1) { | |
2823 | fprintf(stderr, | |
2824 | _("log stripe unit (%d bytes) is too large (maximum is 256KiB)\n" | |
2825 | "log stripe unit adjusted to 32KiB\n"), | |
2826 | (cfg->lsunit * cfg->blocksize)); | |
2827 | } | |
2828 | /* XXX: 64k block size? */ | |
2829 | cfg->lsunit = (32 * 1024) / cfg->blocksize; | |
2830 | } | |
2831 | ||
2832 | } | |
2833 | ||
379f01d2 DC |
2834 | static void |
2835 | open_devices( | |
2836 | struct mkfs_params *cfg, | |
915a27a0 | 2837 | struct libxfs_xinit *xi) |
379f01d2 DC |
2838 | { |
2839 | uint64_t sector_mask; | |
2840 | ||
2841 | /* | |
2842 | * Initialize. This will open the log and rt devices as well. | |
2843 | */ | |
2844 | xi->setblksize = cfg->sectorsize; | |
2845 | if (!libxfs_init(xi)) | |
2846 | usage(); | |
2847 | if (!xi->ddev) { | |
2848 | fprintf(stderr, _("no device name given in argument list\n")); | |
2849 | usage(); | |
2850 | } | |
2851 | ||
2852 | /* | |
2853 | * Ok, Linux only has a 1024-byte resolution on device _size_, | |
2854 | * and the sizes below are in basic 512-byte blocks, | |
2855 | * so if we have (size % 2), on any partition, we can't get | |
2856 | * to the last 512 bytes. The same issue exists for larger | |
2857 | * sector sizes - we cannot write past the last sector. | |
2858 | * | |
2859 | * So, we reduce the size (in basic blocks) to a perfect | |
2860 | * multiple of the sector size, or 1024, whichever is larger. | |
2861 | */ | |
68d16907 | 2862 | sector_mask = (uint64_t)-1 << (max(cfg->sectorlog, 10) - BBSHIFT); |
379f01d2 DC |
2863 | xi->dsize &= sector_mask; |
2864 | xi->rtsize &= sector_mask; | |
68d16907 | 2865 | xi->logBBsize &= (uint64_t)-1 << (max(cfg->lsectorlog, 10) - BBSHIFT); |
915a27a0 | 2866 | } |
379f01d2 | 2867 | |
915a27a0 JT |
2868 | static void |
2869 | discard_devices( | |
7e8a6edb PR |
2870 | struct libxfs_xinit *xi, |
2871 | int quiet) | |
915a27a0 JT |
2872 | { |
2873 | /* | |
2874 | *Â This function has to be called after libxfs has been initialized. | |
2875 | */ | |
379f01d2 DC |
2876 | |
2877 | if (!xi->disfile) | |
7e8a6edb | 2878 | discard_blocks(xi->ddev, xi->dsize, quiet); |
379f01d2 | 2879 | if (xi->rtdev && !xi->risfile) |
7e8a6edb | 2880 | discard_blocks(xi->rtdev, xi->rtsize, quiet); |
379f01d2 | 2881 | if (xi->logdev && xi->logdev != xi->ddev && !xi->lisfile) |
7e8a6edb | 2882 | discard_blocks(xi->logdev, xi->logBBsize, quiet); |
379f01d2 DC |
2883 | } |
2884 | ||
dd5ac314 DC |
2885 | static void |
2886 | validate_datadev( | |
2887 | struct mkfs_params *cfg, | |
2888 | struct cli_params *cli) | |
2889 | { | |
2890 | struct libxfs_xinit *xi = cli->xi; | |
2891 | ||
2892 | if (!xi->dsize) { | |
2893 | /* | |
2894 | * if the device is a file, we can't validate the size here. | |
2895 | * Instead, the file will be truncated to the correct length | |
2896 | * later on. if it's not a file, we've got a dud device. | |
2897 | */ | |
2898 | if (!xi->disfile) { | |
2899 | fprintf(stderr, _("can't get size of data subvolume\n")); | |
2900 | usage(); | |
2901 | } | |
2902 | ASSERT(cfg->dblocks); | |
2903 | } else if (cfg->dblocks) { | |
2904 | /* check the size fits into the underlying device */ | |
2905 | if (cfg->dblocks > DTOBT(xi->dsize, cfg->blocklog)) { | |
2906 | fprintf(stderr, | |
2907 | _("size %s specified for data subvolume is too large, maximum is %lld blocks\n"), | |
2908 | cli->dsize, | |
2909 | (long long)DTOBT(xi->dsize, cfg->blocklog)); | |
2910 | usage(); | |
2911 | } | |
2912 | } else { | |
2913 | /* no user size, so use the full block device */ | |
2914 | cfg->dblocks = DTOBT(xi->dsize, cfg->blocklog); | |
2915 | } | |
2916 | ||
97a40596 | 2917 | if (cfg->dblocks < XFS_MIN_DATA_BLOCKS(cfg)) { |
dd5ac314 | 2918 | fprintf(stderr, |
97a40596 PR |
2919 | _("size %lld of data subvolume is too small, minimum %lld blocks\n"), |
2920 | (long long)cfg->dblocks, XFS_MIN_DATA_BLOCKS(cfg)); | |
dd5ac314 DC |
2921 | usage(); |
2922 | } | |
2923 | ||
2924 | if (xi->dbsize > cfg->sectorsize) { | |
2925 | fprintf(stderr, _( | |
2926 | "Warning: the data subvolume sector size %u is less than the sector size \n\ | |
2927 | reported by the device (%u).\n"), | |
2928 | cfg->sectorsize, xi->dbsize); | |
2929 | } | |
2930 | } | |
2931 | ||
90b7e13d DC |
2932 | static void |
2933 | validate_logdev( | |
2934 | struct mkfs_params *cfg, | |
732f5b90 | 2935 | struct cli_params *cli) |
90b7e13d DC |
2936 | { |
2937 | struct libxfs_xinit *xi = cli->xi; | |
2938 | ||
732f5b90 | 2939 | cfg->loginternal = cli->loginternal; |
90b7e13d DC |
2940 | |
2941 | /* now run device checks */ | |
2942 | if (cfg->loginternal) { | |
90b7e13d DC |
2943 | /* |
2944 | * if no sector size has been specified on the command line, | |
2945 | * use what has been configured and validated for the data | |
2946 | * device. | |
2947 | */ | |
2948 | if (!cli->lsectorsize) { | |
2949 | cfg->lsectorsize = cfg->sectorsize; | |
2950 | cfg->lsectorlog = cfg->sectorlog; | |
2951 | } | |
2952 | ||
2953 | if (cfg->sectorsize != cfg->lsectorsize) { | |
2954 | fprintf(stderr, | |
2955 | _("data and log sector sizes must be equal for internal logs\n")); | |
2956 | usage(); | |
2957 | } | |
2958 | if (cli->logsize && cfg->logblocks >= cfg->dblocks) { | |
2959 | fprintf(stderr, | |
2960 | _("log size %lld too large for internal log\n"), | |
2961 | (long long)cfg->logblocks); | |
2962 | usage(); | |
2963 | } | |
90b7e13d DC |
2964 | return; |
2965 | } | |
2966 | ||
2967 | /* External/log subvolume checks */ | |
732f5b90 | 2968 | if (!*xi->logname || !xi->logdev) { |
90b7e13d DC |
2969 | fprintf(stderr, _("no log subvolume or external log.\n")); |
2970 | usage(); | |
2971 | } | |
2972 | ||
2973 | if (!cfg->logblocks) { | |
2974 | if (xi->logBBsize == 0) { | |
2975 | fprintf(stderr, | |
2976 | _("unable to get size of the log subvolume.\n")); | |
2977 | usage(); | |
2978 | } | |
2979 | cfg->logblocks = DTOBT(xi->logBBsize, cfg->blocklog); | |
2980 | } else if (cfg->logblocks > DTOBT(xi->logBBsize, cfg->blocklog)) { | |
2981 | fprintf(stderr, | |
2982 | _("size %s specified for log subvolume is too large, maximum is %lld blocks\n"), | |
2983 | cli->logsize, | |
2984 | (long long)DTOBT(xi->logBBsize, cfg->blocklog)); | |
2985 | usage(); | |
2986 | } | |
2987 | ||
2988 | if (xi->lbsize > cfg->lsectorsize) { | |
2989 | fprintf(stderr, _( | |
2990 | "Warning: the log subvolume sector size %u is less than the sector size\n\ | |
2991 | reported by the device (%u).\n"), | |
2992 | cfg->lsectorsize, xi->lbsize); | |
2993 | } | |
2994 | } | |
2995 | ||
7a9af89a DC |
2996 | static void |
2997 | validate_rtdev( | |
2998 | struct mkfs_params *cfg, | |
732f5b90 | 2999 | struct cli_params *cli) |
7a9af89a DC |
3000 | { |
3001 | struct libxfs_xinit *xi = cli->xi; | |
3002 | ||
7a9af89a DC |
3003 | if (!xi->rtdev) { |
3004 | if (cli->rtsize) { | |
3005 | fprintf(stderr, | |
3006 | _("size specified for non-existent rt subvolume\n")); | |
3007 | usage(); | |
3008 | } | |
3009 | ||
7a9af89a DC |
3010 | cfg->rtblocks = 0; |
3011 | cfg->rtextents = 0; | |
3012 | cfg->rtbmblocks = 0; | |
3013 | return; | |
3014 | } | |
3015 | if (!xi->rtsize) { | |
3016 | fprintf(stderr, _("Invalid zero length rt subvolume found\n")); | |
3017 | usage(); | |
3018 | } | |
3019 | ||
7a9af89a DC |
3020 | if (cli->rtsize) { |
3021 | if (cfg->rtblocks > DTOBT(xi->rtsize, cfg->blocklog)) { | |
3022 | fprintf(stderr, | |
3023 | _("size %s specified for rt subvolume is too large, maxi->um is %lld blocks\n"), | |
3024 | cli->rtsize, | |
3025 | (long long)DTOBT(xi->rtsize, cfg->blocklog)); | |
3026 | usage(); | |
3027 | } | |
3028 | if (xi->rtbsize > cfg->sectorsize) { | |
3029 | fprintf(stderr, _( | |
3030 | "Warning: the realtime subvolume sector size %u is less than the sector size\n\ | |
3031 | reported by the device (%u).\n"), | |
3032 | cfg->sectorsize, xi->rtbsize); | |
3033 | } | |
3034 | } else { | |
3035 | /* grab volume size */ | |
3036 | cfg->rtblocks = DTOBT(xi->rtsize, cfg->blocklog); | |
3037 | } | |
3038 | ||
3039 | cfg->rtextents = cfg->rtblocks / cfg->rtextblocks; | |
3040 | cfg->rtbmblocks = (xfs_extlen_t)howmany(cfg->rtextents, | |
3041 | NBBY * cfg->blocksize); | |
3042 | } | |
3043 | ||
1de01446 DC |
3044 | static void |
3045 | calculate_initial_ag_geometry( | |
3046 | struct mkfs_params *cfg, | |
3047 | struct cli_params *cli) | |
3048 | { | |
3049 | if (cli->agsize) { /* User-specified AG size */ | |
3050 | cfg->agsize = getnum(cli->agsize, &dopts, D_AGSIZE); | |
3051 | ||
3052 | /* | |
3053 | * Check specified agsize is a multiple of blocksize. | |
3054 | */ | |
3055 | if (cfg->agsize % cfg->blocksize) { | |
3056 | fprintf(stderr, | |
3057 | _("agsize (%s) not a multiple of fs blk size (%d)\n"), | |
3058 | cli->agsize, cfg->blocksize); | |
3059 | usage(); | |
3060 | } | |
3061 | cfg->agsize /= cfg->blocksize; | |
3062 | cfg->agcount = cfg->dblocks / cfg->agsize + | |
3063 | (cfg->dblocks % cfg->agsize != 0); | |
3064 | ||
3065 | } else if (cli->agcount) { /* User-specified AG count */ | |
3066 | cfg->agcount = cli->agcount; | |
3067 | cfg->agsize = cfg->dblocks / cfg->agcount + | |
3068 | (cfg->dblocks % cfg->agcount != 0); | |
3069 | } else { | |
3070 | calc_default_ag_geometry(cfg->blocklog, cfg->dblocks, | |
3071 | cfg->dsunit, &cfg->agsize, | |
3072 | &cfg->agcount); | |
3073 | } | |
3074 | } | |
3075 | ||
051b4e37 DC |
3076 | /* |
3077 | * Align the AG size to stripe geometry. If this fails and we are using | |
3078 | * discovered stripe geometry, tell the caller to clear the stripe geometry. | |
3079 | * Otherwise, set the aligned geometry (valid or invalid!) so that the | |
3080 | * validation call will fail and exit. | |
3081 | */ | |
3082 | static void | |
3083 | align_ag_geometry( | |
3084 | struct mkfs_params *cfg) | |
3085 | { | |
3086 | uint64_t tmp_agsize; | |
3087 | int dsunit = cfg->dsunit; | |
3088 | ||
3089 | if (!dsunit) | |
3090 | goto validate; | |
3091 | ||
3092 | /* | |
3093 | * agsize is not a multiple of dsunit | |
3094 | */ | |
3095 | if ((cfg->agsize % dsunit) != 0) { | |
3096 | /* | |
3097 | * Round up to stripe unit boundary. Also make sure | |
3098 | * that agsize is still larger than | |
3099 | * XFS_AG_MIN_BLOCKS(blocklog) | |
3100 | */ | |
3101 | tmp_agsize = ((cfg->agsize + dsunit - 1) / dsunit) * dsunit; | |
3102 | /* | |
3103 | * Round down to stripe unit boundary if rounding up | |
3104 | * created an AG size that is larger than the AG max. | |
3105 | */ | |
3106 | if (tmp_agsize > XFS_AG_MAX_BLOCKS(cfg->blocklog)) | |
3107 | tmp_agsize = (cfg->agsize / dsunit) * dsunit; | |
3108 | ||
3109 | if (tmp_agsize < XFS_AG_MIN_BLOCKS(cfg->blocklog) && | |
3110 | tmp_agsize > XFS_AG_MAX_BLOCKS(cfg->blocklog)) { | |
3111 | ||
3112 | /* | |
3113 | * If the AG size is invalid and we are using device | |
3114 | * probed stripe alignment, just clear the alignment | |
3115 | * and continue on. | |
3116 | */ | |
3117 | if (!cli_opt_set(&dopts, D_SUNIT) && | |
3118 | !cli_opt_set(&dopts, D_SU)) { | |
3119 | cfg->dsunit = 0; | |
3120 | cfg->dswidth = 0; | |
3121 | goto validate; | |
3122 | } | |
3123 | /* | |
3124 | * set the agsize to the invalid value so the following | |
3125 | * validation of the ag will fail and print a nice error | |
3126 | * and exit. | |
3127 | */ | |
3128 | cfg->agsize = tmp_agsize; | |
3129 | goto validate; | |
3130 | } | |
3131 | ||
3132 | /* update geometry to be stripe unit aligned */ | |
3133 | cfg->agsize = tmp_agsize; | |
3134 | if (!cli_opt_set(&dopts, D_AGCOUNT)) | |
3135 | cfg->agcount = cfg->dblocks / cfg->agsize + | |
3136 | (cfg->dblocks % cfg->agsize != 0); | |
3137 | if (cli_opt_set(&dopts, D_AGSIZE)) | |
3138 | fprintf(stderr, | |
3139 | _("agsize rounded to %lld, sunit = %d\n"), | |
3140 | (long long)cfg->agsize, dsunit); | |
3141 | } | |
3142 | ||
3143 | if ((cfg->agsize % cfg->dswidth) == 0 && | |
3144 | cfg->dswidth != cfg->dsunit && | |
3145 | cfg->agcount > 1) { | |
3146 | ||
3147 | if (cli_opt_set(&dopts, D_AGCOUNT) || | |
3148 | cli_opt_set(&dopts, D_AGSIZE)) { | |
ffb1fbc8 | 3149 | printf(_( |
051b4e37 DC |
3150 | "Warning: AG size is a multiple of stripe width. This can cause performance\n\ |
3151 | problems by aligning all AGs on the same disk. To avoid this, run mkfs with\n\ | |
3152 | an AG size that is one stripe unit smaller or larger, for example %llu.\n"), | |
3153 | (unsigned long long)cfg->agsize - dsunit); | |
ffb1fbc8 | 3154 | fflush(stdout); |
051b4e37 DC |
3155 | goto validate; |
3156 | } | |
3157 | ||
3158 | /* | |
3159 | * This is a non-optimal configuration because all AGs start on | |
3160 | * the same disk in the stripe. Changing the AG size by one | |
3161 | * sunit will guarantee that this does not happen. | |
3162 | */ | |
3163 | tmp_agsize = cfg->agsize - dsunit; | |
3164 | if (tmp_agsize < XFS_AG_MIN_BLOCKS(cfg->blocklog)) { | |
3165 | tmp_agsize = cfg->agsize + dsunit; | |
3166 | if (cfg->dblocks < cfg->agsize) { | |
3167 | /* oh well, nothing to do */ | |
3168 | tmp_agsize = cfg->agsize; | |
3169 | } | |
3170 | } | |
3171 | ||
3172 | cfg->agsize = tmp_agsize; | |
3173 | cfg->agcount = cfg->dblocks / cfg->agsize + | |
3174 | (cfg->dblocks % cfg->agsize != 0); | |
3175 | } | |
3176 | ||
3177 | validate: | |
3178 | /* | |
3179 | * If the last AG is too small, reduce the filesystem size | |
3180 | * and drop the blocks. | |
3181 | */ | |
3182 | if (cfg->dblocks % cfg->agsize != 0 && | |
3183 | (cfg->dblocks % cfg->agsize < XFS_AG_MIN_BLOCKS(cfg->blocklog))) { | |
3184 | ASSERT(!cli_opt_set(&dopts, D_AGCOUNT)); | |
3185 | cfg->dblocks = (xfs_rfsblock_t)((cfg->agcount - 1) * cfg->agsize); | |
3186 | cfg->agcount--; | |
3187 | ASSERT(cfg->agcount != 0); | |
3188 | } | |
3189 | ||
3190 | validate_ag_geometry(cfg->blocklog, cfg->dblocks, | |
3191 | cfg->agsize, cfg->agcount); | |
3192 | } | |
3193 | ||
d7240c96 DC |
3194 | static void |
3195 | calculate_imaxpct( | |
3196 | struct mkfs_params *cfg, | |
3197 | struct cli_params *cli) | |
3198 | { | |
3199 | cfg->imaxpct = cli->imaxpct; | |
3200 | if (cfg->imaxpct) | |
3201 | return; | |
3202 | ||
3203 | /* | |
3204 | * This returns the % of the disk space that is used for | |
3205 | * inodes, it changes relatively to the FS size: | |
3206 | * - over 50 TB, use 1%, | |
3207 | * - 1TB - 50 TB, use 5%, | |
3208 | * - under 1 TB, use XFS_DFL_IMAXIMUM_PCT (25%). | |
3209 | */ | |
3210 | ||
3211 | if (cfg->dblocks < TERABYTES(1, cfg->blocklog)) | |
3212 | cfg->imaxpct = XFS_DFL_IMAXIMUM_PCT; | |
3213 | else if (cfg->dblocks < TERABYTES(50, cfg->blocklog)) | |
3214 | cfg->imaxpct = 5; | |
3215 | else | |
3216 | cfg->imaxpct = 1; | |
3217 | } | |
3218 | ||
befcd768 DC |
3219 | /* |
3220 | * Set up the initial state of the superblock so we can start using the | |
3221 | * libxfs geometry macros. | |
3222 | */ | |
3223 | static void | |
3224 | sb_set_features( | |
3225 | struct mkfs_params *cfg, | |
3226 | struct xfs_sb *sbp) | |
3227 | { | |
3228 | struct sb_feat_args *fp = &cfg->sb_feat; | |
3229 | ||
3230 | sbp->sb_versionnum = XFS_DFL_SB_VERSION_BITS; | |
3231 | if (fp->crcs_enabled) | |
3232 | sbp->sb_versionnum |= XFS_SB_VERSION_5; | |
3233 | else | |
3234 | sbp->sb_versionnum |= XFS_SB_VERSION_4; | |
3235 | ||
3236 | if (fp->inode_align) { | |
3237 | int cluster_size = XFS_INODE_BIG_CLUSTER_SIZE; | |
3238 | ||
3239 | sbp->sb_versionnum |= XFS_SB_VERSION_ALIGNBIT; | |
3240 | if (cfg->sb_feat.crcs_enabled) | |
3241 | cluster_size *= cfg->inodesize / XFS_DINODE_MIN_SIZE; | |
3242 | sbp->sb_inoalignmt = cluster_size >> cfg->blocklog; | |
3243 | } else | |
3244 | sbp->sb_inoalignmt = 0; | |
3245 | ||
3246 | if (cfg->dsunit) | |
3247 | sbp->sb_versionnum |= XFS_SB_VERSION_DALIGNBIT; | |
3248 | if (fp->log_version == 2) | |
3249 | sbp->sb_versionnum |= XFS_SB_VERSION_LOGV2BIT; | |
3250 | if (fp->attr_version == 1) | |
3251 | sbp->sb_versionnum |= XFS_SB_VERSION_ATTRBIT; | |
3252 | if (fp->nci) | |
3253 | sbp->sb_versionnum |= XFS_SB_VERSION_BORGBIT; | |
3254 | ||
3255 | if (cfg->sectorsize > BBSIZE || cfg->lsectorsize > BBSIZE) { | |
3256 | sbp->sb_versionnum |= XFS_SB_VERSION_SECTORBIT; | |
3257 | sbp->sb_logsectlog = (uint8_t)cfg->lsectorlog; | |
3258 | sbp->sb_logsectsize = (uint16_t)cfg->lsectorsize; | |
3259 | } else { | |
3260 | sbp->sb_logsectlog = 0; | |
3261 | sbp->sb_logsectsize = 0; | |
3262 | } | |
3263 | ||
3264 | sbp->sb_features2 = 0; | |
3265 | if (fp->lazy_sb_counters) | |
3266 | sbp->sb_features2 |= XFS_SB_VERSION2_LAZYSBCOUNTBIT; | |
639d0b0b | 3267 | if (fp->projid32bit) |
befcd768 DC |
3268 | sbp->sb_features2 |= XFS_SB_VERSION2_PROJID32BIT; |
3269 | if (fp->parent_pointers) | |
3270 | sbp->sb_features2 |= XFS_SB_VERSION2_PARENTBIT; | |
3271 | if (fp->crcs_enabled) | |
3272 | sbp->sb_features2 |= XFS_SB_VERSION2_CRCBIT; | |
3273 | if (fp->attr_version == 2) | |
3274 | sbp->sb_features2 |= XFS_SB_VERSION2_ATTR2BIT; | |
3275 | ||
3276 | /* v5 superblocks have their own feature bit for dirftype */ | |
3277 | if (fp->dirftype && !fp->crcs_enabled) | |
3278 | sbp->sb_features2 |= XFS_SB_VERSION2_FTYPE; | |
3279 | ||
3280 | /* update whether extended features are in use */ | |
3281 | if (sbp->sb_features2 != 0) | |
3282 | sbp->sb_versionnum |= XFS_SB_VERSION_MOREBITSBIT; | |
3283 | ||
3284 | /* | |
3285 | * Due to a structure alignment issue, sb_features2 ended up in one | |
3286 | * of two locations, the second "incorrect" location represented by | |
3287 | * the sb_bad_features2 field. To avoid older kernels mounting | |
3288 | * filesystems they shouldn't, set both field to the same value. | |
3289 | */ | |
3290 | sbp->sb_bad_features2 = sbp->sb_features2; | |
3291 | ||
3292 | if (!fp->crcs_enabled) | |
3293 | return; | |
3294 | ||
3295 | /* default features for v5 filesystems */ | |
3296 | sbp->sb_features_compat = 0; | |
3297 | sbp->sb_features_ro_compat = 0; | |
3298 | sbp->sb_features_incompat = XFS_SB_FEAT_INCOMPAT_FTYPE; | |
3299 | sbp->sb_features_log_incompat = 0; | |
3300 | ||
3301 | if (fp->finobt) | |
3302 | sbp->sb_features_ro_compat = XFS_SB_FEAT_RO_COMPAT_FINOBT; | |
3303 | if (fp->rmapbt) | |
3304 | sbp->sb_features_ro_compat |= XFS_SB_FEAT_RO_COMPAT_RMAPBT; | |
3305 | if (fp->reflink) | |
3306 | sbp->sb_features_ro_compat |= XFS_SB_FEAT_RO_COMPAT_REFLINK; | |
9eb0d6eb DW |
3307 | if (fp->inobtcnt) |
3308 | sbp->sb_features_ro_compat |= XFS_SB_FEAT_RO_COMPAT_INOBTCNT; | |
e9601810 DW |
3309 | if (fp->bigtime) |
3310 | sbp->sb_features_incompat |= XFS_SB_FEAT_INCOMPAT_BIGTIME; | |
befcd768 DC |
3311 | |
3312 | /* | |
3313 | * Sparse inode chunk support has two main inode alignment requirements. | |
3314 | * First, sparse chunk alignment must match the cluster size. Second, | |
3315 | * full chunk alignment must match the inode chunk size. | |
3316 | * | |
3317 | * Copy the already calculated/scaled inoalignmt to spino_align and | |
3318 | * update the former to the full inode chunk size. | |
3319 | */ | |
3320 | if (fp->spinodes) { | |
3321 | sbp->sb_spino_align = sbp->sb_inoalignmt; | |
3322 | sbp->sb_inoalignmt = XFS_INODES_PER_CHUNK * | |
3323 | cfg->inodesize >> cfg->blocklog; | |
3324 | sbp->sb_features_incompat |= XFS_SB_FEAT_INCOMPAT_SPINODES; | |
3325 | } | |
3326 | ||
69e72722 CB |
3327 | if (fp->nrext64) |
3328 | sbp->sb_features_incompat |= XFS_SB_FEAT_INCOMPAT_NREXT64; | |
befcd768 DC |
3329 | } |
3330 | ||
e3bc8390 DC |
3331 | /* |
3332 | * Make sure that the log size is a multiple of the stripe unit | |
3333 | */ | |
3334 | static void | |
3335 | align_log_size( | |
3336 | struct mkfs_params *cfg, | |
8d1bff2b DW |
3337 | int sunit, |
3338 | int max_logblocks) | |
e3bc8390 | 3339 | { |
8d1bff2b | 3340 | uint64_t tmp_logblocks; |
e3bc8390 DC |
3341 | |
3342 | /* nothing to do if it's already aligned. */ | |
3343 | if ((cfg->logblocks % sunit) == 0) | |
3344 | return; | |
3345 | ||
3346 | if (cli_opt_set(&lopts, L_SIZE)) { | |
3347 | fprintf(stderr, | |
3348 | _("log size %lld is not a multiple of the log stripe unit %d\n"), | |
3349 | (long long) cfg->logblocks, sunit); | |
3350 | usage(); | |
3351 | } | |
3352 | ||
3353 | tmp_logblocks = ((cfg->logblocks + (sunit - 1)) / sunit) * sunit; | |
3354 | ||
3355 | /* If the log is too large, round down instead of round up */ | |
3356 | if ((tmp_logblocks > XFS_MAX_LOG_BLOCKS) || | |
8d1bff2b DW |
3357 | ((tmp_logblocks << cfg->blocklog) > XFS_MAX_LOG_BYTES) || |
3358 | tmp_logblocks > max_logblocks) { | |
e3bc8390 DC |
3359 | tmp_logblocks = (cfg->logblocks / sunit) * sunit; |
3360 | } | |
3361 | cfg->logblocks = tmp_logblocks; | |
3362 | } | |
3363 | ||
3364 | /* | |
3365 | * Make sure that the internal log is correctly aligned to the specified | |
3366 | * stripe unit. | |
3367 | */ | |
3368 | static void | |
3369 | align_internal_log( | |
3370 | struct mkfs_params *cfg, | |
3371 | struct xfs_mount *mp, | |
8d1bff2b DW |
3372 | int sunit, |
3373 | int max_logblocks) | |
e3bc8390 DC |
3374 | { |
3375 | /* round up log start if necessary */ | |
3376 | if ((cfg->logstart % sunit) != 0) | |
3377 | cfg->logstart = ((cfg->logstart + (sunit - 1)) / sunit) * sunit; | |
3378 | ||
8da52988 | 3379 | /* If our log start overlaps the next AG's metadata, fail. */ |
93a199f2 DW |
3380 | if (!libxfs_verify_fsbno(mp, cfg->logstart)) { |
3381 | fprintf(stderr, | |
8da52988 DW |
3382 | _("Due to stripe alignment, the internal log start (%lld) cannot be aligned\n" |
3383 | "within an allocation group.\n"), | |
3384 | (long long) cfg->logstart); | |
3385 | usage(); | |
3386 | } | |
3387 | ||
e3bc8390 | 3388 | /* round up/down the log size now */ |
8d1bff2b | 3389 | align_log_size(cfg, sunit, max_logblocks); |
e3bc8390 | 3390 | |
0da883dd DW |
3391 | /* |
3392 | * If the end of the log has been rounded past the end of the AG, | |
3393 | * reduce logblocks by a stripe unit to try to get it back under EOAG. | |
3394 | */ | |
3395 | if (!libxfs_verify_fsbext(mp, cfg->logstart, cfg->logblocks) && | |
3396 | cfg->logblocks > sunit) { | |
3397 | cfg->logblocks -= sunit; | |
3398 | } | |
3399 | ||
9c726ef0 | 3400 | /* check the aligned log still starts and ends in the same AG. */ |
93a199f2 | 3401 | if (!libxfs_verify_fsbext(mp, cfg->logstart, cfg->logblocks)) { |
e3bc8390 DC |
3402 | fprintf(stderr, |
3403 | _("Due to stripe alignment, the internal log size (%lld) is too large.\n" | |
3404 | "Must fit within an allocation group.\n"), | |
3405 | (long long) cfg->logblocks); | |
3406 | usage(); | |
3407 | } | |
3408 | } | |
3409 | ||
00ff2b10 | 3410 | static void |
e3bc8390 DC |
3411 | validate_log_size(uint64_t logblocks, int blocklog, int min_logblocks) |
3412 | { | |
3413 | if (logblocks < min_logblocks) { | |
3414 | fprintf(stderr, | |
3415 | _("log size %lld blocks too small, minimum size is %d blocks\n"), | |
3416 | (long long)logblocks, min_logblocks); | |
3417 | usage(); | |
3418 | } | |
3419 | if (logblocks > XFS_MAX_LOG_BLOCKS) { | |
3420 | fprintf(stderr, | |
3421 | _("log size %lld blocks too large, maximum size is %lld blocks\n"), | |
3422 | (long long)logblocks, XFS_MAX_LOG_BLOCKS); | |
3423 | usage(); | |
3424 | } | |
3425 | if ((logblocks << blocklog) > XFS_MAX_LOG_BYTES) { | |
3426 | fprintf(stderr, | |
3427 | _("log size %lld bytes too large, maximum size is %lld bytes\n"), | |
3428 | (long long)(logblocks << blocklog), XFS_MAX_LOG_BYTES); | |
3429 | usage(); | |
3430 | } | |
3431 | } | |
3432 | ||
1b580a77 DW |
3433 | static void |
3434 | adjust_ag0_internal_logblocks( | |
3435 | struct mkfs_params *cfg, | |
3436 | struct xfs_mount *mp, | |
3437 | int min_logblocks, | |
3438 | int *max_logblocks) | |
3439 | { | |
3440 | int backoff = 0; | |
3441 | int ichunk_blocks; | |
3442 | ||
3443 | /* | |
3444 | * mkfs will trip over the write verifiers if the log is allocated in | |
3445 | * AG 0 and consumes enough space that we cannot allocate a non-sparse | |
3446 | * inode chunk for the root directory. The inode allocator requires | |
3447 | * that the AG have enough free space for the chunk itself plus enough | |
3448 | * to fix up the freelist with aligned blocks if we need to fill the | |
3449 | * allocation from the AGFL. | |
3450 | */ | |
3451 | ichunk_blocks = XFS_INODES_PER_CHUNK * cfg->inodesize >> cfg->blocklog; | |
3452 | backoff = ichunk_blocks * 4; | |
3453 | ||
3454 | /* | |
3455 | * We try to align inode allocations to the data device stripe unit, | |
3456 | * so ensure there's enough space to perform an aligned allocation. | |
3457 | * The inode geometry structure isn't set up yet, so compute this by | |
3458 | * hand. | |
3459 | */ | |
3460 | backoff = max(backoff, cfg->dsunit * 2); | |
3461 | ||
3462 | *max_logblocks -= backoff; | |
3463 | ||
3464 | /* If the specified log size is too big, complain. */ | |
3465 | if (cli_opt_set(&lopts, L_SIZE) && cfg->logblocks > *max_logblocks) { | |
3466 | fprintf(stderr, | |
3467 | _("internal log size %lld too large, must be less than %d\n"), | |
3468 | (long long)cfg->logblocks, | |
3469 | *max_logblocks); | |
3470 | usage(); | |
3471 | } | |
3472 | ||
3473 | cfg->logblocks = min(cfg->logblocks, *max_logblocks); | |
3474 | } | |
3475 | ||
e3bc8390 DC |
3476 | static void |
3477 | calculate_log_size( | |
3478 | struct mkfs_params *cfg, | |
3479 | struct cli_params *cli, | |
3480 | struct xfs_mount *mp) | |
3481 | { | |
e3bc8390 | 3482 | struct xfs_sb *sbp = &mp->m_sb; |
cdfa467e | 3483 | int min_logblocks; /* absolute minimum */ |
aba6743c | 3484 | int max_logblocks; /* absolute max for this AG */ |
a6fb6abe | 3485 | struct xfs_mount mount; |
e3bc8390 | 3486 | |
a6fb6abe DC |
3487 | /* we need a temporary mount to calculate the minimum log size. */ |
3488 | memset(&mount, 0, sizeof(mount)); | |
3489 | mount.m_sb = *sbp; | |
3490 | libxfs_mount(&mount, &mp->m_sb, 0, 0, 0, 0); | |
3491 | min_logblocks = libxfs_log_calc_minimum_size(&mount); | |
3492 | libxfs_umount(&mount); | |
e3bc8390 DC |
3493 | |
3494 | ASSERT(min_logblocks); | |
68d16907 | 3495 | min_logblocks = max(XFS_MIN_LOG_BLOCKS, min_logblocks); |
e3bc8390 DC |
3496 | |
3497 | /* if we have lots of blocks, check against XFS_MIN_LOG_BYTES, too */ | |
3498 | if (!cli->logsize && | |
3499 | cfg->dblocks >= (1024*1024*1024) >> cfg->blocklog) | |
68d16907 | 3500 | min_logblocks = max(min_logblocks, |
e3bc8390 DC |
3501 | XFS_MIN_LOG_BYTES >> cfg->blocklog); |
3502 | ||
3503 | /* | |
3504 | * external logs will have a device and size by now, so all we have | |
3505 | * to do is validate it against minimum size and align it. | |
3506 | */ | |
3507 | if (!cfg->loginternal) { | |
3508 | if (min_logblocks > cfg->logblocks) { | |
3509 | fprintf(stderr, | |
4f6eceed | 3510 | _("external log device size %lld blocks too small, must be at least %lld blocks\n"), |
e3bc8390 DC |
3511 | (long long)cfg->logblocks, |
3512 | (long long)min_logblocks); | |
3513 | usage(); | |
3514 | } | |
3515 | cfg->logstart = 0; | |
3516 | cfg->logagno = 0; | |
3517 | if (cfg->lsunit) | |
8d1bff2b | 3518 | align_log_size(cfg, cfg->lsunit, XFS_MAX_LOG_BLOCKS); |
e3bc8390 DC |
3519 | |
3520 | validate_log_size(cfg->logblocks, cfg->blocklog, min_logblocks); | |
3521 | return; | |
3522 | } | |
3523 | ||
aba6743c DW |
3524 | /* |
3525 | * Make sure the log fits wholly within an AG | |
3526 | * | |
3527 | * XXX: If agf->freeblks ends up as 0 because the log uses all | |
3528 | * the free space, it causes the kernel all sorts of problems | |
3529 | * with per-ag reservations. Right now just back it off one | |
3530 | * block, but there's a whole can of worms here that needs to be | |
3531 | * opened to decide what is the valid maximum size of a log in | |
3532 | * an AG. | |
3533 | */ | |
3534 | max_logblocks = libxfs_alloc_ag_max_usable(mp) - 1; | |
db5b8665 DW |
3535 | if (max_logblocks < min_logblocks) { |
3536 | fprintf(stderr, | |
3537 | _("max log size %d smaller than min log size %d, filesystem is too small\n"), | |
3538 | max_logblocks, | |
3539 | min_logblocks); | |
3540 | usage(); | |
3541 | } | |
aba6743c | 3542 | |
e3bc8390 DC |
3543 | /* internal log - if no size specified, calculate automatically */ |
3544 | if (!cfg->logblocks) { | |
cdfa467e ES |
3545 | /* Use a 2048:1 fs:log ratio for most filesystems */ |
3546 | cfg->logblocks = (cfg->dblocks << cfg->blocklog) / 2048; | |
3547 | cfg->logblocks = cfg->logblocks >> cfg->blocklog; | |
e3bc8390 | 3548 | |
cdfa467e ES |
3549 | /* But don't go below a reasonable size */ |
3550 | cfg->logblocks = max(cfg->logblocks, | |
3551 | XFS_MIN_REALISTIC_LOG_BLOCKS(cfg->blocklog)); | |
3552 | ||
3553 | /* And for a tiny filesystem, use the absolute minimum size */ | |
3554 | if (cfg->dblocks < MEGABYTES(300, cfg->blocklog)) | |
3555 | cfg->logblocks = min_logblocks; | |
e3bc8390 | 3556 | |
aba6743c | 3557 | /* Ensure the chosen size fits within log size requirements */ |
68d16907 | 3558 | cfg->logblocks = max(min_logblocks, cfg->logblocks); |
aba6743c | 3559 | cfg->logblocks = min(cfg->logblocks, max_logblocks); |
e3bc8390 DC |
3560 | |
3561 | /* and now clamp the size to the maximum supported size */ | |
68d16907 | 3562 | cfg->logblocks = min(cfg->logblocks, XFS_MAX_LOG_BLOCKS); |
e3bc8390 DC |
3563 | if ((cfg->logblocks << cfg->blocklog) > XFS_MAX_LOG_BYTES) |
3564 | cfg->logblocks = XFS_MAX_LOG_BYTES >> cfg->blocklog; | |
3565 | ||
3566 | validate_log_size(cfg->logblocks, cfg->blocklog, min_logblocks); | |
aba6743c DW |
3567 | } else if (cfg->logblocks > max_logblocks) { |
3568 | /* check specified log size */ | |
3569 | fprintf(stderr, | |
3570 | _("internal log size %lld too large, must be less than %d\n"), | |
3571 | (long long)cfg->logblocks, | |
3572 | max_logblocks); | |
3573 | usage(); | |
e3bc8390 DC |
3574 | } |
3575 | ||
3576 | if (cfg->logblocks > sbp->sb_agblocks - libxfs_prealloc_blocks(mp)) { | |
3577 | fprintf(stderr, | |
3578 | _("internal log size %lld too large, must fit in allocation group\n"), | |
3579 | (long long)cfg->logblocks); | |
3580 | usage(); | |
3581 | } | |
3582 | ||
3583 | if (cli_opt_set(&lopts, L_AGNUM)) { | |
3584 | if (cli->logagno >= sbp->sb_agcount) { | |
3585 | fprintf(stderr, | |
3586 | _("log ag number %lld too large, must be less than %lld\n"), | |
3587 | (long long)cli->logagno, | |
3588 | (long long)sbp->sb_agcount); | |
3589 | usage(); | |
3590 | } | |
3591 | cfg->logagno = cli->logagno; | |
3592 | } else | |
3593 | cfg->logagno = (xfs_agnumber_t)(sbp->sb_agcount / 2); | |
3594 | ||
1b580a77 DW |
3595 | if (cfg->logagno == 0) |
3596 | adjust_ag0_internal_logblocks(cfg, mp, min_logblocks, | |
3597 | &max_logblocks); | |
3598 | ||
e3bc8390 DC |
3599 | cfg->logstart = XFS_AGB_TO_FSB(mp, cfg->logagno, |
3600 | libxfs_prealloc_blocks(mp)); | |
3601 | ||
3602 | /* | |
3603 | * Align the logstart at stripe unit boundary. | |
3604 | */ | |
3605 | if (cfg->lsunit) { | |
8d1bff2b | 3606 | align_internal_log(cfg, mp, cfg->lsunit, max_logblocks); |
e3bc8390 | 3607 | } else if (cfg->dsunit) { |
8d1bff2b | 3608 | align_internal_log(cfg, mp, cfg->dsunit, max_logblocks); |
e3bc8390 DC |
3609 | } |
3610 | validate_log_size(cfg->logblocks, cfg->blocklog, min_logblocks); | |
3611 | } | |
3612 | ||
befcd768 | 3613 | /* |
a6fb6abe | 3614 | * Set up superblock with the minimum parameters required for |
befcd768 | 3615 | * the libxfs macros needed by the log sizing code to run successfully. |
a6fb6abe DC |
3616 | * This includes a minimum log size calculation, so we need everything |
3617 | * that goes into that calculation to be setup here including feature | |
3618 | * flags. | |
befcd768 DC |
3619 | */ |
3620 | static void | |
a6fb6abe | 3621 | start_superblock_setup( |
befcd768 DC |
3622 | struct mkfs_params *cfg, |
3623 | struct xfs_mount *mp, | |
3624 | struct xfs_sb *sbp) | |
3625 | { | |
a6fb6abe DC |
3626 | sbp->sb_magicnum = XFS_SB_MAGIC; |
3627 | sbp->sb_sectsize = (uint16_t)cfg->sectorsize; | |
befcd768 | 3628 | sbp->sb_sectlog = (uint8_t)cfg->sectorlog; |
a6fb6abe DC |
3629 | sbp->sb_blocksize = cfg->blocksize; |
3630 | sbp->sb_blocklog = (uint8_t)cfg->blocklog; | |
3631 | ||
befcd768 | 3632 | sbp->sb_agblocks = (xfs_agblock_t)cfg->agsize; |
a6fb6abe | 3633 | sbp->sb_agblklog = (uint8_t)log2_roundup(cfg->agsize); |
befcd768 | 3634 | sbp->sb_agcount = (xfs_agnumber_t)cfg->agcount; |
93a199f2 | 3635 | sbp->sb_dblocks = (xfs_rfsblock_t)cfg->dblocks; |
a6fb6abe DC |
3636 | |
3637 | sbp->sb_inodesize = (uint16_t)cfg->inodesize; | |
3638 | sbp->sb_inodelog = (uint8_t)cfg->inodelog; | |
3639 | sbp->sb_inopblock = (uint16_t)(cfg->blocksize / cfg->inodesize); | |
3640 | sbp->sb_inopblog = (uint8_t)(cfg->blocklog - cfg->inodelog); | |
3641 | ||
3642 | sbp->sb_dirblklog = cfg->dirblocklog - cfg->blocklog; | |
3643 | ||
3644 | sb_set_features(cfg, sbp); | |
befcd768 DC |
3645 | |
3646 | /* | |
a6fb6abe DC |
3647 | * log stripe unit is stored in bytes on disk and cannot be zero |
3648 | * for v2 logs. | |
befcd768 | 3649 | */ |
a6fb6abe DC |
3650 | if (cfg->sb_feat.log_version == 2) { |
3651 | if (cfg->lsunit) | |
3652 | sbp->sb_logsunit = XFS_FSB_TO_B(mp, cfg->lsunit); | |
3653 | else | |
3654 | sbp->sb_logsunit = 1; | |
3655 | } else | |
3656 | sbp->sb_logsunit = 0; | |
3657 | ||
31409f48 DW |
3658 | /* log reservation calculations depend on rt geometry */ |
3659 | sbp->sb_rblocks = cfg->rtblocks; | |
3660 | sbp->sb_rextsize = cfg->rtextblocks; | |
3bc1fdd4 | 3661 | mp->m_features |= libxfs_sb_version_to_features(sbp); |
a6fb6abe DC |
3662 | } |
3663 | ||
3664 | static void | |
3665 | initialise_mount( | |
a6fb6abe DC |
3666 | struct xfs_mount *mp, |
3667 | struct xfs_sb *sbp) | |
3668 | { | |
3669 | /* Minimum needed for libxfs_prealloc_blocks() */ | |
3670 | mp->m_blkbb_log = sbp->sb_blocklog - BBSHIFT; | |
3671 | mp->m_sectbb_log = sbp->sb_sectlog - BBSHIFT; | |
befcd768 DC |
3672 | } |
3673 | ||
afda75a5 DC |
3674 | /* |
3675 | * Format everything from the generated config into the superblock that | |
3676 | * will be used to initialise the on-disk superblock. This is the in-memory | |
3677 | * copy, so no need to care about endian swapping here. | |
3678 | */ | |
3679 | static void | |
a6fb6abe | 3680 | finish_superblock_setup( |
afda75a5 DC |
3681 | struct mkfs_params *cfg, |
3682 | struct xfs_mount *mp, | |
3683 | struct xfs_sb *sbp) | |
3684 | { | |
7f0d0b55 DW |
3685 | if (cfg->label) { |
3686 | size_t label_len; | |
3687 | ||
3688 | /* | |
3689 | * Labels are null terminated unless the string fits exactly | |
3690 | * in the label field, so assume sb_fname is zeroed and then | |
3691 | * do a memcpy because the destination isn't a normal C string. | |
3692 | */ | |
3693 | label_len = min(sizeof(sbp->sb_fname), strlen(cfg->label)); | |
3694 | memcpy(sbp->sb_fname, cfg->label, label_len); | |
3695 | } | |
afda75a5 | 3696 | |
afda75a5 | 3697 | sbp->sb_dblocks = cfg->dblocks; |
afda75a5 DC |
3698 | sbp->sb_rextents = cfg->rtextents; |
3699 | platform_uuid_copy(&sbp->sb_uuid, &cfg->uuid); | |
3700 | /* Only in memory; libxfs expects this as if read from disk */ | |
3701 | platform_uuid_copy(&sbp->sb_meta_uuid, &cfg->uuid); | |
3702 | sbp->sb_logstart = cfg->logstart; | |
3703 | sbp->sb_rootino = sbp->sb_rbmino = sbp->sb_rsumino = NULLFSINO; | |
afda75a5 DC |
3704 | sbp->sb_agcount = (xfs_agnumber_t)cfg->agcount; |
3705 | sbp->sb_rbmblocks = cfg->rtbmblocks; | |
3706 | sbp->sb_logblocks = (xfs_extlen_t)cfg->logblocks; | |
afda75a5 DC |
3707 | sbp->sb_rextslog = (uint8_t)(cfg->rtextents ? |
3708 | libxfs_highbit32((unsigned int)cfg->rtextents) : 0); | |
3709 | sbp->sb_inprogress = 1; /* mkfs is in progress */ | |
3710 | sbp->sb_imax_pct = cfg->imaxpct; | |
3711 | sbp->sb_icount = 0; | |
3712 | sbp->sb_ifree = 0; | |
3713 | sbp->sb_fdblocks = cfg->dblocks - | |
3714 | cfg->agcount * libxfs_prealloc_blocks(mp) - | |
3715 | (cfg->loginternal ? cfg->logblocks : 0); | |
3716 | sbp->sb_frextents = 0; /* will do a free later */ | |
3717 | sbp->sb_uquotino = sbp->sb_gquotino = sbp->sb_pquotino = 0; | |
3718 | sbp->sb_qflags = 0; | |
3719 | sbp->sb_unit = cfg->dsunit; | |
3720 | sbp->sb_width = cfg->dswidth; | |
3bc1fdd4 | 3721 | mp->m_features |= libxfs_sb_version_to_features(sbp); |
afda75a5 | 3722 | |
afda75a5 DC |
3723 | } |
3724 | ||
09468119 DW |
3725 | /* Prepare an uncached buffer, ready to write something out. */ |
3726 | static inline struct xfs_buf * | |
3727 | alloc_write_buf( | |
3728 | struct xfs_buftarg *btp, | |
3729 | xfs_daddr_t daddr, | |
3730 | int bblen) | |
3731 | { | |
3732 | struct xfs_buf *bp; | |
d918bc57 | 3733 | int error; |
09468119 | 3734 | |
d918bc57 DW |
3735 | error = -libxfs_buf_get_uncached(btp, bblen, 0, &bp); |
3736 | if (error) { | |
3737 | fprintf(stderr, _("Could not get memory for buffer, err=%d\n"), | |
3738 | error); | |
3739 | exit(1); | |
3740 | } | |
a25314af DW |
3741 | |
3742 | xfs_buf_set_daddr(bp, daddr); | |
09468119 DW |
3743 | return bp; |
3744 | } | |
3745 | ||
e99bf83d DC |
3746 | /* |
3747 | * Sanitise the data and log devices and prepare them so libxfs can mount the | |
3748 | * device successfully. Also check we can access the rt device if configured. | |
3749 | */ | |
3750 | static void | |
3751 | prepare_devices( | |
3752 | struct mkfs_params *cfg, | |
3753 | struct libxfs_xinit *xi, | |
3754 | struct xfs_mount *mp, | |
3755 | struct xfs_sb *sbp, | |
3756 | bool clear_stale) | |
3757 | { | |
3758 | struct xfs_buf *buf; | |
3759 | int whack_blks = BTOBB(WHACK_SIZE); | |
3760 | int lsunit; | |
3761 | ||
3762 | /* | |
3763 | * If there's an old XFS filesystem on the device with enough intact | |
3764 | * information that we can parse the superblock, there's enough | |
3765 | * information on disk to confuse a future xfs_repair call. To avoid | |
3766 | * this, whack all the old secondary superblocks that we can find. | |
3767 | */ | |
3768 | if (clear_stale) | |
3769 | zero_old_xfs_structures(xi, sbp); | |
3770 | ||
3771 | /* | |
3772 | * If the data device is a file, grow out the file to its final size if | |
3773 | * needed so that the reads for the end of the device in the mount code | |
3774 | * will succeed. | |
3775 | */ | |
3776 | if (xi->disfile && | |
3777 | xi->dsize * xi->dbsize < cfg->dblocks * cfg->blocksize) { | |
3778 | if (ftruncate(xi->dfd, cfg->dblocks * cfg->blocksize) < 0) { | |
3779 | fprintf(stderr, | |
3780 | _("%s: Growing the data section failed\n"), | |
3781 | progname); | |
3782 | exit(1); | |
3783 | } | |
3784 | ||
3785 | /* update size to be able to whack blocks correctly */ | |
3786 | xi->dsize = BTOBB(cfg->dblocks * cfg->blocksize); | |
3787 | } | |
3788 | ||
3789 | /* | |
3790 | * Zero out the end to obliterate any old MD RAID (or other) metadata at | |
3791 | * the end of the device. (MD sb is ~64k from the end, take out a wider | |
3792 | * swath to be sure) | |
3793 | */ | |
09468119 DW |
3794 | buf = alloc_write_buf(mp->m_ddev_targp, (xi->dsize - whack_blks), |
3795 | whack_blks); | |
04338619 | 3796 | memset(buf->b_addr, 0, WHACK_SIZE); |
f524ae04 | 3797 | libxfs_buf_mark_dirty(buf); |
18b4f688 | 3798 | libxfs_buf_relse(buf); |
e99bf83d DC |
3799 | |
3800 | /* | |
3801 | * Now zero out the beginning of the device, to obliterate any old | |
3802 | * filesystem signatures out there. This should take care of | |
3803 | * swap (somewhere around the page size), jfs (32k), | |
3804 | * ext[2,3] and reiserfs (64k) - and hopefully all else. | |
3805 | */ | |
09468119 | 3806 | buf = alloc_write_buf(mp->m_ddev_targp, 0, whack_blks); |
04338619 | 3807 | memset(buf->b_addr, 0, WHACK_SIZE); |
f524ae04 | 3808 | libxfs_buf_mark_dirty(buf); |
18b4f688 | 3809 | libxfs_buf_relse(buf); |
e99bf83d DC |
3810 | |
3811 | /* OK, now write the superblock... */ | |
09468119 | 3812 | buf = alloc_write_buf(mp->m_ddev_targp, XFS_SB_DADDR, |
8b4de37c | 3813 | XFS_FSS_TO_BB(mp, 1)); |
e99bf83d | 3814 | buf->b_ops = &xfs_sb_buf_ops; |
04338619 CM |
3815 | memset(buf->b_addr, 0, cfg->sectorsize); |
3816 | libxfs_sb_to_disk(buf->b_addr, sbp); | |
f524ae04 | 3817 | libxfs_buf_mark_dirty(buf); |
18b4f688 | 3818 | libxfs_buf_relse(buf); |
e99bf83d DC |
3819 | |
3820 | /* ...and zero the log.... */ | |
3821 | lsunit = sbp->sb_logsunit; | |
3822 | if (lsunit == 1) | |
3823 | lsunit = sbp->sb_logsectsize; | |
3824 | ||
3825 | libxfs_log_clear(mp->m_logdev_targp, NULL, | |
3826 | XFS_FSB_TO_DADDR(mp, cfg->logstart), | |
3827 | (xfs_extlen_t)XFS_FSB_TO_BB(mp, cfg->logblocks), | |
3828 | &sbp->sb_uuid, cfg->sb_feat.log_version, | |
3829 | lsunit, XLOG_FMT, XLOG_INIT_CYCLE, false); | |
3830 | ||
3831 | /* finally, check we can write the last block in the realtime area */ | |
ab434d12 | 3832 | if (mp->m_rtdev_targp->bt_bdev && cfg->rtblocks > 0) { |
09468119 DW |
3833 | buf = alloc_write_buf(mp->m_rtdev_targp, |
3834 | XFS_FSB_TO_BB(mp, cfg->rtblocks - 1LL), | |
3835 | BTOBB(cfg->blocksize)); | |
04338619 | 3836 | memset(buf->b_addr, 0, cfg->blocksize); |
f524ae04 | 3837 | libxfs_buf_mark_dirty(buf); |
18b4f688 | 3838 | libxfs_buf_relse(buf); |
e99bf83d DC |
3839 | } |
3840 | ||
3841 | } | |
3842 | ||
0ff1b0ed DC |
3843 | static void |
3844 | initialise_ag_headers( | |
3845 | struct mkfs_params *cfg, | |
3846 | struct xfs_mount *mp, | |
0ff1b0ed | 3847 | xfs_agnumber_t agno, |
7b754805 DW |
3848 | int *worst_freelist, |
3849 | struct list_head *buffer_list) | |
0ff1b0ed | 3850 | { |
7b754805 DW |
3851 | struct aghdr_init_data id = { |
3852 | .agno = agno, | |
3853 | .agsize = cfg->agsize, | |
3854 | }; | |
0ff1b0ed | 3855 | struct xfs_perag *pag = libxfs_perag_get(mp, agno); |
7b754805 | 3856 | int error; |
0ff1b0ed | 3857 | |
0ff1b0ed | 3858 | if (agno == cfg->agcount - 1) |
7b754805 | 3859 | id.agsize = cfg->dblocks - (xfs_rfsblock_t)(agno * cfg->agsize); |
0ff1b0ed | 3860 | |
7b754805 DW |
3861 | INIT_LIST_HEAD(&id.buffer_list); |
3862 | error = -libxfs_ag_init_headers(mp, &id); | |
3863 | if (error) { | |
3864 | fprintf(stderr, _("AG header init failed, error %d\n"), error); | |
3865 | exit(1); | |
0ff1b0ed DC |
3866 | } |
3867 | ||
7b754805 | 3868 | list_splice_tail_init(&id.buffer_list, buffer_list); |
0ff1b0ed | 3869 | |
0ff1b0ed DC |
3870 | if (libxfs_alloc_min_freelist(mp, pag) > *worst_freelist) |
3871 | *worst_freelist = libxfs_alloc_min_freelist(mp, pag); | |
0ff1b0ed DC |
3872 | libxfs_perag_put(pag); |
3873 | } | |
3874 | ||
3875 | static void | |
3876 | initialise_ag_freespace( | |
3877 | struct xfs_mount *mp, | |
3878 | xfs_agnumber_t agno, | |
3879 | int worst_freelist) | |
3880 | { | |
3881 | struct xfs_alloc_arg args; | |
3882 | struct xfs_trans *tp; | |
0ff1b0ed DC |
3883 | int c; |
3884 | ||
225e4bb2 | 3885 | c = -libxfs_trans_alloc_rollable(mp, worst_freelist, &tp); |
0ff1b0ed DC |
3886 | if (c) |
3887 | res_failed(c); | |
3888 | ||
3889 | memset(&args, 0, sizeof(args)); | |
3890 | args.tp = tp; | |
3891 | args.mp = mp; | |
3892 | args.agno = agno; | |
3893 | args.alignment = 1; | |
3894 | args.pag = libxfs_perag_get(mp, agno); | |
3895 | ||
3896 | libxfs_alloc_fix_freelist(&args, 0); | |
3897 | libxfs_perag_put(args.pag); | |
f2279d8d | 3898 | c = -libxfs_trans_commit(tp); |
5770b2f0 DW |
3899 | if (c) { |
3900 | errno = c; | |
3901 | perror(_("initializing AG free space list")); | |
3902 | exit(1); | |
3903 | } | |
0ff1b0ed DC |
3904 | } |
3905 | ||
e2847e5c DC |
3906 | /* |
3907 | * rewrite several secondary superblocks with the root inode number filled out. | |
3908 | * This can help repair recovery from a trashed primary superblock without | |
3909 | * losing the root inode. | |
3910 | */ | |
3911 | static void | |
3912 | rewrite_secondary_superblocks( | |
3913 | struct xfs_mount *mp) | |
3914 | { | |
3915 | struct xfs_buf *buf; | |
d6522f1d | 3916 | struct xfs_dsb *dsb; |
31079e67 | 3917 | int error; |
e2847e5c DC |
3918 | |
3919 | /* rewrite the last superblock */ | |
31079e67 | 3920 | error = -libxfs_buf_read(mp->m_dev, |
e2847e5c DC |
3921 | XFS_AGB_TO_DADDR(mp, mp->m_sb.sb_agcount - 1, |
3922 | XFS_SB_DADDR), | |
31079e67 DW |
3923 | XFS_FSS_TO_BB(mp, 1), 0, &buf, &xfs_sb_buf_ops); |
3924 | if (error) { | |
d855bce8 DW |
3925 | fprintf(stderr, _("%s: could not re-read AG %u superblock\n"), |
3926 | progname, mp->m_sb.sb_agcount - 1); | |
3927 | exit(1); | |
3928 | } | |
d6522f1d CH |
3929 | dsb = buf->b_addr; |
3930 | dsb->sb_rootino = cpu_to_be64(mp->m_sb.sb_rootino); | |
f524ae04 | 3931 | libxfs_buf_mark_dirty(buf); |
18b4f688 | 3932 | libxfs_buf_relse(buf); |
e2847e5c DC |
3933 | |
3934 | /* and one in the middle for luck if there's enough AGs for that */ | |
3935 | if (mp->m_sb.sb_agcount <= 2) | |
3936 | return; | |
3937 | ||
31079e67 | 3938 | error = -libxfs_buf_read(mp->m_dev, |
e2847e5c DC |
3939 | XFS_AGB_TO_DADDR(mp, (mp->m_sb.sb_agcount - 1) / 2, |
3940 | XFS_SB_DADDR), | |
31079e67 DW |
3941 | XFS_FSS_TO_BB(mp, 1), 0, &buf, &xfs_sb_buf_ops); |
3942 | if (error) { | |
d855bce8 DW |
3943 | fprintf(stderr, _("%s: could not re-read AG %u superblock\n"), |
3944 | progname, (mp->m_sb.sb_agcount - 1) / 2); | |
3945 | exit(1); | |
3946 | } | |
d6522f1d CH |
3947 | dsb = buf->b_addr; |
3948 | dsb->sb_rootino = cpu_to_be64(mp->m_sb.sb_rootino); | |
f524ae04 | 3949 | libxfs_buf_mark_dirty(buf); |
18b4f688 | 3950 | libxfs_buf_relse(buf); |
e2847e5c DC |
3951 | } |
3952 | ||
659a4358 DW |
3953 | static void |
3954 | check_root_ino( | |
3955 | struct xfs_mount *mp) | |
3956 | { | |
3957 | xfs_ino_t ino; | |
3958 | ||
3959 | if (XFS_INO_TO_AGNO(mp, mp->m_sb.sb_rootino) != 0) { | |
3960 | fprintf(stderr, | |
3961 | _("%s: root inode created in AG %u, not AG 0\n"), | |
3962 | progname, XFS_INO_TO_AGNO(mp, mp->m_sb.sb_rootino)); | |
3963 | exit(1); | |
3964 | } | |
3965 | ||
3966 | /* | |
3967 | * The superblock points to the root directory inode, but xfs_repair | |
3968 | * expects to find the root inode in a very specific location computed | |
3969 | * from the filesystem geometry for an extra level of verification. | |
3970 | * | |
3971 | * Fail the format immediately if those assumptions ever break, because | |
3972 | * repair will toss the root directory. | |
3973 | */ | |
3974 | ino = libxfs_ialloc_calc_rootino(mp, mp->m_sb.sb_unit); | |
3975 | if (mp->m_sb.sb_rootino != ino) { | |
3976 | fprintf(stderr, | |
3977 | _("%s: root inode (%llu) not allocated in expected location (%llu)\n"), | |
3978 | progname, | |
3979 | (unsigned long long)mp->m_sb.sb_rootino, | |
3980 | (unsigned long long)ino); | |
3981 | exit(1); | |
3982 | } | |
3983 | } | |
3984 | ||
33c62516 DC |
3985 | /* |
3986 | * INI file format option parser. | |
3987 | * | |
3988 | * This is called by the file parser library for every valid option it finds in | |
3989 | * the config file. The option is already broken down into a | |
3990 | * {section,name,value} tuple, so all we need to do is feed it to the correct | |
3991 | * suboption parser function and translate the return value. | |
3992 | * | |
3993 | * Returns 0 on failure, 1 for success. | |
3994 | */ | |
3995 | static int | |
3996 | cfgfile_parse_ini( | |
3997 | void *user, | |
3998 | const char *section, | |
3999 | const char *name, | |
4000 | const char *value) | |
4001 | { | |
4002 | struct cli_params *cli = user; | |
4003 | ||
ab2eef12 DC |
4004 | if (!parse_cfgopt(section, name, value, cli)) |
4005 | return 0; | |
33c62516 DC |
4006 | return 1; |
4007 | } | |
4008 | ||
b6fef47a | 4009 | static void |
33c62516 DC |
4010 | cfgfile_parse( |
4011 | struct cli_params *cli) | |
4012 | { | |
4013 | int error; | |
4014 | ||
4015 | if (!cli->cfgfile) | |
4016 | return; | |
4017 | ||
4018 | error = ini_parse(cli->cfgfile, cfgfile_parse_ini, cli); | |
4019 | if (error) { | |
4020 | if (error > 0) { | |
4021 | fprintf(stderr, | |
4022 | _("%s: Unrecognised input on line %d. Aborting.\n"), | |
4023 | cli->cfgfile, error); | |
4024 | } else if (error == -1) { | |
4025 | fprintf(stderr, | |
4026 | _("Unable to open config file %s. Aborting.\n"), | |
4027 | cli->cfgfile); | |
4028 | } else if (error == -2) { | |
4029 | fprintf(stderr, | |
4030 | _("Memory allocation failure parsing %s. Aborting.\n"), | |
4031 | cli->cfgfile); | |
4032 | } else { | |
4033 | fprintf(stderr, | |
4034 | _("Unknown error %d opening config file %s. Aborting.\n"), | |
4035 | error, cli->cfgfile); | |
4036 | } | |
4037 | exit(1); | |
4038 | } | |
4039 | printf(_("Parameters parsed from config file %s successfully\n"), | |
4040 | cli->cfgfile); | |
4041 | } | |
4042 | ||
2bd0ea18 | 4043 | int |
9440d84d NS |
4044 | main( |
4045 | int argc, | |
4046 | char **argv) | |
2bd0ea18 | 4047 | { |
2bd0ea18 | 4048 | xfs_agnumber_t agno; |
167137fe | 4049 | struct xfs_buf *buf; |
2bd0ea18 | 4050 | int c; |
fdea8fbc | 4051 | int dry_run = 0; |
ad136b33 | 4052 | int discard = 1; |
b449c79e | 4053 | int force_overwrite = 0; |
fdea8fbc | 4054 | int quiet = 0; |
b449c79e DC |
4055 | char *protostring = NULL; |
4056 | int worst_freelist = 0; | |
4057 | ||
4058 | struct libxfs_xinit xi = { | |
4059 | .isdirect = LIBXFS_DIRECT, | |
4060 | .isreadonly = LIBXFS_EXCLUSIVELY, | |
4061 | }; | |
befcd768 DC |
4062 | struct xfs_mount mbuf = {}; |
4063 | struct xfs_mount *mp = &mbuf; | |
4064 | struct xfs_sb *sbp = &mp->m_sb; | |
d6522f1d | 4065 | struct xfs_dsb *dsb; |
b449c79e DC |
4066 | struct fs_topology ft = {}; |
4067 | struct cli_params cli = { | |
4068 | .xi = &xi, | |
4069 | .loginternal = 1, | |
6e0ed3d1 | 4070 | .is_supported = 1, |
b449c79e DC |
4071 | }; |
4072 | struct mkfs_params cfg = {}; | |
4073 | ||
6e0ed3d1 DW |
4074 | struct option long_options[] = { |
4075 | { | |
4076 | .name = "unsupported", | |
4077 | .has_arg = no_argument, | |
4078 | .flag = &cli.is_supported, | |
4079 | .val = 0, | |
4080 | }, | |
4081 | {NULL, 0, NULL, 0 }, | |
4082 | }; | |
4083 | int option_index = 0; | |
4084 | ||
68344ba0 DC |
4085 | /* build time defaults */ |
4086 | struct mkfs_default_params dft = { | |
b729d144 | 4087 | .source = _("package build definitions"), |
68344ba0 DC |
4088 | .sectorsize = XFS_MIN_SECTORSIZE, |
4089 | .blocksize = 1 << XFS_DFL_BLOCKSIZE_LOG, | |
4090 | .sb_feat = { | |
4091 | .log_version = 2, | |
4092 | .attr_version = 2, | |
129d98a9 ES |
4093 | .dir_version = 2, |
4094 | .inode_align = true, | |
68344ba0 DC |
4095 | .nci = false, |
4096 | .lazy_sb_counters = true, | |
639d0b0b | 4097 | .projid32bit = true, |
68344ba0 DC |
4098 | .crcs_enabled = true, |
4099 | .dirftype = true, | |
4100 | .finobt = true, | |
9cf846b5 | 4101 | .spinodes = true, |
bcd5b1b7 | 4102 | .rmapbt = true, |
ec1b42e6 | 4103 | .reflink = true, |
1c08f0ae | 4104 | .inobtcnt = true, |
68344ba0 DC |
4105 | .parent_pointers = false, |
4106 | .nodalign = false, | |
4107 | .nortalign = false, | |
1c08f0ae | 4108 | .bigtime = true, |
e5b18d7d | 4109 | .nrext64 = true, |
fbdda8fa DW |
4110 | /* |
4111 | * When we decide to enable a new feature by default, | |
4112 | * please remember to update the mkfs conf files. | |
4113 | */ | |
68344ba0 | 4114 | }, |
5f1a2100 | 4115 | }; |
2bd0ea18 | 4116 | |
7b754805 | 4117 | struct list_head buffer_list; |
d73b61f9 | 4118 | int error; |
7b754805 | 4119 | |
a43e656b | 4120 | platform_uuid_generate(&cli.uuid); |
2bd0ea18 | 4121 | progname = basename(argv[0]); |
9440d84d NS |
4122 | setlocale(LC_ALL, ""); |
4123 | bindtextdomain(PACKAGE, LOCALEDIR); | |
4124 | textdomain(PACKAGE); | |
4125 | ||
68344ba0 DC |
4126 | /* |
4127 | * TODO: Sourcing defaults from a config file | |
4128 | * | |
4129 | * Before anything else, see if there's a config file with different | |
4130 | * defaults. If a file exists in <package location>, read in the new | |
4131 | * default values and overwrite them in the &dft structure. This way the | |
4132 | * new defaults will apply before we parse the CLI, and the CLI will | |
b729d144 ES |
4133 | * still be able to override them. When more than one source is |
4134 | * implemented, emit a message to indicate where the defaults being | |
4135 | * used came from. | |
4136 | * | |
4137 | * printf(_("Default configuration sourced from %s\n"), dft.source); | |
68344ba0 | 4138 | */ |
68344ba0 DC |
4139 | |
4140 | /* copy new defaults into CLI parsing structure */ | |
4141 | memcpy(&cli.sb_feat, &dft.sb_feat, sizeof(cli.sb_feat)); | |
4142 | memcpy(&cli.fsx, &dft.fsx, sizeof(cli.fsx)); | |
4143 | ||
6e0ed3d1 DW |
4144 | while ((c = getopt_long(argc, argv, "b:c:d:i:l:L:m:n:KNp:qr:s:CfV", |
4145 | long_options, &option_index)) != EOF) { | |
2bd0ea18 | 4146 | switch (c) { |
6e0ed3d1 DW |
4147 | case 0: |
4148 | break; | |
2bd0ea18 | 4149 | case 'C': |
2bd0ea18 | 4150 | case 'f': |
f937adac | 4151 | force_overwrite = 1; |
2bd0ea18 NS |
4152 | break; |
4153 | case 'b': | |
33c62516 | 4154 | case 'c': |
b449c79e | 4155 | case 'd': |
d7240c96 | 4156 | case 'i': |
e3bc8390 | 4157 | case 'l': |
b449c79e | 4158 | case 'm': |
fdea8fbc | 4159 | case 'n': |
fb22e1b1 | 4160 | case 'p': |
7a9af89a | 4161 | case 'r': |
22319b56 | 4162 | case 's': |
85d6f03d | 4163 | parse_subopts(c, optarg, &cli); |
2bd0ea18 | 4164 | break; |
979f7189 NS |
4165 | case 'L': |
4166 | if (strlen(optarg) > sizeof(sbp->sb_fname)) | |
4167 | illegal(optarg, "L"); | |
b449c79e | 4168 | cfg.label = optarg; |
f7b80291 | 4169 | break; |
33a12367 | 4170 | case 'N': |
ebed4acf | 4171 | dry_run = 1; |
33a12367 | 4172 | break; |
ad136b33 CH |
4173 | case 'K': |
4174 | discard = 0; | |
4175 | break; | |
2bd0ea18 | 4176 | case 'q': |
ebed4acf | 4177 | quiet = 1; |
2bd0ea18 | 4178 | break; |
2bd0ea18 | 4179 | case 'V': |
9440d84d | 4180 | printf(_("%s version %s\n"), progname, VERSION); |
3d98fe63 | 4181 | exit(0); |
78aeaffd | 4182 | default: |
2bd0ea18 NS |
4183 | unknown(optopt, ""); |
4184 | } | |
4185 | } | |
4186 | if (argc - optind > 1) { | |
9440d84d | 4187 | fprintf(stderr, _("extra arguments\n")); |
2bd0ea18 NS |
4188 | usage(); |
4189 | } else if (argc - optind == 1) { | |
732f5b90 CH |
4190 | xi.dname = getstr(argv[optind], &dopts, D_NAME); |
4191 | } | |
9440d84d | 4192 | |
33c62516 DC |
4193 | /* |
4194 | * Now we have all the options parsed, we can read in the option file | |
4195 | * specified on the command line via "-c options=xxx". Once we have all | |
4196 | * the options from this file parsed, we can then proceed with parameter | |
4197 | * and bounds checking and making the filesystem. | |
4198 | */ | |
4199 | cfgfile_parse(&cli); | |
4200 | ||
fb22e1b1 | 4201 | protostring = setup_proto(cli.protofile); |
a3ac5af1 | 4202 | |
06ac92fd | 4203 | /* |
585f41bb DC |
4204 | * Extract as much of the valid config as we can from the CLI input |
4205 | * before opening the libxfs devices. | |
06ac92fd | 4206 | */ |
b1b8e54e | 4207 | validate_blocksize(&cfg, &cli, &dft); |
732f5b90 | 4208 | validate_sectorsize(&cfg, &cli, &dft, &ft, dry_run, force_overwrite); |
b449c79e DC |
4209 | |
4210 | /* | |
4211 | * XXX: we still need to set block size and sector size global variables | |
4212 | * so that getnum/cvtnum works correctly | |
4213 | */ | |
4214 | blocksize = cfg.blocksize; | |
4215 | sectorsize = cfg.sectorsize; | |
4216 | ||
22319b56 | 4217 | validate_log_sectorsize(&cfg, &cli, &dft); |
a43e656b | 4218 | validate_sb_features(&cfg, &cli); |
fd5eda53 | 4219 | |
fdea8fbc DC |
4220 | /* |
4221 | * we've now completed basic validation of the features, sector and | |
4222 | * block sizes, so from this point onwards we use the values found in | |
4223 | * the cfg structure for them, not the command line structure. | |
4224 | */ | |
4225 | validate_dirblocksize(&cfg, &cli); | |
8fe29028 | 4226 | validate_inodesize(&cfg, &cli); |
fdea8fbc | 4227 | |
e24dfa22 DC |
4228 | /* |
4229 | * if the device size was specified convert it to a block count | |
4230 | * now we have a valid block size. These will be set to zero if | |
4231 | * nothing was specified, indicating we should use the full device. | |
4232 | */ | |
4233 | cfg.dblocks = calc_dev_size(cli.dsize, &cfg, &dopts, D_SIZE, "data"); | |
4234 | cfg.logblocks = calc_dev_size(cli.logsize, &cfg, &lopts, L_SIZE, "log"); | |
4235 | cfg.rtblocks = calc_dev_size(cli.rtsize, &cfg, &ropts, R_SIZE, "rt"); | |
4236 | ||
80b154f7 DC |
4237 | validate_rtextsize(&cfg, &cli, &ft); |
4238 | ||
379f01d2 DC |
4239 | /* |
4240 | * Open and validate the device configurations | |
4241 | */ | |
915a27a0 | 4242 | open_devices(&cfg, &xi); |
732f5b90 | 4243 | validate_overwrite(xi.dname, force_overwrite); |
dd5ac314 | 4244 | validate_datadev(&cfg, &cli); |
732f5b90 CH |
4245 | validate_logdev(&cfg, &cli); |
4246 | validate_rtdev(&cfg, &cli); | |
59cf9679 | 4247 | calc_stripe_factors(&cfg, &cli, &ft); |
379f01d2 | 4248 | |
1de01446 DC |
4249 | /* |
4250 | * At this point when know exactly what size all the devices are, | |
4251 | * so we can start validating and calculating layout options that are | |
4252 | * dependent on device sizes. Once calculated, make sure everything | |
4253 | * aligns to device geometry correctly. | |
4254 | */ | |
4255 | calculate_initial_ag_geometry(&cfg, &cli); | |
051b4e37 | 4256 | align_ag_geometry(&cfg); |
1de01446 | 4257 | |
d7240c96 DC |
4258 | calculate_imaxpct(&cfg, &cli); |
4259 | ||
befcd768 DC |
4260 | /* |
4261 | * Set up the basic superblock parameters now so that we can use | |
4262 | * the geometry information we've already validated in libxfs | |
4263 | * provided functions to determine on-disk format information. | |
4264 | */ | |
a6fb6abe | 4265 | start_superblock_setup(&cfg, mp, sbp); |
a4170b73 | 4266 | initialise_mount(mp, sbp); |
befcd768 | 4267 | |
e3bc8390 DC |
4268 | /* |
4269 | * With the mount set up, we can finally calculate the log size | |
4270 | * constraints and do default size calculations and final validation | |
4271 | */ | |
4272 | calculate_log_size(&cfg, &cli, mp); | |
4273 | ||
ebc2e798 DW |
4274 | finish_superblock_setup(&cfg, mp, sbp); |
4275 | ||
9cfe71ba DW |
4276 | /* Validate the extent size hints now that @mp is fully set up. */ |
4277 | validate_extsize_hint(mp, &cli); | |
4278 | validate_cowextsize_hint(mp, &cli); | |
4279 | ||
6e0ed3d1 DW |
4280 | validate_supported(mp, &cli); |
4281 | ||
ebc2e798 | 4282 | /* Print the intended geometry of the fs. */ |
ebed4acf | 4283 | if (!quiet || dry_run) { |
ebc2e798 | 4284 | struct xfs_fsop_geom geo; |
ebc2e798 | 4285 | |
fa25ff74 | 4286 | libxfs_fs_geometry(mp, &geo, XFS_FS_GEOM_MAX_STRUCT_VER); |
732f5b90 | 4287 | xfs_report_geom(&geo, xi.dname, xi.logname, xi.rtname); |
ebed4acf | 4288 | if (dry_run) |
9440d84d NS |
4289 | exit(0); |
4290 | } | |
6003fd81 | 4291 | |
ca14a570 DW |
4292 | /* Make sure our checksum algorithm really works. */ |
4293 | if (crc32c_test(CRC32CTEST_QUIET) != 0) { | |
4294 | fprintf(stderr, | |
4295 | _("crc32c self-test failed, will not create a filesystem here.\n")); | |
4296 | return 1; | |
4297 | } | |
4298 | ||
b9d29568 DW |
4299 | /* Make sure our dir/attr hash algorithm really works. */ |
4300 | if (dahash_test(DAHASHTEST_QUIET) != 0) { | |
4301 | fprintf(stderr, | |
4302 | _("xfs dir/attr self-test failed, will not create a filesystem here.\n")); | |
4303 | return 1; | |
4304 | } | |
4305 | ||
915a27a0 JT |
4306 | /* |
4307 | * All values have been validated, discard the old device layout. | |
4308 | */ | |
4309 | if (discard && !dry_run) | |
7e8a6edb | 4310 | discard_devices(&xi, quiet); |
915a27a0 | 4311 | |
2f012bf9 | 4312 | /* |
e99bf83d | 4313 | * we need the libxfs buffer cache from here on in. |
2f012bf9 | 4314 | */ |
75c8b434 | 4315 | libxfs_buftarg_init(mp, xi.ddev, xi.logdev, xi.rtdev); |
2bd0ea18 | 4316 | |
2bd0ea18 | 4317 | /* |
e99bf83d DC |
4318 | * Before we mount the filesystem we need to make sure the devices have |
4319 | * enough of the filesystem structure on them that allows libxfs to | |
4320 | * mount. | |
2bd0ea18 | 4321 | */ |
e99bf83d | 4322 | prepare_devices(&cfg, &xi, mp, sbp, force_overwrite); |
9aa57116 | 4323 | mp = libxfs_mount(mp, sbp, xi.ddev, xi.logdev, xi.rtdev, 0); |
02e85e7f | 4324 | if (mp == NULL) { |
9440d84d NS |
4325 | fprintf(stderr, _("%s: filesystem failed to initialize\n"), |
4326 | progname); | |
2bd0ea18 NS |
4327 | exit(1); |
4328 | } | |
2bd0ea18 | 4329 | |
75c8b434 | 4330 | /* |
0ff1b0ed | 4331 | * Initialise all the static on disk metadata. |
75c8b434 | 4332 | */ |
7b754805 DW |
4333 | INIT_LIST_HEAD(&buffer_list); |
4334 | for (agno = 0; agno < cfg.agcount; agno++) { | |
a4170b73 | 4335 | initialise_ag_headers(&cfg, mp, agno, &worst_freelist, |
7b754805 DW |
4336 | &buffer_list); |
4337 | ||
4338 | if (agno % 16) | |
4339 | continue; | |
4340 | ||
d73b61f9 DW |
4341 | error = -libxfs_buf_delwri_submit(&buffer_list); |
4342 | if (error) { | |
4343 | fprintf(stderr, | |
4344 | _("%s: writing AG headers failed, err=%d\n"), | |
4345 | progname, error); | |
7b754805 DW |
4346 | exit(1); |
4347 | } | |
4348 | } | |
4349 | ||
d73b61f9 DW |
4350 | error = -libxfs_buf_delwri_submit(&buffer_list); |
4351 | if (error) { | |
4352 | fprintf(stderr, _("%s: writing AG headers failed, err=%d\n"), | |
4353 | progname, error); | |
7b754805 DW |
4354 | exit(1); |
4355 | } | |
2bd0ea18 | 4356 | |
2bd0ea18 | 4357 | /* |
0ff1b0ed | 4358 | * Initialise the freespace freelists (i.e. AGFLs) in each AG. |
2bd0ea18 | 4359 | */ |
0ff1b0ed DC |
4360 | for (agno = 0; agno < cfg.agcount; agno++) |
4361 | initialise_ag_freespace(mp, agno, worst_freelist); | |
9440d84d | 4362 | |
2bd0ea18 NS |
4363 | /* |
4364 | * Allocate the root inode and anything else in the proto file. | |
4365 | */ | |
e0aeb058 | 4366 | parse_proto(mp, &cli.fsx, &protostring, cli.proto_slashes_are_spaces); |
2bd0ea18 NS |
4367 | |
4368 | /* | |
9440d84d | 4369 | * Protect ourselves against possible stupidity |
2bd0ea18 | 4370 | */ |
659a4358 | 4371 | check_root_ino(mp); |
2bd0ea18 NS |
4372 | |
4373 | /* | |
e2847e5c | 4374 | * Re-write multiple secondary superblocks with rootinode field set |
2bd0ea18 | 4375 | */ |
e2847e5c DC |
4376 | if (mp->m_sb.sb_agcount > 1) |
4377 | rewrite_secondary_superblocks(mp); | |
2bd0ea18 | 4378 | |
f1b058f9 NS |
4379 | /* |
4380 | * Dump all inodes and buffers before marking us all done. | |
4381 | * Need to drop references to inodes we still hold, first. | |
4382 | */ | |
4383 | libxfs_rtmount_destroy(mp); | |
f1b058f9 NS |
4384 | libxfs_bcache_purge(); |
4385 | ||
2bd0ea18 NS |
4386 | /* |
4387 | * Mark the filesystem ok. | |
4388 | */ | |
67c4a324 ES |
4389 | buf = libxfs_getsb(mp); |
4390 | if (!buf || buf->b_error) | |
4391 | exit(1); | |
d6522f1d CH |
4392 | dsb = buf->b_addr; |
4393 | dsb->sb_inprogress = 0; | |
f524ae04 | 4394 | libxfs_buf_mark_dirty(buf); |
18b4f688 | 4395 | libxfs_buf_relse(buf); |
2bd0ea18 | 4396 | |
10fc0759 DW |
4397 | /* Exit w/ failure if anything failed to get written to our new fs. */ |
4398 | error = -libxfs_umount(mp); | |
4399 | if (error) | |
4400 | exit(1); | |
2bd0ea18 | 4401 | |
10fc0759 | 4402 | libxfs_destroy(&xi); |
2bd0ea18 NS |
4403 | return 0; |
4404 | } |