]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - db/sb.c
xfsprogs: Release v6.8.0
[thirdparty/xfsprogs-dev.git] / db / sb.c
CommitLineData
959ef981 1// SPDX-License-Identifier: GPL-2.0
2bd0ea18 2/*
da23017d
NS
3 * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
4 * All Rights Reserved.
2bd0ea18
NS
5 */
6
6b803e5a
CH
7#include "libxfs.h"
8#include "libxlog.h"
2bd0ea18 9#include "command.h"
2bd0ea18
NS
10#include "type.h"
11#include "faddr.h"
12#include "fprint.h"
13#include "field.h"
14#include "io.h"
15#include "sb.h"
16#include "bit.h"
17#include "output.h"
4ca431fc 18#include "init.h"
2bd0ea18 19
9c4e12fb
ES
20#define uuid_equal(s,d) (platform_uuid_compare((s),(d)) == 0)
21
2bd0ea18
NS
22static int sb_f(int argc, char **argv);
23static void sb_help(void);
4ca431fc
NS
24static int uuid_f(int argc, char **argv);
25static void uuid_help(void);
26static int label_f(int argc, char **argv);
27static void label_help(void);
28static int version_f(int argc, char **argv);
29static void version_help(void);
2bd0ea18
NS
30
31static const cmdinfo_t sb_cmd =
9ee7055c
AM
32 { "sb", NULL, sb_f, 0, 1, 1, N_("[agno]"),
33 N_("set current address to sb header"), sb_help };
4ca431fc 34static const cmdinfo_t uuid_cmd =
9ee7055c
AM
35 { "uuid", NULL, uuid_f, 0, 1, 1, N_("[uuid]"),
36 N_("write/print FS uuid"), uuid_help };
4ca431fc 37static const cmdinfo_t label_cmd =
9ee7055c
AM
38 { "label", NULL, label_f, 0, 1, 1, N_("[label]"),
39 N_("write/print FS label"), label_help };
4ca431fc 40static const cmdinfo_t version_cmd =
9ee7055c
AM
41 { "version", NULL, version_f, 0, -1, 1, N_("[feature | [vnum fnum]]"),
42 N_("set feature bit(s) in the sb version field"), version_help };
2bd0ea18 43
4ca431fc
NS
44void
45sb_init(void)
46{
47 add_command(&sb_cmd);
48 add_command(&uuid_cmd);
49 add_command(&label_cmd);
50 add_command(&version_cmd);
51}
2bd0ea18
NS
52
53#define OFF(f) bitize(offsetof(xfs_sb_t, sb_ ## f))
54#define SZC(f) szcount(xfs_sb_t, sb_ ## f)
55const field_t sb_flds[] = {
56 { "magicnum", FLDT_UINT32X, OI(OFF(magicnum)), C1, 0, TYP_NONE },
57 { "blocksize", FLDT_UINT32D, OI(OFF(blocksize)), C1, 0, TYP_NONE },
58 { "dblocks", FLDT_DRFSBNO, OI(OFF(dblocks)), C1, 0, TYP_NONE },
59 { "rblocks", FLDT_DRFSBNO, OI(OFF(rblocks)), C1, 0, TYP_NONE },
60 { "rextents", FLDT_DRTBNO, OI(OFF(rextents)), C1, 0, TYP_NONE },
61 { "uuid", FLDT_UUID, OI(OFF(uuid)), C1, 0, TYP_NONE },
62 { "logstart", FLDT_DFSBNO, OI(OFF(logstart)), C1, 0, TYP_LOG },
63 { "rootino", FLDT_INO, OI(OFF(rootino)), C1, 0, TYP_INODE },
64 { "rbmino", FLDT_INO, OI(OFF(rbmino)), C1, 0, TYP_INODE },
65 { "rsumino", FLDT_INO, OI(OFF(rsumino)), C1, 0, TYP_INODE },
66 { "rextsize", FLDT_AGBLOCK, OI(OFF(rextsize)), C1, 0, TYP_NONE },
67 { "agblocks", FLDT_AGBLOCK, OI(OFF(agblocks)), C1, 0, TYP_NONE },
68 { "agcount", FLDT_AGNUMBER, OI(OFF(agcount)), C1, 0, TYP_NONE },
69 { "rbmblocks", FLDT_EXTLEN, OI(OFF(rbmblocks)), C1, 0, TYP_NONE },
70 { "logblocks", FLDT_EXTLEN, OI(OFF(logblocks)), C1, 0, TYP_NONE },
71 { "versionnum", FLDT_UINT16X, OI(OFF(versionnum)), C1, 0, TYP_NONE },
72 { "sectsize", FLDT_UINT16D, OI(OFF(sectsize)), C1, 0, TYP_NONE },
73 { "inodesize", FLDT_UINT16D, OI(OFF(inodesize)), C1, 0, TYP_NONE },
74 { "inopblock", FLDT_UINT16D, OI(OFF(inopblock)), C1, 0, TYP_NONE },
75 { "fname", FLDT_CHARNS, OI(OFF(fname)), CI(SZC(fname)), 0, TYP_NONE },
76 { "blocklog", FLDT_UINT8D, OI(OFF(blocklog)), C1, 0, TYP_NONE },
77 { "sectlog", FLDT_UINT8D, OI(OFF(sectlog)), C1, 0, TYP_NONE },
78 { "inodelog", FLDT_UINT8D, OI(OFF(inodelog)), C1, 0, TYP_NONE },
79 { "inopblog", FLDT_UINT8D, OI(OFF(inopblog)), C1, 0, TYP_NONE },
80 { "agblklog", FLDT_UINT8D, OI(OFF(agblklog)), C1, 0, TYP_NONE },
81 { "rextslog", FLDT_UINT8D, OI(OFF(rextslog)), C1, 0, TYP_NONE },
82 { "inprogress", FLDT_UINT8D, OI(OFF(inprogress)), C1, 0, TYP_NONE },
83 { "imax_pct", FLDT_UINT8D, OI(OFF(imax_pct)), C1, 0, TYP_NONE },
84 { "icount", FLDT_UINT64D, OI(OFF(icount)), C1, 0, TYP_NONE },
85 { "ifree", FLDT_UINT64D, OI(OFF(ifree)), C1, 0, TYP_NONE },
86 { "fdblocks", FLDT_UINT64D, OI(OFF(fdblocks)), C1, 0, TYP_NONE },
87 { "frextents", FLDT_UINT64D, OI(OFF(frextents)), C1, 0, TYP_NONE },
88 { "uquotino", FLDT_INO, OI(OFF(uquotino)), C1, 0, TYP_INODE },
b36eef04 89 { "gquotino", FLDT_INO, OI(OFF(gquotino)), C1, 0, TYP_INODE },
2bd0ea18
NS
90 { "qflags", FLDT_UINT16X, OI(OFF(qflags)), C1, 0, TYP_NONE },
91 { "flags", FLDT_UINT8X, OI(OFF(flags)), C1, 0, TYP_NONE },
92 { "shared_vn", FLDT_UINT8D, OI(OFF(shared_vn)), C1, 0, TYP_NONE },
93 { "inoalignmt", FLDT_EXTLEN, OI(OFF(inoalignmt)), C1, 0, TYP_NONE },
94 { "unit", FLDT_UINT32D, OI(OFF(unit)), C1, 0, TYP_NONE },
95 { "width", FLDT_UINT32D, OI(OFF(width)), C1, 0, TYP_NONE },
96 { "dirblklog", FLDT_UINT8D, OI(OFF(dirblklog)), C1, 0, TYP_NONE },
9440d84d
NS
97 { "logsectlog", FLDT_UINT8D, OI(OFF(logsectlog)), C1, 0, TYP_NONE },
98 { "logsectsize", FLDT_UINT16D, OI(OFF(logsectsize)), C1, 0, TYP_NONE },
73bf5988 99 { "logsunit", FLDT_UINT32D, OI(OFF(logsunit)), C1, 0, TYP_NONE },
465e76a9 100 { "features2", FLDT_UINT32X, OI(OFF(features2)), C1, 0, TYP_NONE },
a23fa047
DC
101 { "bad_features2", FLDT_UINT32X, OI(OFF(bad_features2)),
102 C1, 0, TYP_NONE },
103 { "features_compat", FLDT_UINT32X, OI(OFF(features_compat)),
104 C1, 0, TYP_NONE },
105 { "features_ro_compat", FLDT_UINT32X, OI(OFF(features_ro_compat)),
106 C1, 0, TYP_NONE },
107 { "features_incompat", FLDT_UINT32X, OI(OFF(features_incompat)),
108 C1, 0, TYP_NONE },
109 { "features_log_incompat", FLDT_UINT32X, OI(OFF(features_log_incompat)),
110 C1, 0, TYP_NONE },
0522f1cc 111 { "crc", FLDT_CRC, OI(OFF(crc)), C1, 0, TYP_NONE },
061e316e 112 { "spino_align", FLDT_EXTLEN, OI(OFF(spino_align)), C1, 0, TYP_NONE },
a23fa047
DC
113 { "pquotino", FLDT_INO, OI(OFF(pquotino)), C1, 0, TYP_INODE },
114 { "lsn", FLDT_UINT64X, OI(OFF(lsn)), C1, 0, TYP_NONE },
9c4e12fb 115 { "meta_uuid", FLDT_UUID, OI(OFF(meta_uuid)), C1, 0, TYP_NONE },
2bd0ea18
NS
116 { NULL }
117};
118
4ca431fc
NS
119const field_t sb_hfld[] = {
120 { "", FLDT_SB, OI(0), C1, 0, TYP_NONE },
121 { NULL }
122};
123
2bd0ea18
NS
124static void
125sb_help(void)
126{
9ee7055c 127 dbprintf(_(
2bd0ea18
NS
128"\n"
129" set allocation group superblock\n"
130"\n"
131" Example:\n"
132"\n"
133" 'sb 7' - set location to 7th allocation group superblock, set type to 'sb'\n"
134"\n"
9440d84d
NS
135" Located in the first sector of each allocation group, the superblock\n"
136" contains the base information for the filesystem.\n"
2bd0ea18
NS
137" The superblock in allocation group 0 is the primary. The copies in the\n"
138" remaining allocation groups only serve as backup for filesystem recovery.\n"
139" The icount/ifree/fdblocks/frextents are only updated in superblock 0.\n"
140"\n"
9ee7055c 141));
2bd0ea18
NS
142}
143
144static int
145sb_f(
146 int argc,
147 char **argv)
148{
149 xfs_agnumber_t agno;
150 char *p;
151
152 if (argc > 1) {
153 agno = (xfs_agnumber_t)strtoul(argv[1], &p, 0);
154 if (*p != '\0' || agno >= mp->m_sb.sb_agcount) {
9ee7055c 155 dbprintf(_("bad allocation group number %s\n"), argv[1]);
2bd0ea18
NS
156 return 0;
157 }
158 cur_agno = agno;
159 } else if (cur_agno == NULLAGNUMBER)
160 cur_agno = 0;
161 ASSERT(typtab[TYP_SB].typnm == TYP_SB);
9440d84d
NS
162 set_cur(&typtab[TYP_SB],
163 XFS_AG_DADDR(mp, cur_agno, XFS_SB_DADDR),
164 XFS_FSS_TO_BB(mp, 1), DB_RING_ADD, NULL);
2bd0ea18
NS
165 return 0;
166}
167
2bd0ea18
NS
168/*ARGSUSED*/
169int
170sb_size(
171 void *obj,
172 int startoff,
173 int idx)
174{
175 return bitize(mp->m_sb.sb_sectsize);
176}
4ca431fc
NS
177
178static int
179get_sb(xfs_agnumber_t agno, xfs_sb_t *sb)
180{
181 push_cur();
182 set_cur(&typtab[TYP_SB],
183 XFS_AG_DADDR(mp, agno, XFS_SB_DADDR),
184 XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL);
dfc130f3 185
4ca431fc 186 if (!iocur_top->data) {
9ee7055c 187 dbprintf(_("can't read superblock for AG %u\n"), agno);
4ca431fc
NS
188 pop_cur();
189 return 0;
190 }
191
5e656dbb 192 libxfs_sb_from_disk(sb, iocur_top->data);
dfc130f3 193
4ca431fc 194 if (sb->sb_magicnum != XFS_SB_MAGIC) {
9ee7055c 195 dbprintf(_("bad sb magic # %#x in AG %u\n"),
4ca431fc 196 sb->sb_magicnum, agno);
dfc130f3 197 return 0;
4ca431fc 198 }
5e656dbb 199 if (!xfs_sb_good_version(sb)) {
9ee7055c 200 dbprintf(_("bad sb version # %#x in AG %u\n"),
4ca431fc 201 sb->sb_versionnum, agno);
dfc130f3 202 return 0;
4ca431fc
NS
203 }
204 if (agno == 0 && sb->sb_inprogress != 0) {
9ee7055c 205 dbprintf(_("mkfs not completed successfully\n"));
dfc130f3 206 return 0;
4ca431fc
NS
207 }
208 return 1;
209}
210
211/* workaround craziness in the xlog routines */
19879397 212int xlog_recover_do_trans(struct xlog *log, struct xlog_recover *t, int p)
999f0b9c
DC
213{
214 return 0;
215}
4ca431fc 216
add013da
NS
217int
218sb_logcheck(void)
4ca431fc 219{
7ac353a9 220 int dirty;
4ca431fc
NS
221
222 if (mp->m_sb.sb_logstart) {
fc83c757 223 if (x.log.dev && x.log.dev != x.data.dev) {
9ee7055c
AM
224 dbprintf(_("aborting - external log specified for FS "
225 "with an internal log\n"));
4ca431fc
NS
226 return 0;
227 }
228 } else {
fc83c757 229 if (!x.log.dev || (x.log.dev == x.data.dev)) {
9ee7055c
AM
230 dbprintf(_("aborting - no external log specified for FS "
231 "with an external log\n"));
4ca431fc
NS
232 return 0;
233 }
234 }
235
ca8cc76e 236 libxfs_buftarg_init(mp, &x);
999f0b9c 237
c42edb2e 238 dirty = xlog_is_dirty(mp, mp->m_log);
7ac353a9 239 if (dirty == -1) {
9ee7055c 240 dbprintf(_("ERROR: cannot find log head/tail, run xfs_repair\n"));
4ca431fc 241 return 0;
7ac353a9 242 } else if (dirty == 1) {
9ee7055c 243 dbprintf(_(
4ca431fc
NS
244"ERROR: The filesystem has valuable metadata changes in a log which needs to\n"
245"be replayed. Mount the filesystem to replay the log, and unmount it before\n"
246"re-running %s. If you are unable to mount the filesystem, then use\n"
247"the xfs_repair -L option to destroy the log and attempt a repair.\n"
248"Note that destroying the log may cause corruption -- please attempt a mount\n"
9ee7055c 249"of the filesystem before doing this.\n"), progname);
4ca431fc
NS
250 return 0;
251 }
7ac353a9 252 /* Log is clean */
add013da
NS
253 return 1;
254}
255
256static int
257sb_logzero(uuid_t *uuidp)
258{
7f725646
BF
259 int cycle = XLOG_INIT_CYCLE;
260 int error;
261
add013da
NS
262 if (!sb_logcheck())
263 return 0;
4ca431fc 264
7f725646
BF
265 /*
266 * The log must always move forward on v5 superblocks. Bump it to the
267 * next cycle.
268 */
2660e653 269 if (xfs_has_crc(mp))
7f725646
BF
270 cycle = mp->m_log->l_curr_cycle + 1;
271
9ee7055c 272 dbprintf(_("Clearing log and setting UUID\n"));
4ca431fc 273
1c12a814 274 error = libxfs_log_clear(mp->m_logdev_targp, NULL,
4ca431fc
NS
275 XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart),
276 (xfs_extlen_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks),
277 uuidp,
2660e653 278 xfs_has_logv2(mp) ? 2 : 1,
571a78a7 279 mp->m_sb.sb_logsunit, XLOG_FMT, cycle, true);
7f725646 280 if (error) {
9ee7055c 281 dbprintf(_("ERROR: cannot clear the log\n"));
4ca431fc
NS
282 return 0;
283 }
7f725646 284
4ca431fc
NS
285 return 1;
286}
287
288
289static void
290uuid_help(void)
291{
9ee7055c 292 dbprintf(_(
4ca431fc
NS
293"\n"
294" write/print FS uuid\n"
295"\n"
296" Example:\n"
297"\n"
298" 'uuid' - print UUID\n"
299" 'uuid 01234567-0123-0123-0123-0123456789ab' - write UUID\n"
300" 'uuid generate' - generate and write\n"
301" 'uuid rewrite' - copy UUID from SB 0\n"
302"\n"
303"The print function checks the UUID in each SB and will warn if the UUIDs\n"
304"differ between AGs (the log is not checked). The write commands will\n"
305"set the uuid in all AGs to either a specified value, a newly generated\n"
306"value or the value found in the first superblock (SB 0) respectively.\n"
307"As a side effect of writing the UUID, the log is cleared (which is fine\n"
308"on a CLEANLY unmounted FS).\n"
309"\n"
9ee7055c 310));
4ca431fc
NS
311}
312
313static uuid_t *
314do_uuid(xfs_agnumber_t agno, uuid_t *uuid)
315{
316 xfs_sb_t tsb;
317 static uuid_t uu;
318
319 if (!get_sb(agno, &tsb))
320 return NULL;
321
322 if (!uuid) { /* get uuid */
323 memcpy(&uu, &tsb.sb_uuid, sizeof(uuid_t));
324 pop_cur();
325 return &uu;
326 }
327 /* set uuid */
9c4e12fb
ES
328 if (!xfs_sb_version_hascrc(&tsb))
329 goto write;
330 /*
331 * If we have CRCs, and this UUID differs from that stamped in the
332 * metadata, set the incompat flag and copy the old one to the
333 * metadata-specific location.
334 *
335 * If we are setting the user-visible UUID back to match the metadata
336 * UUID, clear the metadata-specific location and the incompat flag.
337 */
338 if (!xfs_sb_version_hasmetauuid(&tsb) &&
339 !uuid_equal(uuid, &mp->m_sb.sb_meta_uuid)) {
340 mp->m_sb.sb_features_incompat |= XFS_SB_FEAT_INCOMPAT_META_UUID;
341 tsb.sb_features_incompat |= XFS_SB_FEAT_INCOMPAT_META_UUID;
342 memcpy(&tsb.sb_meta_uuid, &tsb.sb_uuid, sizeof(uuid_t));
343 } else if (xfs_sb_version_hasmetauuid(&tsb) &&
344 uuid_equal(uuid, &mp->m_sb.sb_meta_uuid)) {
345 memset(&tsb.sb_meta_uuid, 0, sizeof(uuid_t));
346 /* Write those zeros now; it's ignored once we clear the flag */
347 libxfs_sb_to_disk(iocur_top->data, &tsb);
348 mp->m_sb.sb_features_incompat &=
349 ~XFS_SB_FEAT_INCOMPAT_META_UUID;
350 tsb.sb_features_incompat &= ~XFS_SB_FEAT_INCOMPAT_META_UUID;
351 }
352
353write:
4ca431fc 354 memcpy(&tsb.sb_uuid, uuid, sizeof(uuid_t));
19ebedcf 355 libxfs_sb_to_disk(iocur_top->data, &tsb);
4ca431fc
NS
356 write_cur();
357 return uuid;
358}
359
360static int
361uuid_f(
362 int argc,
363 char **argv)
364{
365 char bp[40];
366 xfs_agnumber_t agno;
367 uuid_t uu;
368 uuid_t *uup = NULL;
369
370 if (argc != 1 && argc != 2) {
9ee7055c 371 dbprintf(_("invalid parameters\n"));
4ca431fc
NS
372 return 0;
373 }
374
375 if (argc == 2) { /* WRITE UUID */
376
23d88955 377 if ((x.flags & LIBXFS_ISREADONLY) || !expert_mode) {
9ee7055c 378 dbprintf(_("%s: not in expert mode, writing disabled\n"),
4ca431fc
NS
379 progname);
380 return 0;
381 }
b95b770f
DW
382 if (xfs_sb_version_needsrepair(&mp->m_sb)) {
383 dbprintf(_("%s: filesystem needs xfs_repair\n"),
384 progname);
385 return 0;
386 }
4ca431fc
NS
387
388 if (!strcasecmp(argv[1], "generate")) {
4d32d744 389 platform_uuid_generate(&uu);
4ca431fc 390 } else if (!strcasecmp(argv[1], "nil")) {
4d32d744 391 platform_uuid_clear(&uu);
4ca431fc
NS
392 } else if (!strcasecmp(argv[1], "rewrite")) {
393 uup = do_uuid(0, NULL);
394 if (!uup) {
9ee7055c 395 dbprintf(_("failed to read UUID from AG 0\n"));
4ca431fc
NS
396 return 0;
397 }
6699422d 398 memcpy(&uu, uup, sizeof(uuid_t));
4d32d744 399 platform_uuid_unparse(&uu, bp);
9ee7055c 400 dbprintf(_("old UUID = %s\n"), bp);
9c4e12fb
ES
401 } else if (!strcasecmp(argv[1], "restore")) {
402 xfs_sb_t tsb;
403
404 if (!get_sb(0, &tsb))
405 return 0;
406
407 /* Not set; nothing to do. Success! */
408 if (!xfs_sb_version_hasmetauuid(&tsb))
409 return 0;
f8149110 410
9c4e12fb 411 memcpy(&uu, mp->m_sb.sb_meta_uuid, sizeof(uuid_t));
4ca431fc 412 } else {
4d32d744 413 if (platform_uuid_parse(argv[1], &uu)) {
9ee7055c 414 dbprintf(_("invalid UUID\n"));
4ca431fc
NS
415 return 0;
416 }
417 }
418
ff1f79a7 419 /* clear the log (setting uuid) if it's not dirty */
add013da 420 if (!sb_logzero(&uu))
4ca431fc
NS
421 return 0;
422
9ee7055c 423 dbprintf(_("writing all SBs\n"));
4ca431fc
NS
424 for (agno = 0; agno < mp->m_sb.sb_agcount; agno++)
425 if (!do_uuid(agno, &uu)) {
9ee7055c 426 dbprintf(_("failed to set UUID in AG %d\n"), agno);
4ca431fc
NS
427 break;
428 }
429
4d32d744 430 platform_uuid_unparse(&uu, bp);
9ee7055c 431 dbprintf(_("new UUID = %s\n"), bp);
4ca431fc
NS
432 return 0;
433
434 } else { /* READ+CHECK UUID */
dfc130f3 435
4ca431fc
NS
436 for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
437 uup = do_uuid(agno, NULL);
438 if (!uup) {
9ee7055c 439 dbprintf(_("failed to read UUID from AG %d\n"),
4ca431fc
NS
440 agno);
441 return 0;
442 }
443 if (agno) {
444 if (memcmp(&uu, uup, sizeof(uuid_t))) {
9ee7055c
AM
445 dbprintf(_("warning: UUID in AG %d "
446 "differs to the primary SB\n"),
4ca431fc
NS
447 agno);
448 break;
449 }
450 } else {
6699422d 451 memcpy(&uu, uup, sizeof(uuid_t));
4ca431fc
NS
452 }
453 }
454 if (mp->m_sb.sb_logstart) {
fc83c757 455 if (x.log.dev && x.log.dev != x.data.dev)
9ee7055c
AM
456 dbprintf(_("warning - external log specified "
457 "for FS with an internal log\n"));
fc83c757 458 } else if (!x.log.dev || (x.log.dev == x.data.dev)) {
9ee7055c
AM
459 dbprintf(_("warning - no external log specified "
460 "for FS with an external log\n"));
4ca431fc
NS
461 }
462
4d32d744 463 platform_uuid_unparse(&uu, bp);
9ee7055c 464 dbprintf(_("UUID = %s\n"), bp);
4ca431fc
NS
465 }
466
467 return 0;
468}
469
470
471static void
472label_help(void)
473{
9ee7055c 474 dbprintf(_(
4ca431fc
NS
475"\n"
476" write/print FS label\n"
477"\n"
478" Example:\n"
479"\n"
480" 'label' - print label\n"
481" 'label 123456789012' - write label\n"
482" 'label --' - write an empty label\n"
483"\n"
484"The print function checks the label in each SB and will warn if the labels\n"
485"differ between AGs. The write commands will set the label in all AGs to the\n"
486"specified value. The maximum length of a label is 12 characters - use of a\n"
487"longer label will result in truncation and a warning will be issued.\n"
488"\n"
9ee7055c 489));
4ca431fc
NS
490}
491
492static char *
493do_label(xfs_agnumber_t agno, char *label)
494{
495 size_t len;
496 xfs_sb_t tsb;
dfc130f3 497 static char lbl[sizeof(tsb.sb_fname) + 1];
4ca431fc
NS
498
499 if (!get_sb(agno, &tsb))
500 return NULL;
501
502 memset(&lbl[0], 0, sizeof(lbl));
503
504 if (!label) { /* get label */
505 pop_cur();
506 memcpy(&lbl[0], &tsb.sb_fname, sizeof(tsb.sb_fname));
507 return &lbl[0];
508 }
509 /* set label */
510 if ((len = strlen(label)) > sizeof(tsb.sb_fname)) {
511 if (agno == 0)
9ee7055c 512 dbprintf(_("%s: truncating label length from %d to %d\n"),
4ca431fc
NS
513 progname, (int)len, (int)sizeof(tsb.sb_fname));
514 len = sizeof(tsb.sb_fname);
515 }
516 if ( len == 2 &&
517 (strcmp(label, "\"\"") == 0 ||
518 strcmp(label, "''") == 0 ||
519 strcmp(label, "--") == 0) )
520 label[0] = label[1] = '\0';
521 memset(&tsb.sb_fname, 0, sizeof(tsb.sb_fname));
522 memcpy(&tsb.sb_fname, label, len);
523 memcpy(&lbl[0], &tsb.sb_fname, sizeof(tsb.sb_fname));
19ebedcf 524 libxfs_sb_to_disk(iocur_top->data, &tsb);
4ca431fc
NS
525 write_cur();
526 return &lbl[0];
527}
528
529static int
530label_f(
531 int argc,
532 char **argv)
533{
534 char *p = NULL;
535 xfs_sb_t sb;
536 xfs_agnumber_t ag;
537
538 if (argc != 1 && argc != 2) {
9ee7055c 539 dbprintf(_("invalid parameters\n"));
4ca431fc
NS
540 return 0;
541 }
542
543 if (argc == 2) { /* WRITE LABEL */
544
23d88955 545 if ((x.flags & LIBXFS_ISREADONLY) || !expert_mode) {
9ee7055c 546 dbprintf(_("%s: not in expert mode, writing disabled\n"),
4ca431fc
NS
547 progname);
548 return 0;
549 }
550
b95b770f
DW
551 if (xfs_sb_version_needsrepair(&mp->m_sb)) {
552 dbprintf(_("%s: filesystem needs xfs_repair\n"),
553 progname);
554 return 0;
555 }
556
9ee7055c 557 dbprintf(_("writing all SBs\n"));
4ca431fc
NS
558 for (ag = 0; ag < mp->m_sb.sb_agcount; ag++)
559 if ((p = do_label(ag, argv[1])) == NULL) {
9ee7055c 560 dbprintf(_("failed to set label in AG %d\n"), ag);
4ca431fc
NS
561 break;
562 }
9ee7055c 563 dbprintf(_("new label = \"%s\"\n"), p);
4ca431fc
NS
564
565 } else { /* READ LABEL */
566
567 for (ag = 0; ag < mp->m_sb.sb_agcount; ag++) {
568 p = do_label(ag, NULL);
569 if (!p) {
9ee7055c 570 dbprintf(_("failed to read label in AG %d\n"), ag);
4ca431fc
NS
571 return 0;
572 }
573 if (!ag)
574 memcpy(&sb.sb_fname, p, sizeof(sb.sb_fname));
575 else if (memcmp(&sb.sb_fname, p, sizeof(sb.sb_fname)))
9ee7055c 576 dbprintf(_("warning: AG %d label differs\n"), ag);
4ca431fc 577 }
9ee7055c 578 dbprintf(_("label = \"%s\"\n"), p);
4ca431fc
NS
579 }
580 return 0;
581}
582
583
584static void
585version_help(void)
586{
9ee7055c 587 dbprintf(_(
4ca431fc
NS
588"\n"
589" set/print feature bits in sb version\n"
590"\n"
591" Example:\n"
592"\n"
593" 'version' - print current feature bits\n"
594" 'version extflg' - enable unwritten extents\n"
70476e54
NS
595" 'version attr1' - enable v1 inline extended attributes\n"
596" 'version attr2' - enable v2 inline extended attributes\n"
66997473 597" 'version log2' - enable v2 log format\n"
4ca431fc
NS
598"\n"
599"The version function prints currently enabled features for a filesystem\n"
ff1f79a7 600"according to the version field of its primary superblock.\n"
4ca431fc 601"It can also be used to enable selected features, such as support for\n"
ff1f79a7 602"unwritten extents. The updated version is written into all AGs.\n"
4ca431fc 603"\n"
9ee7055c 604));
4ca431fc
NS
605}
606
607static int
14f8b681 608do_version(xfs_agnumber_t agno, uint16_t version, uint32_t features)
4ca431fc
NS
609{
610 xfs_sb_t tsb;
611
612 if (!get_sb(agno, &tsb))
613 return 0;
614
72f11257
ES
615 if (xfs_sb_has_mismatched_features2(&tsb)) {
616 dbprintf(_("Superblock has mismatched features2 fields, "
617 "skipping modification\n"));
618 return 0;
619 }
620
66997473 621 if ((version & XFS_SB_VERSION_LOGV2BIT) &&
5e656dbb 622 !xfs_sb_version_haslogv2(&tsb)) {
66997473 623 tsb.sb_logsunit = 1;
66997473
NS
624 }
625
70476e54
NS
626 tsb.sb_versionnum = version;
627 tsb.sb_features2 = features;
72f11257 628 tsb.sb_bad_features2 = features;
19ebedcf 629 libxfs_sb_to_disk(iocur_top->data, &tsb);
4ca431fc
NS
630 write_cur();
631 return 1;
632}
633
634static char *
635version_string(
575f24e5 636 struct xfs_mount *mp)
4ca431fc 637{
575f24e5 638 static char s[1024];
4ca431fc 639
575f24e5 640 if (XFS_SB_VERSION_NUM(&mp->m_sb) == XFS_SB_VERSION_1)
4ca431fc 641 strcpy(s, "V1");
575f24e5 642 else if (XFS_SB_VERSION_NUM(&mp->m_sb) == XFS_SB_VERSION_2)
4ca431fc 643 strcpy(s, "V2");
575f24e5 644 else if (XFS_SB_VERSION_NUM(&mp->m_sb) == XFS_SB_VERSION_3)
4ca431fc 645 strcpy(s, "V3");
575f24e5 646 else if (XFS_SB_VERSION_NUM(&mp->m_sb) == XFS_SB_VERSION_4)
4ca431fc 647 strcpy(s, "V4");
575f24e5 648 else if (XFS_SB_VERSION_NUM(&mp->m_sb) == XFS_SB_VERSION_5)
a23fa047 649 strcpy(s, "V5");
4ca431fc 650
5f6f3660
DC
651 /*
652 * We assume the state of these features now, so macros don't exist for
653 * them any more.
654 */
2660e653 655 if (xfs_has_nlink(mp))
5f6f3660 656 strcat(s, ",NLINK");
575f24e5 657 if (mp->m_sb.sb_versionnum & XFS_SB_VERSION_SHAREDBIT)
5f6f3660 658 strcat(s, ",SHARED");
575f24e5 659 if (mp->m_sb.sb_versionnum & XFS_SB_VERSION_DIRV2BIT)
5f6f3660
DC
660 strcat(s, ",DIRV2");
661
2660e653 662 if (xfs_has_attr(mp))
4ca431fc 663 strcat(s, ",ATTR");
2660e653 664 if (xfs_has_quota(mp))
4ca431fc 665 strcat(s, ",QUOTA");
2660e653 666 if (xfs_has_align(mp))
4ca431fc 667 strcat(s, ",ALIGN");
2660e653 668 if (xfs_has_dalign(mp))
4ca431fc 669 strcat(s, ",DALIGN");
2660e653 670 if (xfs_has_logv2(mp))
4ca431fc 671 strcat(s, ",LOGV2");
b7fdeb4d 672 /* This feature is required now as well */
2660e653 673 if (xfs_has_extflg(mp))
4ca431fc 674 strcat(s, ",EXTFLG");
2660e653 675 if (xfs_has_sector(mp))
4ca431fc 676 strcat(s, ",SECTOR");
2660e653 677 if (xfs_has_asciici(mp))
51ca7008 678 strcat(s, ",ASCII_CI");
2660e653 679 if (mp->m_sb.sb_versionnum & XFS_SB_VERSION_MOREBITSBIT)
ca86e759 680 strcat(s, ",MOREBITS");
2660e653 681 if (xfs_has_attr2(mp))
ca86e759 682 strcat(s, ",ATTR2");
2660e653 683 if (xfs_has_lazysbcount(mp))
cdded3d8 684 strcat(s, ",LAZYSBCOUNT");
2660e653 685 if (xfs_has_projid32(mp))
22bc10ed 686 strcat(s, ",PROJID32BIT");
2660e653 687 if (xfs_has_crc(mp))
a23fa047 688 strcat(s, ",CRC");
2660e653 689 if (xfs_has_ftype(mp))
42737f1a 690 strcat(s, ",FTYPE");
2660e653 691 if (xfs_has_finobt(mp))
b7fc3b36 692 strcat(s, ",FINOBT");
2660e653 693 if (xfs_has_sparseinodes(mp))
b8db0171 694 strcat(s, ",SPARSE_INODES");
2660e653 695 if (xfs_has_metauuid(mp))
9c4e12fb 696 strcat(s, ",META_UUID");
2660e653 697 if (xfs_has_rmapbt(mp))
f810b1bc 698 strcat(s, ",RMAPBT");
2660e653 699 if (xfs_has_reflink(mp))
9fb2cb27 700 strcat(s, ",REFLINK");
2660e653 701 if (xfs_has_inobtcounts(mp))
13b89172 702 strcat(s, ",INOBTCNT");
2660e653 703 if (xfs_has_bigtime(mp))
344f38a9 704 strcat(s, ",BIGTIME");
2660e653 705 if (xfs_has_needsrepair(mp))
67b8ca98 706 strcat(s, ",NEEDSREPAIR");
d7eb8fbd
CB
707 if (xfs_has_large_extent_counts(mp))
708 strcat(s, ",NREXT64");
4ca431fc
NS
709 return s;
710}
711
a23fa047
DC
712/*
713 * XXX: this only supports reading and writing to version 4 superblock fields.
714 * V5 superblocks always define certain V4 feature bits - they are blocked from
715 * being changed if a V5 sb is detected, but otherwise v5 superblock features
716 * are not handled here.
717 */
4ca431fc
NS
718static int
719version_f(
720 int argc,
721 char **argv)
722{
14f8b681
DW
723 uint16_t version = 0;
724 uint32_t features = 0;
3bc1fdd4 725 unsigned long old_mfeatures = 0;
4ca431fc
NS
726 xfs_agnumber_t ag;
727
728 if (argc == 2) { /* WRITE VERSION */
729
23d88955 730 if ((x.flags & LIBXFS_ISREADONLY) || !expert_mode) {
9ee7055c 731 dbprintf(_("%s: not in expert mode, writing disabled\n"),
4ca431fc
NS
732 progname);
733 return 0;
734 }
735
736 /* Logic here derived from the IRIX xfs_chver(1M) script. */
737 if (!strcasecmp(argv[1], "extflg")) {
738 switch (XFS_SB_VERSION_NUM(&mp->m_sb)) {
739 case XFS_SB_VERSION_1:
740 version = 0x0004 | XFS_SB_VERSION_EXTFLGBIT;
741 break;
742 case XFS_SB_VERSION_2:
743 version = 0x0014 | XFS_SB_VERSION_EXTFLGBIT;
744 break;
745 case XFS_SB_VERSION_3:
746 version = 0x0034 | XFS_SB_VERSION_EXTFLGBIT;
747 break;
748 case XFS_SB_VERSION_4:
b7fdeb4d
CH
749 if (mp->m_sb.sb_versionnum &
750 XFS_SB_VERSION_EXTFLGBIT)
a23fa047
DC
751 dbprintf(
752 _("unwritten extents flag is already enabled\n"));
4ca431fc
NS
753 else
754 version = mp->m_sb.sb_versionnum |
755 XFS_SB_VERSION_EXTFLGBIT;
756 break;
a23fa047
DC
757 case XFS_SB_VERSION_5:
758 dbprintf(
759 _("unwritten extents always enabled for v5 superblocks.\n"));
760 break;
4ca431fc 761 }
66997473
NS
762 } else if (!strcasecmp(argv[1], "log2")) {
763 switch (XFS_SB_VERSION_NUM(&mp->m_sb)) {
764 case XFS_SB_VERSION_1:
765 version = 0x0004 | XFS_SB_VERSION_LOGV2BIT;
766 break;
767 case XFS_SB_VERSION_2:
768 version = 0x0014 | XFS_SB_VERSION_LOGV2BIT;
769 break;
770 case XFS_SB_VERSION_3:
771 version = 0x0034 | XFS_SB_VERSION_LOGV2BIT;
772 break;
773 case XFS_SB_VERSION_4:
2660e653 774 if (xfs_has_logv2(mp))
a23fa047
DC
775 dbprintf(
776 _("version 2 log format is already in use\n"));
66997473
NS
777 else
778 version = mp->m_sb.sb_versionnum |
779 XFS_SB_VERSION_LOGV2BIT;
780 break;
a23fa047
DC
781 case XFS_SB_VERSION_5:
782 dbprintf(
783 _("Version 2 logs always enabled for v5 superblocks.\n"));
784 break;
66997473 785 }
a23fa047
DC
786 } else if (XFS_SB_VERSION_NUM(&mp->m_sb) == XFS_SB_VERSION_5) {
787 dbprintf(
788 _("%s: Cannot change %s on v5 superblocks.\n"),
789 progname, argv[1]);
790 return 0;
70476e54 791 } else if (!strcasecmp(argv[1], "attr1")) {
a23fa047 792
2660e653 793 if (xfs_has_attr2(mp)) {
70476e54
NS
794 if (!(mp->m_sb.sb_features2 &=
795 ~XFS_SB_VERSION2_ATTR2BIT))
796 mp->m_sb.sb_versionnum &=
797 ~XFS_SB_VERSION_MOREBITSBIT;
798 }
5e656dbb 799 xfs_sb_version_addattr(&mp->m_sb);
70476e54
NS
800 version = mp->m_sb.sb_versionnum;
801 features = mp->m_sb.sb_features2;
802 } else if (!strcasecmp(argv[1], "attr2")) {
5e656dbb
BN
803 xfs_sb_version_addattr(&mp->m_sb);
804 xfs_sb_version_addattr2(&mp->m_sb);
22bc10ed
AM
805 version = mp->m_sb.sb_versionnum;
806 features = mp->m_sb.sb_features2;
807 } else if (!strcasecmp(argv[1], "projid32bit")) {
3bc1fdd4 808 xfs_sb_version_addprojid32(&mp->m_sb);
70476e54
NS
809 version = mp->m_sb.sb_versionnum;
810 features = mp->m_sb.sb_features2;
4ca431fc 811 } else {
9ee7055c 812 dbprintf(_("%s: invalid version change command \"%s\"\n"),
4ca431fc
NS
813 progname, argv[1]);
814 return 0;
815 }
816
817 if (version) {
9ee7055c 818 dbprintf(_("writing all SBs\n"));
4ca431fc 819 for (ag = 0; ag < mp->m_sb.sb_agcount; ag++)
70476e54 820 if (!do_version(ag, version, features)) {
9ee7055c
AM
821 dbprintf(_("failed to set versionnum "
822 "in AG %d\n"), ag);
4ca431fc
NS
823 break;
824 }
825 mp->m_sb.sb_versionnum = version;
70476e54 826 mp->m_sb.sb_features2 = features;
3bc1fdd4
DC
827 mp->m_features &= ~XFS_FEAT_ATTR2;
828 mp->m_features |= libxfs_sb_version_to_features(&mp->m_sb);
4ca431fc
NS
829 }
830 }
d2df702b
NS
831
832 if (argc == 3) { /* VERSIONNUM + FEATURES2 */
833 char *sp;
834
835 version = mp->m_sb.sb_versionnum;
836 features = mp->m_sb.sb_features2;
837 mp->m_sb.sb_versionnum = strtoul(argv[1], &sp, 0);
838 mp->m_sb.sb_features2 = strtoul(argv[2], &sp, 0);
3bc1fdd4
DC
839 old_mfeatures = mp->m_features;
840 mp->m_features = libxfs_sb_version_to_features(&mp->m_sb);
d2df702b
NS
841 }
842
9ee7055c 843 dbprintf(_("versionnum [0x%x+0x%x] = %s\n"), mp->m_sb.sb_versionnum,
575f24e5 844 mp->m_sb.sb_features2, version_string(mp));
d2df702b
NS
845
846 if (argc == 3) { /* now reset... */
847 mp->m_sb.sb_versionnum = version;
848 mp->m_sb.sb_features2 = features;
3bc1fdd4 849 mp->m_features = old_mfeatures;
d2df702b
NS
850 return 0;
851 }
852
4ca431fc
NS
853 return 0;
854}