]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - db/sb.c
fix parallel builds
[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 =
9ee7055c
AM
42 { "sb", NULL, sb_f, 0, 1, 1, N_("[agno]"),
43 N_("set current address to sb header"), sb_help };
4ca431fc 44static const cmdinfo_t uuid_cmd =
9ee7055c
AM
45 { "uuid", NULL, uuid_f, 0, 1, 1, N_("[uuid]"),
46 N_("write/print FS uuid"), uuid_help };
4ca431fc 47static const cmdinfo_t label_cmd =
9ee7055c
AM
48 { "label", NULL, label_f, 0, 1, 1, N_("[label]"),
49 N_("write/print FS label"), label_help };
4ca431fc 50static const cmdinfo_t version_cmd =
9ee7055c
AM
51 { "version", NULL, version_f, 0, -1, 1, N_("[feature | [vnum fnum]]"),
52 N_("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 },
45935737 111 { "bad_features2", FLDT_UINT32X, OI(OFF(bad_features2)), C1, 0, TYP_NONE },
2bd0ea18
NS
112 { NULL }
113};
114
4ca431fc
NS
115const field_t sb_hfld[] = {
116 { "", FLDT_SB, OI(0), C1, 0, TYP_NONE },
117 { NULL }
118};
119
2bd0ea18
NS
120static void
121sb_help(void)
122{
9ee7055c 123 dbprintf(_(
2bd0ea18
NS
124"\n"
125" set allocation group superblock\n"
126"\n"
127" Example:\n"
128"\n"
129" 'sb 7' - set location to 7th allocation group superblock, set type to 'sb'\n"
130"\n"
9440d84d
NS
131" Located in the first sector of each allocation group, the superblock\n"
132" contains the base information for the filesystem.\n"
2bd0ea18
NS
133" The superblock in allocation group 0 is the primary. The copies in the\n"
134" remaining allocation groups only serve as backup for filesystem recovery.\n"
135" The icount/ifree/fdblocks/frextents are only updated in superblock 0.\n"
136"\n"
9ee7055c 137));
2bd0ea18
NS
138}
139
140static int
141sb_f(
142 int argc,
143 char **argv)
144{
145 xfs_agnumber_t agno;
146 char *p;
147
148 if (argc > 1) {
149 agno = (xfs_agnumber_t)strtoul(argv[1], &p, 0);
150 if (*p != '\0' || agno >= mp->m_sb.sb_agcount) {
9ee7055c 151 dbprintf(_("bad allocation group number %s\n"), argv[1]);
2bd0ea18
NS
152 return 0;
153 }
154 cur_agno = agno;
155 } else if (cur_agno == NULLAGNUMBER)
156 cur_agno = 0;
157 ASSERT(typtab[TYP_SB].typnm == TYP_SB);
9440d84d
NS
158 set_cur(&typtab[TYP_SB],
159 XFS_AG_DADDR(mp, cur_agno, XFS_SB_DADDR),
160 XFS_FSS_TO_BB(mp, 1), DB_RING_ADD, NULL);
2bd0ea18
NS
161 return 0;
162}
163
2bd0ea18
NS
164/*ARGSUSED*/
165int
166sb_size(
167 void *obj,
168 int startoff,
169 int idx)
170{
171 return bitize(mp->m_sb.sb_sectsize);
172}
4ca431fc
NS
173
174static int
175get_sb(xfs_agnumber_t agno, xfs_sb_t *sb)
176{
177 push_cur();
178 set_cur(&typtab[TYP_SB],
179 XFS_AG_DADDR(mp, agno, XFS_SB_DADDR),
180 XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL);
dfc130f3 181
4ca431fc 182 if (!iocur_top->data) {
9ee7055c 183 dbprintf(_("can't read superblock for AG %u\n"), agno);
4ca431fc
NS
184 pop_cur();
185 return 0;
186 }
187
5e656dbb 188 libxfs_sb_from_disk(sb, iocur_top->data);
dfc130f3 189
4ca431fc 190 if (sb->sb_magicnum != XFS_SB_MAGIC) {
9ee7055c 191 dbprintf(_("bad sb magic # %#x in AG %u\n"),
4ca431fc 192 sb->sb_magicnum, agno);
dfc130f3 193 return 0;
4ca431fc 194 }
5e656dbb 195 if (!xfs_sb_good_version(sb)) {
9ee7055c 196 dbprintf(_("bad sb version # %#x in AG %u\n"),
4ca431fc 197 sb->sb_versionnum, agno);
dfc130f3 198 return 0;
4ca431fc
NS
199 }
200 if (agno == 0 && sb->sb_inprogress != 0) {
9ee7055c 201 dbprintf(_("mkfs not completed successfully\n"));
dfc130f3 202 return 0;
4ca431fc
NS
203 }
204 return 1;
205}
206
207/* workaround craziness in the xlog routines */
208int xlog_recover_do_trans(xlog_t *log, xlog_recover_t *t, int p) { return 0; }
209
add013da
NS
210int
211sb_logcheck(void)
4ca431fc
NS
212{
213 xlog_t log;
214 xfs_daddr_t head_blk, tail_blk;
215
216 if (mp->m_sb.sb_logstart) {
217 if (x.logdev && x.logdev != x.ddev) {
9ee7055c
AM
218 dbprintf(_("aborting - external log specified for FS "
219 "with an internal log\n"));
4ca431fc
NS
220 return 0;
221 }
222 } else {
223 if (!x.logdev || (x.logdev == x.ddev)) {
9ee7055c
AM
224 dbprintf(_("aborting - no external log specified for FS "
225 "with an external log\n"));
4ca431fc
NS
226 return 0;
227 }
228 }
229
230 memset(&log, 0, sizeof(log));
231 if (!x.logdev)
232 x.logdev = x.ddev;
233 x.logBBsize = XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks);
234 x.logBBstart = XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart);
235 log.l_dev = (mp->m_sb.sb_logstart == 0) ? x.logdev : x.ddev;
236 log.l_logsize = BBTOB(log.l_logBBsize);
237 log.l_logBBsize = x.logBBsize;
238 log.l_logBBstart = x.logBBstart;
239 log.l_mp = mp;
240
5e656dbb 241 if (xlog_find_tail(&log, &head_blk, &tail_blk)) {
9ee7055c 242 dbprintf(_("ERROR: cannot find log head/tail, run xfs_repair\n"));
4ca431fc
NS
243 return 0;
244 }
245 if (head_blk != tail_blk) {
9ee7055c 246 dbprintf(_(
4ca431fc
NS
247"ERROR: The filesystem has valuable metadata changes in a log which needs to\n"
248"be replayed. Mount the filesystem to replay the log, and unmount it before\n"
249"re-running %s. If you are unable to mount the filesystem, then use\n"
250"the xfs_repair -L option to destroy the log and attempt a repair.\n"
251"Note that destroying the log may cause corruption -- please attempt a mount\n"
9ee7055c 252"of the filesystem before doing this.\n"), progname);
4ca431fc
NS
253 return 0;
254 }
add013da
NS
255 return 1;
256}
257
258static int
259sb_logzero(uuid_t *uuidp)
260{
261 if (!sb_logcheck())
262 return 0;
4ca431fc 263
9ee7055c 264 dbprintf(_("Clearing log and setting UUID\n"));
4ca431fc 265
add013da
NS
266 if (libxfs_log_clear(
267 (mp->m_sb.sb_logstart == 0) ? x.logdev : x.ddev,
4ca431fc
NS
268 XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart),
269 (xfs_extlen_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks),
270 uuidp,
5e656dbb 271 xfs_sb_version_haslogv2(&mp->m_sb) ? 2 : 1,
4ca431fc 272 mp->m_sb.sb_logsunit, XLOG_FMT)) {
9ee7055c 273 dbprintf(_("ERROR: cannot clear the log\n"));
4ca431fc
NS
274 return 0;
275 }
276 return 1;
277}
278
279
280static void
281uuid_help(void)
282{
9ee7055c 283 dbprintf(_(
4ca431fc
NS
284"\n"
285" write/print FS uuid\n"
286"\n"
287" Example:\n"
288"\n"
289" 'uuid' - print UUID\n"
290" 'uuid 01234567-0123-0123-0123-0123456789ab' - write UUID\n"
291" 'uuid generate' - generate and write\n"
292" 'uuid rewrite' - copy UUID from SB 0\n"
293"\n"
294"The print function checks the UUID in each SB and will warn if the UUIDs\n"
295"differ between AGs (the log is not checked). The write commands will\n"
296"set the uuid in all AGs to either a specified value, a newly generated\n"
297"value or the value found in the first superblock (SB 0) respectively.\n"
298"As a side effect of writing the UUID, the log is cleared (which is fine\n"
299"on a CLEANLY unmounted FS).\n"
300"\n"
9ee7055c 301));
4ca431fc
NS
302}
303
304static uuid_t *
305do_uuid(xfs_agnumber_t agno, uuid_t *uuid)
306{
307 xfs_sb_t tsb;
308 static uuid_t uu;
309
310 if (!get_sb(agno, &tsb))
311 return NULL;
312
313 if (!uuid) { /* get uuid */
314 memcpy(&uu, &tsb.sb_uuid, sizeof(uuid_t));
315 pop_cur();
316 return &uu;
317 }
318 /* set uuid */
319 memcpy(&tsb.sb_uuid, uuid, sizeof(uuid_t));
5e656dbb 320 libxfs_sb_to_disk(iocur_top->data, &tsb, XFS_SB_UUID);
4ca431fc
NS
321 write_cur();
322 return uuid;
323}
324
325static int
326uuid_f(
327 int argc,
328 char **argv)
329{
330 char bp[40];
331 xfs_agnumber_t agno;
332 uuid_t uu;
333 uuid_t *uup = NULL;
334
335 if (argc != 1 && argc != 2) {
9ee7055c 336 dbprintf(_("invalid parameters\n"));
4ca431fc
NS
337 return 0;
338 }
339
340 if (argc == 2) { /* WRITE UUID */
341
342 if ((x.isreadonly & LIBXFS_ISREADONLY) || !expert_mode) {
9ee7055c 343 dbprintf(_("%s: not in expert mode, writing disabled\n"),
4ca431fc
NS
344 progname);
345 return 0;
346 }
347
348 if (!strcasecmp(argv[1], "generate")) {
4d32d744 349 platform_uuid_generate(&uu);
4ca431fc 350 } else if (!strcasecmp(argv[1], "nil")) {
4d32d744 351 platform_uuid_clear(&uu);
4ca431fc
NS
352 } else if (!strcasecmp(argv[1], "rewrite")) {
353 uup = do_uuid(0, NULL);
354 if (!uup) {
9ee7055c 355 dbprintf(_("failed to read UUID from AG 0\n"));
4ca431fc
NS
356 return 0;
357 }
6699422d 358 memcpy(&uu, uup, sizeof(uuid_t));
4d32d744 359 platform_uuid_unparse(&uu, bp);
9ee7055c 360 dbprintf(_("old UUID = %s\n"), bp);
4ca431fc 361 } else {
4d32d744 362 if (platform_uuid_parse(argv[1], &uu)) {
9ee7055c 363 dbprintf(_("invalid UUID\n"));
4ca431fc
NS
364 return 0;
365 }
366 }
367
368 /* clear the log (setting uuid) if its not dirty */
add013da 369 if (!sb_logzero(&uu))
4ca431fc
NS
370 return 0;
371
9ee7055c 372 dbprintf(_("writing all SBs\n"));
4ca431fc
NS
373 for (agno = 0; agno < mp->m_sb.sb_agcount; agno++)
374 if (!do_uuid(agno, &uu)) {
9ee7055c 375 dbprintf(_("failed to set UUID in AG %d\n"), agno);
4ca431fc
NS
376 break;
377 }
378
4d32d744 379 platform_uuid_unparse(&uu, bp);
9ee7055c 380 dbprintf(_("new UUID = %s\n"), bp);
4ca431fc
NS
381 return 0;
382
383 } else { /* READ+CHECK UUID */
dfc130f3 384
4ca431fc
NS
385 for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
386 uup = do_uuid(agno, NULL);
387 if (!uup) {
9ee7055c 388 dbprintf(_("failed to read UUID from AG %d\n"),
4ca431fc
NS
389 agno);
390 return 0;
391 }
392 if (agno) {
393 if (memcmp(&uu, uup, sizeof(uuid_t))) {
9ee7055c
AM
394 dbprintf(_("warning: UUID in AG %d "
395 "differs to the primary SB\n"),
4ca431fc
NS
396 agno);
397 break;
398 }
399 } else {
6699422d 400 memcpy(&uu, uup, sizeof(uuid_t));
4ca431fc
NS
401 }
402 }
403 if (mp->m_sb.sb_logstart) {
404 if (x.logdev && x.logdev != x.ddev)
9ee7055c
AM
405 dbprintf(_("warning - external log specified "
406 "for FS with an internal log\n"));
4ca431fc 407 } else if (!x.logdev || (x.logdev == x.ddev)) {
9ee7055c
AM
408 dbprintf(_("warning - no external log specified "
409 "for FS with an external log\n"));
4ca431fc
NS
410 }
411
4d32d744 412 platform_uuid_unparse(&uu, bp);
9ee7055c 413 dbprintf(_("UUID = %s\n"), bp);
4ca431fc
NS
414 }
415
416 return 0;
417}
418
419
420static void
421label_help(void)
422{
9ee7055c 423 dbprintf(_(
4ca431fc
NS
424"\n"
425" write/print FS label\n"
426"\n"
427" Example:\n"
428"\n"
429" 'label' - print label\n"
430" 'label 123456789012' - write label\n"
431" 'label --' - write an empty label\n"
432"\n"
433"The print function checks the label in each SB and will warn if the labels\n"
434"differ between AGs. The write commands will set the label in all AGs to the\n"
435"specified value. The maximum length of a label is 12 characters - use of a\n"
436"longer label will result in truncation and a warning will be issued.\n"
437"\n"
9ee7055c 438));
4ca431fc
NS
439}
440
441static char *
442do_label(xfs_agnumber_t agno, char *label)
443{
444 size_t len;
445 xfs_sb_t tsb;
dfc130f3 446 static char lbl[sizeof(tsb.sb_fname) + 1];
4ca431fc
NS
447
448 if (!get_sb(agno, &tsb))
449 return NULL;
450
451 memset(&lbl[0], 0, sizeof(lbl));
452
453 if (!label) { /* get label */
454 pop_cur();
455 memcpy(&lbl[0], &tsb.sb_fname, sizeof(tsb.sb_fname));
456 return &lbl[0];
457 }
458 /* set label */
459 if ((len = strlen(label)) > sizeof(tsb.sb_fname)) {
460 if (agno == 0)
9ee7055c 461 dbprintf(_("%s: truncating label length from %d to %d\n"),
4ca431fc
NS
462 progname, (int)len, (int)sizeof(tsb.sb_fname));
463 len = sizeof(tsb.sb_fname);
464 }
465 if ( len == 2 &&
466 (strcmp(label, "\"\"") == 0 ||
467 strcmp(label, "''") == 0 ||
468 strcmp(label, "--") == 0) )
469 label[0] = label[1] = '\0';
470 memset(&tsb.sb_fname, 0, sizeof(tsb.sb_fname));
471 memcpy(&tsb.sb_fname, label, len);
472 memcpy(&lbl[0], &tsb.sb_fname, sizeof(tsb.sb_fname));
5e656dbb 473 libxfs_sb_to_disk(iocur_top->data, &tsb, XFS_SB_FNAME);
4ca431fc
NS
474 write_cur();
475 return &lbl[0];
476}
477
478static int
479label_f(
480 int argc,
481 char **argv)
482{
483 char *p = NULL;
484 xfs_sb_t sb;
485 xfs_agnumber_t ag;
486
487 if (argc != 1 && argc != 2) {
9ee7055c 488 dbprintf(_("invalid parameters\n"));
4ca431fc
NS
489 return 0;
490 }
491
492 if (argc == 2) { /* WRITE LABEL */
493
494 if ((x.isreadonly & LIBXFS_ISREADONLY) || !expert_mode) {
9ee7055c 495 dbprintf(_("%s: not in expert mode, writing disabled\n"),
4ca431fc
NS
496 progname);
497 return 0;
498 }
499
9ee7055c 500 dbprintf(_("writing all SBs\n"));
4ca431fc
NS
501 for (ag = 0; ag < mp->m_sb.sb_agcount; ag++)
502 if ((p = do_label(ag, argv[1])) == NULL) {
9ee7055c 503 dbprintf(_("failed to set label in AG %d\n"), ag);
4ca431fc
NS
504 break;
505 }
9ee7055c 506 dbprintf(_("new label = \"%s\"\n"), p);
4ca431fc
NS
507
508 } else { /* READ LABEL */
509
510 for (ag = 0; ag < mp->m_sb.sb_agcount; ag++) {
511 p = do_label(ag, NULL);
512 if (!p) {
9ee7055c 513 dbprintf(_("failed to read label in AG %d\n"), ag);
4ca431fc
NS
514 return 0;
515 }
516 if (!ag)
517 memcpy(&sb.sb_fname, p, sizeof(sb.sb_fname));
518 else if (memcmp(&sb.sb_fname, p, sizeof(sb.sb_fname)))
9ee7055c 519 dbprintf(_("warning: AG %d label differs\n"), ag);
4ca431fc 520 }
9ee7055c 521 dbprintf(_("label = \"%s\"\n"), p);
4ca431fc
NS
522 }
523 return 0;
524}
525
526
527static void
528version_help(void)
529{
9ee7055c 530 dbprintf(_(
4ca431fc
NS
531"\n"
532" set/print feature bits in sb version\n"
533"\n"
534" Example:\n"
535"\n"
536" 'version' - print current feature bits\n"
537" 'version extflg' - enable unwritten extents\n"
70476e54
NS
538" 'version attr1' - enable v1 inline extended attributes\n"
539" 'version attr2' - enable v2 inline extended attributes\n"
66997473 540" 'version log2' - enable v2 log format\n"
4ca431fc
NS
541"\n"
542"The version function prints currently enabled features for a filesystem\n"
543"according to its the version field of the primary superblock.\n"
544"It can also be used to enable selected features, such as support for\n"
66997473 545"unwritten extents. The upated version is written into all AGs.\n"
4ca431fc 546"\n"
9ee7055c 547));
4ca431fc
NS
548}
549
550static int
70476e54 551do_version(xfs_agnumber_t agno, __uint16_t version, __uint32_t features)
4ca431fc
NS
552{
553 xfs_sb_t tsb;
66997473 554 __int64_t fields = 0;
4ca431fc
NS
555
556 if (!get_sb(agno, &tsb))
557 return 0;
558
66997473 559 if ((version & XFS_SB_VERSION_LOGV2BIT) &&
5e656dbb 560 !xfs_sb_version_haslogv2(&tsb)) {
66997473
NS
561 tsb.sb_logsunit = 1;
562 fields |= (1LL << XFS_SBS_LOGSUNIT);
563 }
564
70476e54
NS
565 tsb.sb_versionnum = version;
566 tsb.sb_features2 = features;
66997473 567 fields |= XFS_SB_VERSIONNUM | XFS_SB_FEATURES2;
5e656dbb 568 libxfs_sb_to_disk(iocur_top->data, &tsb, fields);
4ca431fc
NS
569 write_cur();
570 return 1;
571}
572
573static char *
574version_string(
575 xfs_sb_t *sbp)
576{
577 static char s[1024];
578
579 if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_1)
580 strcpy(s, "V1");
581 else if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_2)
582 strcpy(s, "V2");
583 else if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_3)
584 strcpy(s, "V3");
585 else if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4)
586 strcpy(s, "V4");
587
5e656dbb 588 if (xfs_sb_version_hasattr(sbp))
4ca431fc 589 strcat(s, ",ATTR");
5e656dbb 590 if (xfs_sb_version_hasnlink(sbp))
4ca431fc 591 strcat(s, ",NLINK");
5e656dbb 592 if (xfs_sb_version_hasquota(sbp))
4ca431fc 593 strcat(s, ",QUOTA");
5e656dbb 594 if (xfs_sb_version_hasalign(sbp))
4ca431fc 595 strcat(s, ",ALIGN");
5e656dbb 596 if (xfs_sb_version_hasdalign(sbp))
4ca431fc 597 strcat(s, ",DALIGN");
5e656dbb 598 if (xfs_sb_version_hasshared(sbp))
4ca431fc 599 strcat(s, ",SHARED");
5e656dbb 600 if (xfs_sb_version_hasdirv2(sbp))
4ca431fc 601 strcat(s, ",DIRV2");
5e656dbb 602 if (xfs_sb_version_haslogv2(sbp))
4ca431fc 603 strcat(s, ",LOGV2");
5e656dbb 604 if (xfs_sb_version_hasextflgbit(sbp))
4ca431fc 605 strcat(s, ",EXTFLG");
5e656dbb 606 if (xfs_sb_version_hassector(sbp))
4ca431fc 607 strcat(s, ",SECTOR");
51ca7008
BN
608 if (xfs_sb_version_hasasciici(sbp))
609 strcat(s, ",ASCII_CI");
5e656dbb 610 if (xfs_sb_version_hasmorebits(sbp))
ca86e759 611 strcat(s, ",MOREBITS");
5e656dbb 612 if (xfs_sb_version_hasattr2(sbp))
ca86e759 613 strcat(s, ",ATTR2");
5e656dbb 614 if (xfs_sb_version_haslazysbcount(sbp))
cdded3d8 615 strcat(s, ",LAZYSBCOUNT");
4ca431fc
NS
616 return s;
617}
618
619static int
620version_f(
621 int argc,
622 char **argv)
623{
624 __uint16_t version = 0;
70476e54 625 __uint32_t features = 0;
4ca431fc
NS
626 xfs_agnumber_t ag;
627
628 if (argc == 2) { /* WRITE VERSION */
629
630 if ((x.isreadonly & LIBXFS_ISREADONLY) || !expert_mode) {
9ee7055c 631 dbprintf(_("%s: not in expert mode, writing disabled\n"),
4ca431fc
NS
632 progname);
633 return 0;
634 }
635
636 /* Logic here derived from the IRIX xfs_chver(1M) script. */
637 if (!strcasecmp(argv[1], "extflg")) {
638 switch (XFS_SB_VERSION_NUM(&mp->m_sb)) {
639 case XFS_SB_VERSION_1:
640 version = 0x0004 | XFS_SB_VERSION_EXTFLGBIT;
641 break;
642 case XFS_SB_VERSION_2:
643 version = 0x0014 | XFS_SB_VERSION_EXTFLGBIT;
644 break;
645 case XFS_SB_VERSION_3:
646 version = 0x0034 | XFS_SB_VERSION_EXTFLGBIT;
647 break;
648 case XFS_SB_VERSION_4:
5e656dbb 649 if (xfs_sb_version_hasextflgbit(&mp->m_sb))
9ee7055c
AM
650 dbprintf(_("unwritten extents flag"
651 " is already enabled\n"));
4ca431fc
NS
652 else
653 version = mp->m_sb.sb_versionnum |
654 XFS_SB_VERSION_EXTFLGBIT;
655 break;
656 }
66997473
NS
657 } else if (!strcasecmp(argv[1], "log2")) {
658 switch (XFS_SB_VERSION_NUM(&mp->m_sb)) {
659 case XFS_SB_VERSION_1:
660 version = 0x0004 | XFS_SB_VERSION_LOGV2BIT;
661 break;
662 case XFS_SB_VERSION_2:
663 version = 0x0014 | XFS_SB_VERSION_LOGV2BIT;
664 break;
665 case XFS_SB_VERSION_3:
666 version = 0x0034 | XFS_SB_VERSION_LOGV2BIT;
667 break;
668 case XFS_SB_VERSION_4:
5e656dbb 669 if (xfs_sb_version_haslogv2(&mp->m_sb))
9ee7055c
AM
670 dbprintf(_("version 2 log format"
671 " is already in use\n"));
66997473
NS
672 else
673 version = mp->m_sb.sb_versionnum |
674 XFS_SB_VERSION_LOGV2BIT;
675 break;
676 }
70476e54 677 } else if (!strcasecmp(argv[1], "attr1")) {
5e656dbb 678 if (xfs_sb_version_hasattr2(&mp->m_sb)) {
70476e54
NS
679 if (!(mp->m_sb.sb_features2 &=
680 ~XFS_SB_VERSION2_ATTR2BIT))
681 mp->m_sb.sb_versionnum &=
682 ~XFS_SB_VERSION_MOREBITSBIT;
683 }
5e656dbb 684 xfs_sb_version_addattr(&mp->m_sb);
70476e54
NS
685 version = mp->m_sb.sb_versionnum;
686 features = mp->m_sb.sb_features2;
687 } else if (!strcasecmp(argv[1], "attr2")) {
5e656dbb
BN
688 xfs_sb_version_addattr(&mp->m_sb);
689 xfs_sb_version_addattr2(&mp->m_sb);
70476e54
NS
690 version = mp->m_sb.sb_versionnum;
691 features = mp->m_sb.sb_features2;
4ca431fc 692 } else {
9ee7055c 693 dbprintf(_("%s: invalid version change command \"%s\"\n"),
4ca431fc
NS
694 progname, argv[1]);
695 return 0;
696 }
697
698 if (version) {
9ee7055c 699 dbprintf(_("writing all SBs\n"));
4ca431fc 700 for (ag = 0; ag < mp->m_sb.sb_agcount; ag++)
70476e54 701 if (!do_version(ag, version, features)) {
9ee7055c
AM
702 dbprintf(_("failed to set versionnum "
703 "in AG %d\n"), ag);
4ca431fc
NS
704 break;
705 }
706 mp->m_sb.sb_versionnum = version;
70476e54 707 mp->m_sb.sb_features2 = features;
4ca431fc
NS
708 }
709 }
d2df702b
NS
710
711 if (argc == 3) { /* VERSIONNUM + FEATURES2 */
712 char *sp;
713
714 version = mp->m_sb.sb_versionnum;
715 features = mp->m_sb.sb_features2;
716 mp->m_sb.sb_versionnum = strtoul(argv[1], &sp, 0);
717 mp->m_sb.sb_features2 = strtoul(argv[2], &sp, 0);
718 }
719
9ee7055c 720 dbprintf(_("versionnum [0x%x+0x%x] = %s\n"), mp->m_sb.sb_versionnum,
ca86e759 721 mp->m_sb.sb_features2, version_string(&mp->m_sb));
d2df702b
NS
722
723 if (argc == 3) { /* now reset... */
724 mp->m_sb.sb_versionnum = version;
725 mp->m_sb.sb_features2 = features;
726 return 0;
727 }
728
4ca431fc
NS
729 return 0;
730}