]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - db/sb.c
xfs: remove suport for filesystems without unwritten extent flag
[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 */
999f0b9c
DC
212int xlog_recover_do_trans(struct xlog *log, xlog_recover_t *t, int p)
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) {
223 if (x.logdev && x.logdev != x.ddev) {
9ee7055c
AM
224 dbprintf(_("aborting - external log specified for FS "
225 "with an internal log\n"));
4ca431fc
NS
226 return 0;
227 }
228 } else {
229 if (!x.logdev || (x.logdev == x.ddev)) {
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
75c8b434 236 libxfs_buftarg_init(mp, x.ddev, x.logdev, x.rtdev);
999f0b9c 237
7f725646 238 dirty = xlog_is_dirty(mp, mp->m_log, &x, 0);
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 */
269 if (xfs_sb_version_hascrc(&mp->m_sb))
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,
5e656dbb 278 xfs_sb_version_haslogv2(&mp->m_sb) ? 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
377 if ((x.isreadonly & LIBXFS_ISREADONLY) || !expert_mode) {
9ee7055c 378 dbprintf(_("%s: not in expert mode, writing disabled\n"),
4ca431fc
NS
379 progname);
380 return 0;
381 }
382
383 if (!strcasecmp(argv[1], "generate")) {
4d32d744 384 platform_uuid_generate(&uu);
4ca431fc 385 } else if (!strcasecmp(argv[1], "nil")) {
4d32d744 386 platform_uuid_clear(&uu);
4ca431fc
NS
387 } else if (!strcasecmp(argv[1], "rewrite")) {
388 uup = do_uuid(0, NULL);
389 if (!uup) {
9ee7055c 390 dbprintf(_("failed to read UUID from AG 0\n"));
4ca431fc
NS
391 return 0;
392 }
6699422d 393 memcpy(&uu, uup, sizeof(uuid_t));
4d32d744 394 platform_uuid_unparse(&uu, bp);
9ee7055c 395 dbprintf(_("old UUID = %s\n"), bp);
9c4e12fb
ES
396 } else if (!strcasecmp(argv[1], "restore")) {
397 xfs_sb_t tsb;
398
399 if (!get_sb(0, &tsb))
400 return 0;
401
402 /* Not set; nothing to do. Success! */
403 if (!xfs_sb_version_hasmetauuid(&tsb))
404 return 0;
f8149110 405
9c4e12fb 406 memcpy(&uu, mp->m_sb.sb_meta_uuid, sizeof(uuid_t));
4ca431fc 407 } else {
4d32d744 408 if (platform_uuid_parse(argv[1], &uu)) {
9ee7055c 409 dbprintf(_("invalid UUID\n"));
4ca431fc
NS
410 return 0;
411 }
412 }
413
ff1f79a7 414 /* clear the log (setting uuid) if it's not dirty */
add013da 415 if (!sb_logzero(&uu))
4ca431fc
NS
416 return 0;
417
9ee7055c 418 dbprintf(_("writing all SBs\n"));
4ca431fc
NS
419 for (agno = 0; agno < mp->m_sb.sb_agcount; agno++)
420 if (!do_uuid(agno, &uu)) {
9ee7055c 421 dbprintf(_("failed to set UUID in AG %d\n"), agno);
4ca431fc
NS
422 break;
423 }
424
4d32d744 425 platform_uuid_unparse(&uu, bp);
9ee7055c 426 dbprintf(_("new UUID = %s\n"), bp);
4ca431fc
NS
427 return 0;
428
429 } else { /* READ+CHECK UUID */
dfc130f3 430
4ca431fc
NS
431 for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
432 uup = do_uuid(agno, NULL);
433 if (!uup) {
9ee7055c 434 dbprintf(_("failed to read UUID from AG %d\n"),
4ca431fc
NS
435 agno);
436 return 0;
437 }
438 if (agno) {
439 if (memcmp(&uu, uup, sizeof(uuid_t))) {
9ee7055c
AM
440 dbprintf(_("warning: UUID in AG %d "
441 "differs to the primary SB\n"),
4ca431fc
NS
442 agno);
443 break;
444 }
445 } else {
6699422d 446 memcpy(&uu, uup, sizeof(uuid_t));
4ca431fc
NS
447 }
448 }
449 if (mp->m_sb.sb_logstart) {
450 if (x.logdev && x.logdev != x.ddev)
9ee7055c
AM
451 dbprintf(_("warning - external log specified "
452 "for FS with an internal log\n"));
4ca431fc 453 } else if (!x.logdev || (x.logdev == x.ddev)) {
9ee7055c
AM
454 dbprintf(_("warning - no external log specified "
455 "for FS with an external log\n"));
4ca431fc
NS
456 }
457
4d32d744 458 platform_uuid_unparse(&uu, bp);
9ee7055c 459 dbprintf(_("UUID = %s\n"), bp);
4ca431fc
NS
460 }
461
462 return 0;
463}
464
465
466static void
467label_help(void)
468{
9ee7055c 469 dbprintf(_(
4ca431fc
NS
470"\n"
471" write/print FS label\n"
472"\n"
473" Example:\n"
474"\n"
475" 'label' - print label\n"
476" 'label 123456789012' - write label\n"
477" 'label --' - write an empty label\n"
478"\n"
479"The print function checks the label in each SB and will warn if the labels\n"
480"differ between AGs. The write commands will set the label in all AGs to the\n"
481"specified value. The maximum length of a label is 12 characters - use of a\n"
482"longer label will result in truncation and a warning will be issued.\n"
483"\n"
9ee7055c 484));
4ca431fc
NS
485}
486
487static char *
488do_label(xfs_agnumber_t agno, char *label)
489{
490 size_t len;
491 xfs_sb_t tsb;
dfc130f3 492 static char lbl[sizeof(tsb.sb_fname) + 1];
4ca431fc
NS
493
494 if (!get_sb(agno, &tsb))
495 return NULL;
496
497 memset(&lbl[0], 0, sizeof(lbl));
498
499 if (!label) { /* get label */
500 pop_cur();
501 memcpy(&lbl[0], &tsb.sb_fname, sizeof(tsb.sb_fname));
502 return &lbl[0];
503 }
504 /* set label */
505 if ((len = strlen(label)) > sizeof(tsb.sb_fname)) {
506 if (agno == 0)
9ee7055c 507 dbprintf(_("%s: truncating label length from %d to %d\n"),
4ca431fc
NS
508 progname, (int)len, (int)sizeof(tsb.sb_fname));
509 len = sizeof(tsb.sb_fname);
510 }
511 if ( len == 2 &&
512 (strcmp(label, "\"\"") == 0 ||
513 strcmp(label, "''") == 0 ||
514 strcmp(label, "--") == 0) )
515 label[0] = label[1] = '\0';
516 memset(&tsb.sb_fname, 0, sizeof(tsb.sb_fname));
517 memcpy(&tsb.sb_fname, label, len);
518 memcpy(&lbl[0], &tsb.sb_fname, sizeof(tsb.sb_fname));
19ebedcf 519 libxfs_sb_to_disk(iocur_top->data, &tsb);
4ca431fc
NS
520 write_cur();
521 return &lbl[0];
522}
523
524static int
525label_f(
526 int argc,
527 char **argv)
528{
529 char *p = NULL;
530 xfs_sb_t sb;
531 xfs_agnumber_t ag;
532
533 if (argc != 1 && argc != 2) {
9ee7055c 534 dbprintf(_("invalid parameters\n"));
4ca431fc
NS
535 return 0;
536 }
537
538 if (argc == 2) { /* WRITE LABEL */
539
540 if ((x.isreadonly & LIBXFS_ISREADONLY) || !expert_mode) {
9ee7055c 541 dbprintf(_("%s: not in expert mode, writing disabled\n"),
4ca431fc
NS
542 progname);
543 return 0;
544 }
545
9ee7055c 546 dbprintf(_("writing all SBs\n"));
4ca431fc
NS
547 for (ag = 0; ag < mp->m_sb.sb_agcount; ag++)
548 if ((p = do_label(ag, argv[1])) == NULL) {
9ee7055c 549 dbprintf(_("failed to set label in AG %d\n"), ag);
4ca431fc
NS
550 break;
551 }
9ee7055c 552 dbprintf(_("new label = \"%s\"\n"), p);
4ca431fc
NS
553
554 } else { /* READ LABEL */
555
556 for (ag = 0; ag < mp->m_sb.sb_agcount; ag++) {
557 p = do_label(ag, NULL);
558 if (!p) {
9ee7055c 559 dbprintf(_("failed to read label in AG %d\n"), ag);
4ca431fc
NS
560 return 0;
561 }
562 if (!ag)
563 memcpy(&sb.sb_fname, p, sizeof(sb.sb_fname));
564 else if (memcmp(&sb.sb_fname, p, sizeof(sb.sb_fname)))
9ee7055c 565 dbprintf(_("warning: AG %d label differs\n"), ag);
4ca431fc 566 }
9ee7055c 567 dbprintf(_("label = \"%s\"\n"), p);
4ca431fc
NS
568 }
569 return 0;
570}
571
572
573static void
574version_help(void)
575{
9ee7055c 576 dbprintf(_(
4ca431fc
NS
577"\n"
578" set/print feature bits in sb version\n"
579"\n"
580" Example:\n"
581"\n"
582" 'version' - print current feature bits\n"
583" 'version extflg' - enable unwritten extents\n"
70476e54
NS
584" 'version attr1' - enable v1 inline extended attributes\n"
585" 'version attr2' - enable v2 inline extended attributes\n"
66997473 586" 'version log2' - enable v2 log format\n"
4ca431fc
NS
587"\n"
588"The version function prints currently enabled features for a filesystem\n"
ff1f79a7 589"according to the version field of its primary superblock.\n"
4ca431fc 590"It can also be used to enable selected features, such as support for\n"
ff1f79a7 591"unwritten extents. The updated version is written into all AGs.\n"
4ca431fc 592"\n"
9ee7055c 593));
4ca431fc
NS
594}
595
596static int
14f8b681 597do_version(xfs_agnumber_t agno, uint16_t version, uint32_t features)
4ca431fc
NS
598{
599 xfs_sb_t tsb;
600
601 if (!get_sb(agno, &tsb))
602 return 0;
603
72f11257
ES
604 if (xfs_sb_has_mismatched_features2(&tsb)) {
605 dbprintf(_("Superblock has mismatched features2 fields, "
606 "skipping modification\n"));
607 return 0;
608 }
609
66997473 610 if ((version & XFS_SB_VERSION_LOGV2BIT) &&
5e656dbb 611 !xfs_sb_version_haslogv2(&tsb)) {
66997473 612 tsb.sb_logsunit = 1;
66997473
NS
613 }
614
70476e54
NS
615 tsb.sb_versionnum = version;
616 tsb.sb_features2 = features;
72f11257 617 tsb.sb_bad_features2 = features;
19ebedcf 618 libxfs_sb_to_disk(iocur_top->data, &tsb);
4ca431fc
NS
619 write_cur();
620 return 1;
621}
622
623static char *
624version_string(
625 xfs_sb_t *sbp)
626{
627 static char s[1024];
628
629 if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_1)
630 strcpy(s, "V1");
631 else if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_2)
632 strcpy(s, "V2");
633 else if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_3)
634 strcpy(s, "V3");
635 else if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4)
636 strcpy(s, "V4");
a23fa047
DC
637 else if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5)
638 strcpy(s, "V5");
4ca431fc 639
5f6f3660
DC
640 /*
641 * We assume the state of these features now, so macros don't exist for
642 * them any more.
643 */
644 if (sbp->sb_versionnum & XFS_SB_VERSION_NLINKBIT)
645 strcat(s, ",NLINK");
646 if (sbp->sb_versionnum & XFS_SB_VERSION_SHAREDBIT)
647 strcat(s, ",SHARED");
648 if (sbp->sb_versionnum & XFS_SB_VERSION_DIRV2BIT)
649 strcat(s, ",DIRV2");
650
5e656dbb 651 if (xfs_sb_version_hasattr(sbp))
4ca431fc 652 strcat(s, ",ATTR");
5e656dbb 653 if (xfs_sb_version_hasquota(sbp))
4ca431fc 654 strcat(s, ",QUOTA");
5e656dbb 655 if (xfs_sb_version_hasalign(sbp))
4ca431fc 656 strcat(s, ",ALIGN");
5e656dbb 657 if (xfs_sb_version_hasdalign(sbp))
4ca431fc 658 strcat(s, ",DALIGN");
5e656dbb 659 if (xfs_sb_version_haslogv2(sbp))
4ca431fc 660 strcat(s, ",LOGV2");
b7fdeb4d
CH
661 /* This feature is required now as well */
662 if (sbp->sb_versionnum & XFS_SB_VERSION_EXTFLGBIT)
4ca431fc 663 strcat(s, ",EXTFLG");
5e656dbb 664 if (xfs_sb_version_hassector(sbp))
4ca431fc 665 strcat(s, ",SECTOR");
51ca7008
BN
666 if (xfs_sb_version_hasasciici(sbp))
667 strcat(s, ",ASCII_CI");
5e656dbb 668 if (xfs_sb_version_hasmorebits(sbp))
ca86e759 669 strcat(s, ",MOREBITS");
5e656dbb 670 if (xfs_sb_version_hasattr2(sbp))
ca86e759 671 strcat(s, ",ATTR2");
5e656dbb 672 if (xfs_sb_version_haslazysbcount(sbp))
cdded3d8 673 strcat(s, ",LAZYSBCOUNT");
22bc10ed
AM
674 if (xfs_sb_version_hasprojid32bit(sbp))
675 strcat(s, ",PROJID32BIT");
a23fa047
DC
676 if (xfs_sb_version_hascrc(sbp))
677 strcat(s, ",CRC");
42737f1a
MT
678 if (xfs_sb_version_hasftype(sbp))
679 strcat(s, ",FTYPE");
b7fc3b36
ES
680 if (xfs_sb_version_hasfinobt(sbp))
681 strcat(s, ",FINOBT");
b8db0171
BF
682 if (xfs_sb_version_hassparseinodes(sbp))
683 strcat(s, ",SPARSE_INODES");
9c4e12fb
ES
684 if (xfs_sb_version_hasmetauuid(sbp))
685 strcat(s, ",META_UUID");
f810b1bc
ZL
686 if (xfs_sb_version_hasrmapbt(sbp))
687 strcat(s, ",RMAPBT");
9fb2cb27
DW
688 if (xfs_sb_version_hasreflink(sbp))
689 strcat(s, ",REFLINK");
4ca431fc
NS
690 return s;
691}
692
a23fa047
DC
693/*
694 * XXX: this only supports reading and writing to version 4 superblock fields.
695 * V5 superblocks always define certain V4 feature bits - they are blocked from
696 * being changed if a V5 sb is detected, but otherwise v5 superblock features
697 * are not handled here.
698 */
4ca431fc
NS
699static int
700version_f(
701 int argc,
702 char **argv)
703{
14f8b681
DW
704 uint16_t version = 0;
705 uint32_t features = 0;
4ca431fc
NS
706 xfs_agnumber_t ag;
707
708 if (argc == 2) { /* WRITE VERSION */
709
710 if ((x.isreadonly & LIBXFS_ISREADONLY) || !expert_mode) {
9ee7055c 711 dbprintf(_("%s: not in expert mode, writing disabled\n"),
4ca431fc
NS
712 progname);
713 return 0;
714 }
715
716 /* Logic here derived from the IRIX xfs_chver(1M) script. */
717 if (!strcasecmp(argv[1], "extflg")) {
718 switch (XFS_SB_VERSION_NUM(&mp->m_sb)) {
719 case XFS_SB_VERSION_1:
720 version = 0x0004 | XFS_SB_VERSION_EXTFLGBIT;
721 break;
722 case XFS_SB_VERSION_2:
723 version = 0x0014 | XFS_SB_VERSION_EXTFLGBIT;
724 break;
725 case XFS_SB_VERSION_3:
726 version = 0x0034 | XFS_SB_VERSION_EXTFLGBIT;
727 break;
728 case XFS_SB_VERSION_4:
b7fdeb4d
CH
729 if (mp->m_sb.sb_versionnum &
730 XFS_SB_VERSION_EXTFLGBIT)
a23fa047
DC
731 dbprintf(
732 _("unwritten extents flag is already enabled\n"));
4ca431fc
NS
733 else
734 version = mp->m_sb.sb_versionnum |
735 XFS_SB_VERSION_EXTFLGBIT;
736 break;
a23fa047
DC
737 case XFS_SB_VERSION_5:
738 dbprintf(
739 _("unwritten extents always enabled for v5 superblocks.\n"));
740 break;
4ca431fc 741 }
66997473
NS
742 } else if (!strcasecmp(argv[1], "log2")) {
743 switch (XFS_SB_VERSION_NUM(&mp->m_sb)) {
744 case XFS_SB_VERSION_1:
745 version = 0x0004 | XFS_SB_VERSION_LOGV2BIT;
746 break;
747 case XFS_SB_VERSION_2:
748 version = 0x0014 | XFS_SB_VERSION_LOGV2BIT;
749 break;
750 case XFS_SB_VERSION_3:
751 version = 0x0034 | XFS_SB_VERSION_LOGV2BIT;
752 break;
753 case XFS_SB_VERSION_4:
5e656dbb 754 if (xfs_sb_version_haslogv2(&mp->m_sb))
a23fa047
DC
755 dbprintf(
756 _("version 2 log format is already in use\n"));
66997473
NS
757 else
758 version = mp->m_sb.sb_versionnum |
759 XFS_SB_VERSION_LOGV2BIT;
760 break;
a23fa047
DC
761 case XFS_SB_VERSION_5:
762 dbprintf(
763 _("Version 2 logs always enabled for v5 superblocks.\n"));
764 break;
66997473 765 }
a23fa047
DC
766 } else if (XFS_SB_VERSION_NUM(&mp->m_sb) == XFS_SB_VERSION_5) {
767 dbprintf(
768 _("%s: Cannot change %s on v5 superblocks.\n"),
769 progname, argv[1]);
770 return 0;
70476e54 771 } else if (!strcasecmp(argv[1], "attr1")) {
a23fa047 772
5e656dbb 773 if (xfs_sb_version_hasattr2(&mp->m_sb)) {
70476e54
NS
774 if (!(mp->m_sb.sb_features2 &=
775 ~XFS_SB_VERSION2_ATTR2BIT))
776 mp->m_sb.sb_versionnum &=
777 ~XFS_SB_VERSION_MOREBITSBIT;
778 }
5e656dbb 779 xfs_sb_version_addattr(&mp->m_sb);
70476e54
NS
780 version = mp->m_sb.sb_versionnum;
781 features = mp->m_sb.sb_features2;
782 } else if (!strcasecmp(argv[1], "attr2")) {
5e656dbb
BN
783 xfs_sb_version_addattr(&mp->m_sb);
784 xfs_sb_version_addattr2(&mp->m_sb);
22bc10ed
AM
785 version = mp->m_sb.sb_versionnum;
786 features = mp->m_sb.sb_features2;
787 } else if (!strcasecmp(argv[1], "projid32bit")) {
788 xfs_sb_version_addprojid32bit(&mp->m_sb);
70476e54
NS
789 version = mp->m_sb.sb_versionnum;
790 features = mp->m_sb.sb_features2;
4ca431fc 791 } else {
9ee7055c 792 dbprintf(_("%s: invalid version change command \"%s\"\n"),
4ca431fc
NS
793 progname, argv[1]);
794 return 0;
795 }
796
797 if (version) {
9ee7055c 798 dbprintf(_("writing all SBs\n"));
4ca431fc 799 for (ag = 0; ag < mp->m_sb.sb_agcount; ag++)
70476e54 800 if (!do_version(ag, version, features)) {
9ee7055c
AM
801 dbprintf(_("failed to set versionnum "
802 "in AG %d\n"), ag);
4ca431fc
NS
803 break;
804 }
805 mp->m_sb.sb_versionnum = version;
70476e54 806 mp->m_sb.sb_features2 = features;
4ca431fc
NS
807 }
808 }
d2df702b
NS
809
810 if (argc == 3) { /* VERSIONNUM + FEATURES2 */
811 char *sp;
812
813 version = mp->m_sb.sb_versionnum;
814 features = mp->m_sb.sb_features2;
815 mp->m_sb.sb_versionnum = strtoul(argv[1], &sp, 0);
816 mp->m_sb.sb_features2 = strtoul(argv[2], &sp, 0);
817 }
818
9ee7055c 819 dbprintf(_("versionnum [0x%x+0x%x] = %s\n"), mp->m_sb.sb_versionnum,
ca86e759 820 mp->m_sb.sb_features2, version_string(&mp->m_sb));
d2df702b
NS
821
822 if (argc == 3) { /* now reset... */
823 mp->m_sb.sb_versionnum = version;
824 mp->m_sb.sb_features2 = features;
825 return 0;
826 }
827
4ca431fc
NS
828 return 0;
829}