]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - db/sb.c
Update mkfs manpage for new defaults:
[thirdparty/xfsprogs-dev.git] / db / sb.c
CommitLineData
2bd0ea18 1/*
da23017d
NS
2 * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
3 * All Rights Reserved.
dfc130f3 4 *
da23017d
NS
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
2bd0ea18 7 * published by the Free Software Foundation.
dfc130f3 8 *
da23017d
NS
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
dfc130f3 13 *
da23017d
NS
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
2bd0ea18
NS
17 */
18
1d7e80ee
NS
19#include <xfs/libxfs.h>
20#include <xfs/libxlog.h>
2bd0ea18 21#include "command.h"
2bd0ea18
NS
22#include "type.h"
23#include "faddr.h"
24#include "fprint.h"
25#include "field.h"
26#include "io.h"
27#include "sb.h"
28#include "bit.h"
29#include "output.h"
4ca431fc 30#include "init.h"
2bd0ea18
NS
31
32static int sb_f(int argc, char **argv);
33static void sb_help(void);
4ca431fc
NS
34static int uuid_f(int argc, char **argv);
35static void uuid_help(void);
36static int label_f(int argc, char **argv);
37static void label_help(void);
38static int version_f(int argc, char **argv);
39static void version_help(void);
2bd0ea18
NS
40
41static const cmdinfo_t sb_cmd =
42 { "sb", NULL, sb_f, 0, 1, 1, "[agno]",
43 "set current address to sb header", sb_help };
4ca431fc
NS
44static const cmdinfo_t uuid_cmd =
45 { "uuid", NULL, uuid_f, 0, 1, 1, "[uuid]",
46 "write/print FS uuid", uuid_help };
47static const cmdinfo_t label_cmd =
48 { "label", NULL, label_f, 0, 1, 1, "[label]",
49 "write/print FS label", label_help };
50static const cmdinfo_t version_cmd =
d2df702b 51 { "version", NULL, version_f, 0, -1, 1, "[feature | [vnum fnum]]",
4ca431fc 52 "set feature bit(s) in the sb version field", version_help };
2bd0ea18 53
4ca431fc
NS
54void
55sb_init(void)
56{
57 add_command(&sb_cmd);
58 add_command(&uuid_cmd);
59 add_command(&label_cmd);
60 add_command(&version_cmd);
61}
2bd0ea18
NS
62
63#define OFF(f) bitize(offsetof(xfs_sb_t, sb_ ## f))
64#define SZC(f) szcount(xfs_sb_t, sb_ ## f)
65const field_t sb_flds[] = {
66 { "magicnum", FLDT_UINT32X, OI(OFF(magicnum)), C1, 0, TYP_NONE },
67 { "blocksize", FLDT_UINT32D, OI(OFF(blocksize)), C1, 0, TYP_NONE },
68 { "dblocks", FLDT_DRFSBNO, OI(OFF(dblocks)), C1, 0, TYP_NONE },
69 { "rblocks", FLDT_DRFSBNO, OI(OFF(rblocks)), C1, 0, TYP_NONE },
70 { "rextents", FLDT_DRTBNO, OI(OFF(rextents)), C1, 0, TYP_NONE },
71 { "uuid", FLDT_UUID, OI(OFF(uuid)), C1, 0, TYP_NONE },
72 { "logstart", FLDT_DFSBNO, OI(OFF(logstart)), C1, 0, TYP_LOG },
73 { "rootino", FLDT_INO, OI(OFF(rootino)), C1, 0, TYP_INODE },
74 { "rbmino", FLDT_INO, OI(OFF(rbmino)), C1, 0, TYP_INODE },
75 { "rsumino", FLDT_INO, OI(OFF(rsumino)), C1, 0, TYP_INODE },
76 { "rextsize", FLDT_AGBLOCK, OI(OFF(rextsize)), C1, 0, TYP_NONE },
77 { "agblocks", FLDT_AGBLOCK, OI(OFF(agblocks)), C1, 0, TYP_NONE },
78 { "agcount", FLDT_AGNUMBER, OI(OFF(agcount)), C1, 0, TYP_NONE },
79 { "rbmblocks", FLDT_EXTLEN, OI(OFF(rbmblocks)), C1, 0, TYP_NONE },
80 { "logblocks", FLDT_EXTLEN, OI(OFF(logblocks)), C1, 0, TYP_NONE },
81 { "versionnum", FLDT_UINT16X, OI(OFF(versionnum)), C1, 0, TYP_NONE },
82 { "sectsize", FLDT_UINT16D, OI(OFF(sectsize)), C1, 0, TYP_NONE },
83 { "inodesize", FLDT_UINT16D, OI(OFF(inodesize)), C1, 0, TYP_NONE },
84 { "inopblock", FLDT_UINT16D, OI(OFF(inopblock)), C1, 0, TYP_NONE },
85 { "fname", FLDT_CHARNS, OI(OFF(fname)), CI(SZC(fname)), 0, TYP_NONE },
86 { "blocklog", FLDT_UINT8D, OI(OFF(blocklog)), C1, 0, TYP_NONE },
87 { "sectlog", FLDT_UINT8D, OI(OFF(sectlog)), C1, 0, TYP_NONE },
88 { "inodelog", FLDT_UINT8D, OI(OFF(inodelog)), C1, 0, TYP_NONE },
89 { "inopblog", FLDT_UINT8D, OI(OFF(inopblog)), C1, 0, TYP_NONE },
90 { "agblklog", FLDT_UINT8D, OI(OFF(agblklog)), C1, 0, TYP_NONE },
91 { "rextslog", FLDT_UINT8D, OI(OFF(rextslog)), C1, 0, TYP_NONE },
92 { "inprogress", FLDT_UINT8D, OI(OFF(inprogress)), C1, 0, TYP_NONE },
93 { "imax_pct", FLDT_UINT8D, OI(OFF(imax_pct)), C1, 0, TYP_NONE },
94 { "icount", FLDT_UINT64D, OI(OFF(icount)), C1, 0, TYP_NONE },
95 { "ifree", FLDT_UINT64D, OI(OFF(ifree)), C1, 0, TYP_NONE },
96 { "fdblocks", FLDT_UINT64D, OI(OFF(fdblocks)), C1, 0, TYP_NONE },
97 { "frextents", FLDT_UINT64D, OI(OFF(frextents)), C1, 0, TYP_NONE },
98 { "uquotino", FLDT_INO, OI(OFF(uquotino)), C1, 0, TYP_INODE },
b36eef04 99 { "gquotino", FLDT_INO, OI(OFF(gquotino)), C1, 0, TYP_INODE },
2bd0ea18
NS
100 { "qflags", FLDT_UINT16X, OI(OFF(qflags)), C1, 0, TYP_NONE },
101 { "flags", FLDT_UINT8X, OI(OFF(flags)), C1, 0, TYP_NONE },
102 { "shared_vn", FLDT_UINT8D, OI(OFF(shared_vn)), C1, 0, TYP_NONE },
103 { "inoalignmt", FLDT_EXTLEN, OI(OFF(inoalignmt)), C1, 0, TYP_NONE },
104 { "unit", FLDT_UINT32D, OI(OFF(unit)), C1, 0, TYP_NONE },
105 { "width", FLDT_UINT32D, OI(OFF(width)), C1, 0, TYP_NONE },
106 { "dirblklog", FLDT_UINT8D, OI(OFF(dirblklog)), C1, 0, TYP_NONE },
9440d84d
NS
107 { "logsectlog", FLDT_UINT8D, OI(OFF(logsectlog)), C1, 0, TYP_NONE },
108 { "logsectsize", FLDT_UINT16D, OI(OFF(logsectsize)), C1, 0, TYP_NONE },
73bf5988 109 { "logsunit", FLDT_UINT32D, OI(OFF(logsunit)), C1, 0, TYP_NONE },
465e76a9 110 { "features2", FLDT_UINT32X, OI(OFF(features2)), C1, 0, TYP_NONE },
2bd0ea18
NS
111 { NULL }
112};
113
4ca431fc
NS
114const field_t sb_hfld[] = {
115 { "", FLDT_SB, OI(0), C1, 0, TYP_NONE },
116 { NULL }
117};
118
2bd0ea18
NS
119static void
120sb_help(void)
121{
122 dbprintf(
123"\n"
124" set allocation group superblock\n"
125"\n"
126" Example:\n"
127"\n"
128" 'sb 7' - set location to 7th allocation group superblock, set type to 'sb'\n"
129"\n"
9440d84d
NS
130" Located in the first sector of each allocation group, the superblock\n"
131" contains the base information for the filesystem.\n"
2bd0ea18
NS
132" The superblock in allocation group 0 is the primary. The copies in the\n"
133" remaining allocation groups only serve as backup for filesystem recovery.\n"
134" The icount/ifree/fdblocks/frextents are only updated in superblock 0.\n"
135"\n"
136);
137}
138
139static int
140sb_f(
141 int argc,
142 char **argv)
143{
144 xfs_agnumber_t agno;
145 char *p;
146
147 if (argc > 1) {
148 agno = (xfs_agnumber_t)strtoul(argv[1], &p, 0);
149 if (*p != '\0' || agno >= mp->m_sb.sb_agcount) {
150 dbprintf("bad allocation group number %s\n", argv[1]);
151 return 0;
152 }
153 cur_agno = agno;
154 } else if (cur_agno == NULLAGNUMBER)
155 cur_agno = 0;
156 ASSERT(typtab[TYP_SB].typnm == TYP_SB);
9440d84d
NS
157 set_cur(&typtab[TYP_SB],
158 XFS_AG_DADDR(mp, cur_agno, XFS_SB_DADDR),
159 XFS_FSS_TO_BB(mp, 1), DB_RING_ADD, NULL);
2bd0ea18
NS
160 return 0;
161}
162
2bd0ea18
NS
163/*ARGSUSED*/
164int
165sb_size(
166 void *obj,
167 int startoff,
168 int idx)
169{
170 return bitize(mp->m_sb.sb_sectsize);
171}
4ca431fc
NS
172
173static int
174get_sb(xfs_agnumber_t agno, xfs_sb_t *sb)
175{
176 push_cur();
177 set_cur(&typtab[TYP_SB],
178 XFS_AG_DADDR(mp, agno, XFS_SB_DADDR),
179 XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL);
dfc130f3 180
4ca431fc
NS
181 if (!iocur_top->data) {
182 dbprintf("can't read superblock for AG %u\n", agno);
183 pop_cur();
184 return 0;
185 }
186
46eca962 187 libxfs_xlate_sb(iocur_top->data, sb, 1, XFS_SB_ALL_BITS);
dfc130f3 188
4ca431fc
NS
189 if (sb->sb_magicnum != XFS_SB_MAGIC) {
190 dbprintf("bad sb magic # %#x in AG %u\n",
191 sb->sb_magicnum, agno);
dfc130f3 192 return 0;
4ca431fc
NS
193 }
194 if (!XFS_SB_GOOD_VERSION(sb)) {
195 dbprintf("bad sb version # %#x in AG %u\n",
196 sb->sb_versionnum, agno);
dfc130f3 197 return 0;
4ca431fc
NS
198 }
199 if (agno == 0 && sb->sb_inprogress != 0) {
200 dbprintf("mkfs not completed successfully\n");
dfc130f3 201 return 0;
4ca431fc
NS
202 }
203 return 1;
204}
205
206/* workaround craziness in the xlog routines */
207int xlog_recover_do_trans(xlog_t *log, xlog_recover_t *t, int p) { return 0; }
208
add013da
NS
209int
210sb_logcheck(void)
4ca431fc
NS
211{
212 xlog_t log;
213 xfs_daddr_t head_blk, tail_blk;
214
215 if (mp->m_sb.sb_logstart) {
216 if (x.logdev && x.logdev != x.ddev) {
217 dbprintf("aborting - external log specified for FS "
218 "with an internal log\n");
219 return 0;
220 }
221 } else {
222 if (!x.logdev || (x.logdev == x.ddev)) {
223 dbprintf("aborting - no external log specified for FS "
224 "with an external log\n");
225 return 0;
226 }
227 }
228
229 memset(&log, 0, sizeof(log));
230 if (!x.logdev)
231 x.logdev = x.ddev;
232 x.logBBsize = XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks);
233 x.logBBstart = XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart);
234 log.l_dev = (mp->m_sb.sb_logstart == 0) ? x.logdev : x.ddev;
235 log.l_logsize = BBTOB(log.l_logBBsize);
236 log.l_logBBsize = x.logBBsize;
237 log.l_logBBstart = x.logBBstart;
238 log.l_mp = mp;
239
240 if (xlog_find_tail(&log, &head_blk, &tail_blk, 0)) {
241 dbprintf("ERROR: cannot find log head/tail, run xfs_repair\n");
242 return 0;
243 }
244 if (head_blk != tail_blk) {
245 dbprintf(
246"ERROR: The filesystem has valuable metadata changes in a log which needs to\n"
247"be replayed. Mount the filesystem to replay the log, and unmount it before\n"
248"re-running %s. If you are unable to mount the filesystem, then use\n"
249"the xfs_repair -L option to destroy the log and attempt a repair.\n"
250"Note that destroying the log may cause corruption -- please attempt a mount\n"
251"of the filesystem before doing this.\n", progname);
252 return 0;
253 }
add013da
NS
254 return 1;
255}
256
257static int
258sb_logzero(uuid_t *uuidp)
259{
260 if (!sb_logcheck())
261 return 0;
4ca431fc
NS
262
263 dbprintf("Clearing log and setting UUID\n");
264
add013da
NS
265 if (libxfs_log_clear(
266 (mp->m_sb.sb_logstart == 0) ? x.logdev : x.ddev,
4ca431fc
NS
267 XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart),
268 (xfs_extlen_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks),
269 uuidp,
270 XFS_SB_VERSION_HASLOGV2(&mp->m_sb) ? 2 : 1,
271 mp->m_sb.sb_logsunit, XLOG_FMT)) {
272 dbprintf("ERROR: cannot clear the log\n");
273 return 0;
274 }
275 return 1;
276}
277
278
279static void
280uuid_help(void)
281{
282 dbprintf(
283"\n"
284" write/print FS uuid\n"
285"\n"
286" Example:\n"
287"\n"
288" 'uuid' - print UUID\n"
289" 'uuid 01234567-0123-0123-0123-0123456789ab' - write UUID\n"
290" 'uuid generate' - generate and write\n"
291" 'uuid rewrite' - copy UUID from SB 0\n"
292"\n"
293"The print function checks the UUID in each SB and will warn if the UUIDs\n"
294"differ between AGs (the log is not checked). The write commands will\n"
295"set the uuid in all AGs to either a specified value, a newly generated\n"
296"value or the value found in the first superblock (SB 0) respectively.\n"
297"As a side effect of writing the UUID, the log is cleared (which is fine\n"
298"on a CLEANLY unmounted FS).\n"
299"\n"
300);
301}
302
303static uuid_t *
304do_uuid(xfs_agnumber_t agno, uuid_t *uuid)
305{
306 xfs_sb_t tsb;
307 static uuid_t uu;
308
309 if (!get_sb(agno, &tsb))
310 return NULL;
311
312 if (!uuid) { /* get uuid */
313 memcpy(&uu, &tsb.sb_uuid, sizeof(uuid_t));
314 pop_cur();
315 return &uu;
316 }
317 /* set uuid */
318 memcpy(&tsb.sb_uuid, uuid, sizeof(uuid_t));
46eca962 319 libxfs_xlate_sb(iocur_top->data, &tsb, -1, XFS_SB_UUID);
4ca431fc
NS
320 write_cur();
321 return uuid;
322}
323
324static int
325uuid_f(
326 int argc,
327 char **argv)
328{
329 char bp[40];
330 xfs_agnumber_t agno;
331 uuid_t uu;
332 uuid_t *uup = NULL;
333
334 if (argc != 1 && argc != 2) {
335 dbprintf("invalid parameters\n");
336 return 0;
337 }
338
339 if (argc == 2) { /* WRITE UUID */
340
341 if ((x.isreadonly & LIBXFS_ISREADONLY) || !expert_mode) {
342 dbprintf("%s: not in expert mode, writing disabled\n",
343 progname);
344 return 0;
345 }
346
347 if (!strcasecmp(argv[1], "generate")) {
4d32d744 348 platform_uuid_generate(&uu);
4ca431fc 349 } else if (!strcasecmp(argv[1], "nil")) {
4d32d744 350 platform_uuid_clear(&uu);
4ca431fc
NS
351 } else if (!strcasecmp(argv[1], "rewrite")) {
352 uup = do_uuid(0, NULL);
353 if (!uup) {
354 dbprintf("failed to read UUID from AG 0\n");
355 return 0;
356 }
6699422d 357 memcpy(&uu, uup, sizeof(uuid_t));
4d32d744 358 platform_uuid_unparse(&uu, bp);
4ca431fc
NS
359 dbprintf("old UUID = %s\n", bp);
360 } else {
4d32d744 361 if (platform_uuid_parse(argv[1], &uu)) {
4ca431fc
NS
362 dbprintf("invalid UUID\n");
363 return 0;
364 }
365 }
366
367 /* clear the log (setting uuid) if its not dirty */
add013da 368 if (!sb_logzero(&uu))
4ca431fc
NS
369 return 0;
370
371 dbprintf("writing all SBs\n");
372 for (agno = 0; agno < mp->m_sb.sb_agcount; agno++)
373 if (!do_uuid(agno, &uu)) {
374 dbprintf("failed to set UUID in AG %d\n", agno);
375 break;
376 }
377
4d32d744 378 platform_uuid_unparse(&uu, bp);
4ca431fc
NS
379 dbprintf("new UUID = %s\n", bp);
380 return 0;
381
382 } else { /* READ+CHECK UUID */
dfc130f3 383
4ca431fc
NS
384 for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
385 uup = do_uuid(agno, NULL);
386 if (!uup) {
387 dbprintf("failed to read UUID from AG %d\n",
388 agno);
389 return 0;
390 }
391 if (agno) {
392 if (memcmp(&uu, uup, sizeof(uuid_t))) {
393 dbprintf("warning: UUID in AG %d "
394 "differs to the primary SB\n",
395 agno);
396 break;
397 }
398 } else {
6699422d 399 memcpy(&uu, uup, sizeof(uuid_t));
4ca431fc
NS
400 }
401 }
402 if (mp->m_sb.sb_logstart) {
403 if (x.logdev && x.logdev != x.ddev)
404 dbprintf("warning - external log specified "
405 "for FS with an internal log\n");
406 } else if (!x.logdev || (x.logdev == x.ddev)) {
407 dbprintf("warning - no external log specified "
408 "for FS with an external log\n");
409 }
410
4d32d744 411 platform_uuid_unparse(&uu, bp);
4ca431fc
NS
412 dbprintf("UUID = %s\n", bp);
413 }
414
415 return 0;
416}
417
418
419static void
420label_help(void)
421{
422 dbprintf(
423"\n"
424" write/print FS label\n"
425"\n"
426" Example:\n"
427"\n"
428" 'label' - print label\n"
429" 'label 123456789012' - write label\n"
430" 'label --' - write an empty label\n"
431"\n"
432"The print function checks the label in each SB and will warn if the labels\n"
433"differ between AGs. The write commands will set the label in all AGs to the\n"
434"specified value. The maximum length of a label is 12 characters - use of a\n"
435"longer label will result in truncation and a warning will be issued.\n"
436"\n"
437);
438}
439
440static char *
441do_label(xfs_agnumber_t agno, char *label)
442{
443 size_t len;
444 xfs_sb_t tsb;
dfc130f3 445 static char lbl[sizeof(tsb.sb_fname) + 1];
4ca431fc
NS
446
447 if (!get_sb(agno, &tsb))
448 return NULL;
449
450 memset(&lbl[0], 0, sizeof(lbl));
451
452 if (!label) { /* get label */
453 pop_cur();
454 memcpy(&lbl[0], &tsb.sb_fname, sizeof(tsb.sb_fname));
455 return &lbl[0];
456 }
457 /* set label */
458 if ((len = strlen(label)) > sizeof(tsb.sb_fname)) {
459 if (agno == 0)
460 dbprintf("%s: truncating label length from %d to %d\n",
461 progname, (int)len, (int)sizeof(tsb.sb_fname));
462 len = sizeof(tsb.sb_fname);
463 }
464 if ( len == 2 &&
465 (strcmp(label, "\"\"") == 0 ||
466 strcmp(label, "''") == 0 ||
467 strcmp(label, "--") == 0) )
468 label[0] = label[1] = '\0';
469 memset(&tsb.sb_fname, 0, sizeof(tsb.sb_fname));
470 memcpy(&tsb.sb_fname, label, len);
471 memcpy(&lbl[0], &tsb.sb_fname, sizeof(tsb.sb_fname));
46eca962 472 libxfs_xlate_sb(iocur_top->data, &tsb, -1, XFS_SB_FNAME);
4ca431fc
NS
473 write_cur();
474 return &lbl[0];
475}
476
477static int
478label_f(
479 int argc,
480 char **argv)
481{
482 char *p = NULL;
483 xfs_sb_t sb;
484 xfs_agnumber_t ag;
485
486 if (argc != 1 && argc != 2) {
487 dbprintf("invalid parameters\n");
488 return 0;
489 }
490
491 if (argc == 2) { /* WRITE LABEL */
492
493 if ((x.isreadonly & LIBXFS_ISREADONLY) || !expert_mode) {
494 dbprintf("%s: not in expert mode, writing disabled\n",
495 progname);
496 return 0;
497 }
498
499 dbprintf("writing all SBs\n");
500 for (ag = 0; ag < mp->m_sb.sb_agcount; ag++)
501 if ((p = do_label(ag, argv[1])) == NULL) {
502 dbprintf("failed to set label in AG %d\n", ag);
503 break;
504 }
505 dbprintf("new label = \"%s\"\n", p);
506
507 } else { /* READ LABEL */
508
509 for (ag = 0; ag < mp->m_sb.sb_agcount; ag++) {
510 p = do_label(ag, NULL);
511 if (!p) {
512 dbprintf("failed to read label in AG %d\n", ag);
513 return 0;
514 }
515 if (!ag)
516 memcpy(&sb.sb_fname, p, sizeof(sb.sb_fname));
517 else if (memcmp(&sb.sb_fname, p, sizeof(sb.sb_fname)))
518 dbprintf("warning: AG %d label differs\n", ag);
519 }
520 dbprintf("label = \"%s\"\n", p);
521 }
522 return 0;
523}
524
525
526static void
527version_help(void)
528{
529 dbprintf(
530"\n"
531" set/print feature bits in sb version\n"
532"\n"
533" Example:\n"
534"\n"
535" 'version' - print current feature bits\n"
536" 'version extflg' - enable unwritten extents\n"
70476e54
NS
537" 'version attr1' - enable v1 inline extended attributes\n"
538" 'version attr2' - enable v2 inline extended attributes\n"
66997473 539" 'version log2' - enable v2 log format\n"
4ca431fc
NS
540"\n"
541"The version function prints currently enabled features for a filesystem\n"
542"according to its the version field of the primary superblock.\n"
543"It can also be used to enable selected features, such as support for\n"
66997473 544"unwritten extents. The upated version is written into all AGs.\n"
4ca431fc
NS
545"\n"
546);
547}
548
549static int
70476e54 550do_version(xfs_agnumber_t agno, __uint16_t version, __uint32_t features)
4ca431fc
NS
551{
552 xfs_sb_t tsb;
66997473 553 __int64_t fields = 0;
4ca431fc
NS
554
555 if (!get_sb(agno, &tsb))
556 return 0;
557
66997473
NS
558 if ((version & XFS_SB_VERSION_LOGV2BIT) &&
559 !XFS_SB_VERSION_HASLOGV2(&tsb)) {
560 tsb.sb_logsunit = 1;
561 fields |= (1LL << XFS_SBS_LOGSUNIT);
562 }
563
70476e54
NS
564 tsb.sb_versionnum = version;
565 tsb.sb_features2 = features;
66997473
NS
566 fields |= XFS_SB_VERSIONNUM | XFS_SB_FEATURES2;
567 libxfs_xlate_sb(iocur_top->data, &tsb, -1, fields);
4ca431fc
NS
568 write_cur();
569 return 1;
570}
571
572static char *
573version_string(
574 xfs_sb_t *sbp)
575{
576 static char s[1024];
577
578 if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_1)
579 strcpy(s, "V1");
580 else if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_2)
581 strcpy(s, "V2");
582 else if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_3)
583 strcpy(s, "V3");
584 else if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4)
585 strcpy(s, "V4");
586
587 if (XFS_SB_VERSION_HASATTR(sbp))
588 strcat(s, ",ATTR");
589 if (XFS_SB_VERSION_HASNLINK(sbp))
590 strcat(s, ",NLINK");
591 if (XFS_SB_VERSION_HASQUOTA(sbp))
592 strcat(s, ",QUOTA");
593 if (XFS_SB_VERSION_HASALIGN(sbp))
594 strcat(s, ",ALIGN");
595 if (XFS_SB_VERSION_HASDALIGN(sbp))
596 strcat(s, ",DALIGN");
597 if (XFS_SB_VERSION_HASSHARED(sbp))
598 strcat(s, ",SHARED");
599 if (XFS_SB_VERSION_HASDIRV2(sbp))
600 strcat(s, ",DIRV2");
601 if (XFS_SB_VERSION_HASLOGV2(sbp))
602 strcat(s, ",LOGV2");
603 if (XFS_SB_VERSION_HASEXTFLGBIT(sbp))
604 strcat(s, ",EXTFLG");
605 if (XFS_SB_VERSION_HASSECTOR(sbp))
606 strcat(s, ",SECTOR");
ca86e759
NS
607 if (XFS_SB_VERSION_HASMOREBITS(sbp))
608 strcat(s, ",MOREBITS");
609 if (XFS_SB_VERSION_HASATTR2(sbp))
610 strcat(s, ",ATTR2");
cdded3d8
DC
611 if (XFS_SB_VERSION_LAZYSBCOUNT(sbp))
612 strcat(s, ",LAZYSBCOUNT");
4ca431fc
NS
613 return s;
614}
615
616static int
617version_f(
618 int argc,
619 char **argv)
620{
621 __uint16_t version = 0;
70476e54 622 __uint32_t features = 0;
4ca431fc
NS
623 xfs_agnumber_t ag;
624
625 if (argc == 2) { /* WRITE VERSION */
626
627 if ((x.isreadonly & LIBXFS_ISREADONLY) || !expert_mode) {
628 dbprintf("%s: not in expert mode, writing disabled\n",
629 progname);
630 return 0;
631 }
632
633 /* Logic here derived from the IRIX xfs_chver(1M) script. */
634 if (!strcasecmp(argv[1], "extflg")) {
635 switch (XFS_SB_VERSION_NUM(&mp->m_sb)) {
636 case XFS_SB_VERSION_1:
637 version = 0x0004 | XFS_SB_VERSION_EXTFLGBIT;
638 break;
639 case XFS_SB_VERSION_2:
640 version = 0x0014 | XFS_SB_VERSION_EXTFLGBIT;
641 break;
642 case XFS_SB_VERSION_3:
643 version = 0x0034 | XFS_SB_VERSION_EXTFLGBIT;
644 break;
645 case XFS_SB_VERSION_4:
646 if (XFS_SB_VERSION_HASEXTFLGBIT(&mp->m_sb))
647 dbprintf("unwritten extents flag"
648 " is already enabled\n");
649 else
650 version = mp->m_sb.sb_versionnum |
651 XFS_SB_VERSION_EXTFLGBIT;
652 break;
653 }
66997473
NS
654 } else if (!strcasecmp(argv[1], "log2")) {
655 switch (XFS_SB_VERSION_NUM(&mp->m_sb)) {
656 case XFS_SB_VERSION_1:
657 version = 0x0004 | XFS_SB_VERSION_LOGV2BIT;
658 break;
659 case XFS_SB_VERSION_2:
660 version = 0x0014 | XFS_SB_VERSION_LOGV2BIT;
661 break;
662 case XFS_SB_VERSION_3:
663 version = 0x0034 | XFS_SB_VERSION_LOGV2BIT;
664 break;
665 case XFS_SB_VERSION_4:
666 if (XFS_SB_VERSION_HASLOGV2(&mp->m_sb))
667 dbprintf("version 2 log format"
668 " is already in use\n");
669 else
670 version = mp->m_sb.sb_versionnum |
671 XFS_SB_VERSION_LOGV2BIT;
672 break;
673 }
70476e54
NS
674 } else if (!strcasecmp(argv[1], "attr1")) {
675 if (XFS_SB_VERSION_HASATTR2(&mp->m_sb)) {
676 if (!(mp->m_sb.sb_features2 &=
677 ~XFS_SB_VERSION2_ATTR2BIT))
678 mp->m_sb.sb_versionnum &=
679 ~XFS_SB_VERSION_MOREBITSBIT;
680 }
681 XFS_SB_VERSION_ADDATTR(&mp->m_sb);
682 version = mp->m_sb.sb_versionnum;
683 features = mp->m_sb.sb_features2;
684 } else if (!strcasecmp(argv[1], "attr2")) {
685 XFS_SB_VERSION_ADDATTR(&mp->m_sb);
686 XFS_SB_VERSION_ADDATTR2(&mp->m_sb);
687 version = mp->m_sb.sb_versionnum;
688 features = mp->m_sb.sb_features2;
4ca431fc
NS
689 } else {
690 dbprintf("%s: invalid version change command \"%s\"\n",
691 progname, argv[1]);
692 return 0;
693 }
694
695 if (version) {
696 dbprintf("writing all SBs\n");
697 for (ag = 0; ag < mp->m_sb.sb_agcount; ag++)
70476e54 698 if (!do_version(ag, version, features)) {
4ca431fc
NS
699 dbprintf("failed to set versionnum "
700 "in AG %d\n", ag);
701 break;
702 }
703 mp->m_sb.sb_versionnum = version;
70476e54 704 mp->m_sb.sb_features2 = features;
4ca431fc
NS
705 }
706 }
d2df702b
NS
707
708 if (argc == 3) { /* VERSIONNUM + FEATURES2 */
709 char *sp;
710
711 version = mp->m_sb.sb_versionnum;
712 features = mp->m_sb.sb_features2;
713 mp->m_sb.sb_versionnum = strtoul(argv[1], &sp, 0);
714 mp->m_sb.sb_features2 = strtoul(argv[2], &sp, 0);
715 }
716
ca86e759
NS
717 dbprintf("versionnum [0x%x+0x%x] = %s\n", mp->m_sb.sb_versionnum,
718 mp->m_sb.sb_features2, version_string(&mp->m_sb));
d2df702b
NS
719
720 if (argc == 3) { /* now reset... */
721 mp->m_sb.sb_versionnum = version;
722 mp->m_sb.sb_features2 = features;
723 return 0;
724 }
725
4ca431fc
NS
726 return 0;
727}