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