1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
20 #define uuid_equal(s,d) (platform_uuid_compare((s),(d)) == 0)
22 static int sb_f(int argc
, char **argv
);
23 static void sb_help(void);
24 static int uuid_f(int argc
, char **argv
);
25 static void uuid_help(void);
26 static int label_f(int argc
, char **argv
);
27 static void label_help(void);
28 static int version_f(int argc
, char **argv
);
29 static void version_help(void);
31 static const cmdinfo_t sb_cmd
=
32 { "sb", NULL
, sb_f
, 0, 1, 1, N_("[agno]"),
33 N_("set current address to sb header"), sb_help
};
34 static const cmdinfo_t uuid_cmd
=
35 { "uuid", NULL
, uuid_f
, 0, 1, 1, N_("[uuid]"),
36 N_("write/print FS uuid"), uuid_help
};
37 static const cmdinfo_t label_cmd
=
38 { "label", NULL
, label_f
, 0, 1, 1, N_("[label]"),
39 N_("write/print FS label"), label_help
};
40 static const cmdinfo_t version_cmd
=
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
};
48 add_command(&uuid_cmd
);
49 add_command(&label_cmd
);
50 add_command(&version_cmd
);
53 #define OFF(f) bitize(offsetof(xfs_sb_t, sb_ ## f))
54 #define SZC(f) szcount(xfs_sb_t, sb_ ## f)
55 const 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
},
89 { "gquotino", FLDT_INO
, OI(OFF(gquotino
)), C1
, 0, TYP_INODE
},
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
},
97 { "logsectlog", FLDT_UINT8D
, OI(OFF(logsectlog
)), C1
, 0, TYP_NONE
},
98 { "logsectsize", FLDT_UINT16D
, OI(OFF(logsectsize
)), C1
, 0, TYP_NONE
},
99 { "logsunit", FLDT_UINT32D
, OI(OFF(logsunit
)), C1
, 0, TYP_NONE
},
100 { "features2", FLDT_UINT32X
, OI(OFF(features2
)), C1
, 0, TYP_NONE
},
101 { "bad_features2", FLDT_UINT32X
, OI(OFF(bad_features2
)),
103 { "features_compat", FLDT_UINT32X
, OI(OFF(features_compat
)),
105 { "features_ro_compat", FLDT_UINT32X
, OI(OFF(features_ro_compat
)),
107 { "features_incompat", FLDT_UINT32X
, OI(OFF(features_incompat
)),
109 { "features_log_incompat", FLDT_UINT32X
, OI(OFF(features_log_incompat
)),
111 { "crc", FLDT_CRC
, OI(OFF(crc
)), C1
, 0, TYP_NONE
},
112 { "spino_align", FLDT_EXTLEN
, OI(OFF(spino_align
)), C1
, 0, TYP_NONE
},
113 { "pquotino", FLDT_INO
, OI(OFF(pquotino
)), C1
, 0, TYP_INODE
},
114 { "lsn", FLDT_UINT64X
, OI(OFF(lsn
)), C1
, 0, TYP_NONE
},
115 { "meta_uuid", FLDT_UUID
, OI(OFF(meta_uuid
)), C1
, 0, TYP_NONE
},
119 const field_t sb_hfld
[] = {
120 { "", FLDT_SB
, OI(0), C1
, 0, TYP_NONE
},
129 " set allocation group superblock\n"
133 " 'sb 7' - set location to 7th allocation group superblock, set type to 'sb'\n"
135 " Located in the first sector of each allocation group, the superblock\n"
136 " contains the base information for the filesystem.\n"
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"
153 agno
= (xfs_agnumber_t
)strtoul(argv
[1], &p
, 0);
154 if (*p
!= '\0' || agno
>= mp
->m_sb
.sb_agcount
) {
155 dbprintf(_("bad allocation group number %s\n"), argv
[1]);
159 } else if (cur_agno
== NULLAGNUMBER
)
161 ASSERT(typtab
[TYP_SB
].typnm
== TYP_SB
);
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
);
175 return bitize(mp
->m_sb
.sb_sectsize
);
179 get_sb(xfs_agnumber_t agno
, xfs_sb_t
*sb
)
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
);
186 if (!iocur_top
->data
) {
187 dbprintf(_("can't read superblock for AG %u\n"), agno
);
192 libxfs_sb_from_disk(sb
, iocur_top
->data
);
194 if (sb
->sb_magicnum
!= XFS_SB_MAGIC
) {
195 dbprintf(_("bad sb magic # %#x in AG %u\n"),
196 sb
->sb_magicnum
, agno
);
199 if (!xfs_sb_good_version(sb
)) {
200 dbprintf(_("bad sb version # %#x in AG %u\n"),
201 sb
->sb_versionnum
, agno
);
204 if (agno
== 0 && sb
->sb_inprogress
!= 0) {
205 dbprintf(_("mkfs not completed successfully\n"));
211 /* workaround craziness in the xlog routines */
212 int xlog_recover_do_trans(struct xlog
*log
, xlog_recover_t
*t
, int p
)
222 if (mp
->m_sb
.sb_logstart
) {
223 if (x
.logdev
&& x
.logdev
!= x
.ddev
) {
224 dbprintf(_("aborting - external log specified for FS "
225 "with an internal log\n"));
229 if (!x
.logdev
|| (x
.logdev
== x
.ddev
)) {
230 dbprintf(_("aborting - no external log specified for FS "
231 "with an external log\n"));
236 libxfs_buftarg_init(mp
, x
.ddev
, x
.logdev
, x
.rtdev
);
238 dirty
= xlog_is_dirty(mp
, mp
->m_log
, &x
, 0);
240 dbprintf(_("ERROR: cannot find log head/tail, run xfs_repair\n"));
242 } else if (dirty
== 1) {
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"
249 "of the filesystem before doing this.\n"), progname
);
257 sb_logzero(uuid_t
*uuidp
)
259 int cycle
= XLOG_INIT_CYCLE
;
266 * The log must always move forward on v5 superblocks. Bump it to the
269 if (xfs_sb_version_hascrc(&mp
->m_sb
))
270 cycle
= mp
->m_log
->l_curr_cycle
+ 1;
272 dbprintf(_("Clearing log and setting UUID\n"));
274 error
= libxfs_log_clear(mp
->m_logdev_targp
, NULL
,
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
),
278 xfs_sb_version_haslogv2(&mp
->m_sb
) ? 2 : 1,
279 mp
->m_sb
.sb_logsunit
, XLOG_FMT
, cycle
, true);
281 dbprintf(_("ERROR: cannot clear the log\n"));
294 " write/print FS uuid\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"
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"
314 do_uuid(xfs_agnumber_t agno
, uuid_t
*uuid
)
319 if (!get_sb(agno
, &tsb
))
322 if (!uuid
) { /* get uuid */
323 memcpy(&uu
, &tsb
.sb_uuid
, sizeof(uuid_t
));
328 if (!xfs_sb_version_hascrc(&tsb
))
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.
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.
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
;
354 memcpy(&tsb
.sb_uuid
, uuid
, sizeof(uuid_t
));
355 libxfs_sb_to_disk(iocur_top
->data
, &tsb
);
370 if (argc
!= 1 && argc
!= 2) {
371 dbprintf(_("invalid parameters\n"));
375 if (argc
== 2) { /* WRITE UUID */
377 if ((x
.isreadonly
& LIBXFS_ISREADONLY
) || !expert_mode
) {
378 dbprintf(_("%s: not in expert mode, writing disabled\n"),
383 if (!strcasecmp(argv
[1], "generate")) {
384 platform_uuid_generate(&uu
);
385 } else if (!strcasecmp(argv
[1], "nil")) {
386 platform_uuid_clear(&uu
);
387 } else if (!strcasecmp(argv
[1], "rewrite")) {
388 uup
= do_uuid(0, NULL
);
390 dbprintf(_("failed to read UUID from AG 0\n"));
393 memcpy(&uu
, uup
, sizeof(uuid_t
));
394 platform_uuid_unparse(&uu
, bp
);
395 dbprintf(_("old UUID = %s\n"), bp
);
396 } else if (!strcasecmp(argv
[1], "restore")) {
399 if (!get_sb(0, &tsb
))
402 /* Not set; nothing to do. Success! */
403 if (!xfs_sb_version_hasmetauuid(&tsb
))
406 memcpy(&uu
, mp
->m_sb
.sb_meta_uuid
, sizeof(uuid_t
));
408 if (platform_uuid_parse(argv
[1], &uu
)) {
409 dbprintf(_("invalid UUID\n"));
414 /* clear the log (setting uuid) if it's not dirty */
415 if (!sb_logzero(&uu
))
418 dbprintf(_("writing all SBs\n"));
419 for (agno
= 0; agno
< mp
->m_sb
.sb_agcount
; agno
++)
420 if (!do_uuid(agno
, &uu
)) {
421 dbprintf(_("failed to set UUID in AG %d\n"), agno
);
425 platform_uuid_unparse(&uu
, bp
);
426 dbprintf(_("new UUID = %s\n"), bp
);
429 } else { /* READ+CHECK UUID */
431 for (agno
= 0; agno
< mp
->m_sb
.sb_agcount
; agno
++) {
432 uup
= do_uuid(agno
, NULL
);
434 dbprintf(_("failed to read UUID from AG %d\n"),
439 if (memcmp(&uu
, uup
, sizeof(uuid_t
))) {
440 dbprintf(_("warning: UUID in AG %d "
441 "differs to the primary SB\n"),
446 memcpy(&uu
, uup
, sizeof(uuid_t
));
449 if (mp
->m_sb
.sb_logstart
) {
450 if (x
.logdev
&& x
.logdev
!= x
.ddev
)
451 dbprintf(_("warning - external log specified "
452 "for FS with an internal log\n"));
453 } else if (!x
.logdev
|| (x
.logdev
== x
.ddev
)) {
454 dbprintf(_("warning - no external log specified "
455 "for FS with an external log\n"));
458 platform_uuid_unparse(&uu
, bp
);
459 dbprintf(_("UUID = %s\n"), bp
);
471 " write/print FS label\n"
475 " 'label' - print label\n"
476 " 'label 123456789012' - write label\n"
477 " 'label --' - write an empty label\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"
488 do_label(xfs_agnumber_t agno
, char *label
)
492 static char lbl
[sizeof(tsb
.sb_fname
) + 1];
494 if (!get_sb(agno
, &tsb
))
497 memset(&lbl
[0], 0, sizeof(lbl
));
499 if (!label
) { /* get label */
501 memcpy(&lbl
[0], &tsb
.sb_fname
, sizeof(tsb
.sb_fname
));
505 if ((len
= strlen(label
)) > sizeof(tsb
.sb_fname
)) {
507 dbprintf(_("%s: truncating label length from %d to %d\n"),
508 progname
, (int)len
, (int)sizeof(tsb
.sb_fname
));
509 len
= sizeof(tsb
.sb_fname
);
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
));
519 libxfs_sb_to_disk(iocur_top
->data
, &tsb
);
533 if (argc
!= 1 && argc
!= 2) {
534 dbprintf(_("invalid parameters\n"));
538 if (argc
== 2) { /* WRITE LABEL */
540 if ((x
.isreadonly
& LIBXFS_ISREADONLY
) || !expert_mode
) {
541 dbprintf(_("%s: not in expert mode, writing disabled\n"),
546 dbprintf(_("writing all SBs\n"));
547 for (ag
= 0; ag
< mp
->m_sb
.sb_agcount
; ag
++)
548 if ((p
= do_label(ag
, argv
[1])) == NULL
) {
549 dbprintf(_("failed to set label in AG %d\n"), ag
);
552 dbprintf(_("new label = \"%s\"\n"), p
);
554 } else { /* READ LABEL */
556 for (ag
= 0; ag
< mp
->m_sb
.sb_agcount
; ag
++) {
557 p
= do_label(ag
, NULL
);
559 dbprintf(_("failed to read label in AG %d\n"), ag
);
563 memcpy(&sb
.sb_fname
, p
, sizeof(sb
.sb_fname
));
564 else if (memcmp(&sb
.sb_fname
, p
, sizeof(sb
.sb_fname
)))
565 dbprintf(_("warning: AG %d label differs\n"), ag
);
567 dbprintf(_("label = \"%s\"\n"), p
);
578 " set/print feature bits in sb version\n"
582 " 'version' - print current feature bits\n"
583 " 'version extflg' - enable unwritten extents\n"
584 " 'version attr1' - enable v1 inline extended attributes\n"
585 " 'version attr2' - enable v2 inline extended attributes\n"
586 " 'version log2' - enable v2 log format\n"
588 "The version function prints currently enabled features for a filesystem\n"
589 "according to the version field of its primary superblock.\n"
590 "It can also be used to enable selected features, such as support for\n"
591 "unwritten extents. The updated version is written into all AGs.\n"
597 do_version(xfs_agnumber_t agno
, uint16_t version
, uint32_t features
)
601 if (!get_sb(agno
, &tsb
))
604 if (xfs_sb_has_mismatched_features2(&tsb
)) {
605 dbprintf(_("Superblock has mismatched features2 fields, "
606 "skipping modification\n"));
610 if ((version
& XFS_SB_VERSION_LOGV2BIT
) &&
611 !xfs_sb_version_haslogv2(&tsb
)) {
615 tsb
.sb_versionnum
= version
;
616 tsb
.sb_features2
= features
;
617 tsb
.sb_bad_features2
= features
;
618 libxfs_sb_to_disk(iocur_top
->data
, &tsb
);
629 if (XFS_SB_VERSION_NUM(sbp
) == XFS_SB_VERSION_1
)
631 else if (XFS_SB_VERSION_NUM(sbp
) == XFS_SB_VERSION_2
)
633 else if (XFS_SB_VERSION_NUM(sbp
) == XFS_SB_VERSION_3
)
635 else if (XFS_SB_VERSION_NUM(sbp
) == XFS_SB_VERSION_4
)
637 else if (XFS_SB_VERSION_NUM(sbp
) == XFS_SB_VERSION_5
)
641 * We assume the state of these features now, so macros don't exist for
644 if (sbp
->sb_versionnum
& XFS_SB_VERSION_NLINKBIT
)
646 if (sbp
->sb_versionnum
& XFS_SB_VERSION_SHAREDBIT
)
647 strcat(s
, ",SHARED");
648 if (sbp
->sb_versionnum
& XFS_SB_VERSION_DIRV2BIT
)
651 if (xfs_sb_version_hasattr(sbp
))
653 if (xfs_sb_version_hasquota(sbp
))
655 if (xfs_sb_version_hasalign(sbp
))
657 if (xfs_sb_version_hasdalign(sbp
))
658 strcat(s
, ",DALIGN");
659 if (xfs_sb_version_haslogv2(sbp
))
661 if (xfs_sb_version_hasextflgbit(sbp
))
662 strcat(s
, ",EXTFLG");
663 if (xfs_sb_version_hassector(sbp
))
664 strcat(s
, ",SECTOR");
665 if (xfs_sb_version_hasasciici(sbp
))
666 strcat(s
, ",ASCII_CI");
667 if (xfs_sb_version_hasmorebits(sbp
))
668 strcat(s
, ",MOREBITS");
669 if (xfs_sb_version_hasattr2(sbp
))
671 if (xfs_sb_version_haslazysbcount(sbp
))
672 strcat(s
, ",LAZYSBCOUNT");
673 if (xfs_sb_version_hasprojid32bit(sbp
))
674 strcat(s
, ",PROJID32BIT");
675 if (xfs_sb_version_hascrc(sbp
))
677 if (xfs_sb_version_hasftype(sbp
))
679 if (xfs_sb_version_hasfinobt(sbp
))
680 strcat(s
, ",FINOBT");
681 if (xfs_sb_version_hassparseinodes(sbp
))
682 strcat(s
, ",SPARSE_INODES");
683 if (xfs_sb_version_hasmetauuid(sbp
))
684 strcat(s
, ",META_UUID");
685 if (xfs_sb_version_hasrmapbt(sbp
))
686 strcat(s
, ",RMAPBT");
687 if (xfs_sb_version_hasreflink(sbp
))
688 strcat(s
, ",REFLINK");
693 * XXX: this only supports reading and writing to version 4 superblock fields.
694 * V5 superblocks always define certain V4 feature bits - they are blocked from
695 * being changed if a V5 sb is detected, but otherwise v5 superblock features
696 * are not handled here.
703 uint16_t version
= 0;
704 uint32_t features
= 0;
707 if (argc
== 2) { /* WRITE VERSION */
709 if ((x
.isreadonly
& LIBXFS_ISREADONLY
) || !expert_mode
) {
710 dbprintf(_("%s: not in expert mode, writing disabled\n"),
715 /* Logic here derived from the IRIX xfs_chver(1M) script. */
716 if (!strcasecmp(argv
[1], "extflg")) {
717 switch (XFS_SB_VERSION_NUM(&mp
->m_sb
)) {
718 case XFS_SB_VERSION_1
:
719 version
= 0x0004 | XFS_SB_VERSION_EXTFLGBIT
;
721 case XFS_SB_VERSION_2
:
722 version
= 0x0014 | XFS_SB_VERSION_EXTFLGBIT
;
724 case XFS_SB_VERSION_3
:
725 version
= 0x0034 | XFS_SB_VERSION_EXTFLGBIT
;
727 case XFS_SB_VERSION_4
:
728 if (xfs_sb_version_hasextflgbit(&mp
->m_sb
))
730 _("unwritten extents flag is already enabled\n"));
732 version
= mp
->m_sb
.sb_versionnum
|
733 XFS_SB_VERSION_EXTFLGBIT
;
735 case XFS_SB_VERSION_5
:
737 _("unwritten extents always enabled for v5 superblocks.\n"));
740 } else if (!strcasecmp(argv
[1], "log2")) {
741 switch (XFS_SB_VERSION_NUM(&mp
->m_sb
)) {
742 case XFS_SB_VERSION_1
:
743 version
= 0x0004 | XFS_SB_VERSION_LOGV2BIT
;
745 case XFS_SB_VERSION_2
:
746 version
= 0x0014 | XFS_SB_VERSION_LOGV2BIT
;
748 case XFS_SB_VERSION_3
:
749 version
= 0x0034 | XFS_SB_VERSION_LOGV2BIT
;
751 case XFS_SB_VERSION_4
:
752 if (xfs_sb_version_haslogv2(&mp
->m_sb
))
754 _("version 2 log format is already in use\n"));
756 version
= mp
->m_sb
.sb_versionnum
|
757 XFS_SB_VERSION_LOGV2BIT
;
759 case XFS_SB_VERSION_5
:
761 _("Version 2 logs always enabled for v5 superblocks.\n"));
764 } else if (XFS_SB_VERSION_NUM(&mp
->m_sb
) == XFS_SB_VERSION_5
) {
766 _("%s: Cannot change %s on v5 superblocks.\n"),
769 } else if (!strcasecmp(argv
[1], "attr1")) {
771 if (xfs_sb_version_hasattr2(&mp
->m_sb
)) {
772 if (!(mp
->m_sb
.sb_features2
&=
773 ~XFS_SB_VERSION2_ATTR2BIT
))
774 mp
->m_sb
.sb_versionnum
&=
775 ~XFS_SB_VERSION_MOREBITSBIT
;
777 xfs_sb_version_addattr(&mp
->m_sb
);
778 version
= mp
->m_sb
.sb_versionnum
;
779 features
= mp
->m_sb
.sb_features2
;
780 } else if (!strcasecmp(argv
[1], "attr2")) {
781 xfs_sb_version_addattr(&mp
->m_sb
);
782 xfs_sb_version_addattr2(&mp
->m_sb
);
783 version
= mp
->m_sb
.sb_versionnum
;
784 features
= mp
->m_sb
.sb_features2
;
785 } else if (!strcasecmp(argv
[1], "projid32bit")) {
786 xfs_sb_version_addprojid32bit(&mp
->m_sb
);
787 version
= mp
->m_sb
.sb_versionnum
;
788 features
= mp
->m_sb
.sb_features2
;
790 dbprintf(_("%s: invalid version change command \"%s\"\n"),
796 dbprintf(_("writing all SBs\n"));
797 for (ag
= 0; ag
< mp
->m_sb
.sb_agcount
; ag
++)
798 if (!do_version(ag
, version
, features
)) {
799 dbprintf(_("failed to set versionnum "
803 mp
->m_sb
.sb_versionnum
= version
;
804 mp
->m_sb
.sb_features2
= features
;
808 if (argc
== 3) { /* VERSIONNUM + FEATURES2 */
811 version
= mp
->m_sb
.sb_versionnum
;
812 features
= mp
->m_sb
.sb_features2
;
813 mp
->m_sb
.sb_versionnum
= strtoul(argv
[1], &sp
, 0);
814 mp
->m_sb
.sb_features2
= strtoul(argv
[2], &sp
, 0);
817 dbprintf(_("versionnum [0x%x+0x%x] = %s\n"), mp
->m_sb
.sb_versionnum
,
818 mp
->m_sb
.sb_features2
, version_string(&mp
->m_sb
));
820 if (argc
== 3) { /* now reset... */
821 mp
->m_sb
.sb_versionnum
= version
;
822 mp
->m_sb
.sb_features2
= features
;