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