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);
30 static size_t check_label(char *label
, bool can_warn
);
32 static const cmdinfo_t sb_cmd
=
33 { "sb", NULL
, sb_f
, 0, 1, 1, N_("[agno]"),
34 N_("set current address to sb header"), sb_help
};
35 static const cmdinfo_t uuid_cmd
=
36 { "uuid", NULL
, uuid_f
, 0, 1, 1, N_("[uuid]"),
37 N_("write/print FS uuid"), uuid_help
};
38 static const cmdinfo_t label_cmd
=
39 { "label", NULL
, label_f
, 0, 1, 1, N_("[label]"),
40 N_("write/print FS label"), label_help
};
41 static const cmdinfo_t version_cmd
=
42 { "version", NULL
, version_f
, 0, -1, 1, N_("[feature | [vnum fnum]]"),
43 N_("set feature bit(s) in the sb version field"), version_help
};
49 add_command(&uuid_cmd
);
50 add_command(&label_cmd
);
51 add_command(&version_cmd
);
55 * Counts superblock fields that only exist when the metadata directory feature
63 return xfs_has_metadir(mp
) ? 1 : 0;
66 #define OFF(f) bitize(offsetof(struct xfs_dsb, sb_ ## f))
67 #define SZC(f) szcount(struct xfs_dsb, sb_ ## f)
68 const field_t sb_flds
[] = {
69 { "magicnum", FLDT_UINT32X
, OI(OFF(magicnum
)), C1
, 0, TYP_NONE
},
70 { "blocksize", FLDT_UINT32D
, OI(OFF(blocksize
)), C1
, 0, TYP_NONE
},
71 { "dblocks", FLDT_DRFSBNO
, OI(OFF(dblocks
)), C1
, 0, TYP_NONE
},
72 { "rblocks", FLDT_DRFSBNO
, OI(OFF(rblocks
)), C1
, 0, TYP_NONE
},
73 { "rextents", FLDT_DRTBNO
, OI(OFF(rextents
)), C1
, 0, TYP_NONE
},
74 { "uuid", FLDT_UUID
, OI(OFF(uuid
)), C1
, 0, TYP_NONE
},
75 { "logstart", FLDT_DFSBNO
, OI(OFF(logstart
)), C1
, 0, TYP_LOG
},
76 { "rootino", FLDT_INO
, OI(OFF(rootino
)), C1
, 0, TYP_INODE
},
77 { "rbmino", FLDT_INO
, OI(OFF(rbmino
)), C1
, 0, TYP_INODE
},
78 { "rsumino", FLDT_INO
, OI(OFF(rsumino
)), C1
, 0, TYP_INODE
},
79 { "rextsize", FLDT_AGBLOCK
, OI(OFF(rextsize
)), C1
, 0, TYP_NONE
},
80 { "agblocks", FLDT_AGBLOCK
, OI(OFF(agblocks
)), C1
, 0, TYP_NONE
},
81 { "agcount", FLDT_AGNUMBER
, OI(OFF(agcount
)), C1
, 0, TYP_NONE
},
82 { "rbmblocks", FLDT_EXTLEN
, OI(OFF(rbmblocks
)), C1
, 0, TYP_NONE
},
83 { "logblocks", FLDT_EXTLEN
, OI(OFF(logblocks
)), C1
, 0, TYP_NONE
},
84 { "versionnum", FLDT_UINT16X
, OI(OFF(versionnum
)), C1
, 0, TYP_NONE
},
85 { "sectsize", FLDT_UINT16D
, OI(OFF(sectsize
)), C1
, 0, TYP_NONE
},
86 { "inodesize", FLDT_UINT16D
, OI(OFF(inodesize
)), C1
, 0, TYP_NONE
},
87 { "inopblock", FLDT_UINT16D
, OI(OFF(inopblock
)), C1
, 0, TYP_NONE
},
88 { "fname", FLDT_CHARNS
, OI(OFF(fname
)), CI(SZC(fname
)), 0, TYP_NONE
},
89 { "blocklog", FLDT_UINT8D
, OI(OFF(blocklog
)), C1
, 0, TYP_NONE
},
90 { "sectlog", FLDT_UINT8D
, OI(OFF(sectlog
)), C1
, 0, TYP_NONE
},
91 { "inodelog", FLDT_UINT8D
, OI(OFF(inodelog
)), C1
, 0, TYP_NONE
},
92 { "inopblog", FLDT_UINT8D
, OI(OFF(inopblog
)), C1
, 0, TYP_NONE
},
93 { "agblklog", FLDT_UINT8D
, OI(OFF(agblklog
)), C1
, 0, TYP_NONE
},
94 { "rextslog", FLDT_UINT8D
, OI(OFF(rextslog
)), C1
, 0, TYP_NONE
},
95 { "inprogress", FLDT_UINT8D
, OI(OFF(inprogress
)), C1
, 0, TYP_NONE
},
96 { "imax_pct", FLDT_UINT8D
, OI(OFF(imax_pct
)), C1
, 0, TYP_NONE
},
97 { "icount", FLDT_UINT64D
, OI(OFF(icount
)), C1
, 0, TYP_NONE
},
98 { "ifree", FLDT_UINT64D
, OI(OFF(ifree
)), C1
, 0, TYP_NONE
},
99 { "fdblocks", FLDT_UINT64D
, OI(OFF(fdblocks
)), C1
, 0, TYP_NONE
},
100 { "frextents", FLDT_UINT64D
, OI(OFF(frextents
)), C1
, 0, TYP_NONE
},
101 { "uquotino", FLDT_INO
, OI(OFF(uquotino
)), C1
, 0, TYP_INODE
},
102 { "gquotino", FLDT_INO
, OI(OFF(gquotino
)), C1
, 0, TYP_INODE
},
103 { "qflags", FLDT_UINT16X
, OI(OFF(qflags
)), C1
, 0, TYP_NONE
},
104 { "flags", FLDT_UINT8X
, OI(OFF(flags
)), C1
, 0, TYP_NONE
},
105 { "shared_vn", FLDT_UINT8D
, OI(OFF(shared_vn
)), C1
, 0, TYP_NONE
},
106 { "inoalignmt", FLDT_EXTLEN
, OI(OFF(inoalignmt
)), C1
, 0, TYP_NONE
},
107 { "unit", FLDT_UINT32D
, OI(OFF(unit
)), C1
, 0, TYP_NONE
},
108 { "width", FLDT_UINT32D
, OI(OFF(width
)), C1
, 0, TYP_NONE
},
109 { "dirblklog", FLDT_UINT8D
, OI(OFF(dirblklog
)), C1
, 0, TYP_NONE
},
110 { "logsectlog", FLDT_UINT8D
, OI(OFF(logsectlog
)), C1
, 0, TYP_NONE
},
111 { "logsectsize", FLDT_UINT16D
, OI(OFF(logsectsize
)), C1
, 0, TYP_NONE
},
112 { "logsunit", FLDT_UINT32D
, OI(OFF(logsunit
)), C1
, 0, TYP_NONE
},
113 { "features2", FLDT_UINT32X
, OI(OFF(features2
)), C1
, 0, TYP_NONE
},
114 { "bad_features2", FLDT_UINT32X
, OI(OFF(bad_features2
)),
116 { "features_compat", FLDT_UINT32X
, OI(OFF(features_compat
)),
118 { "features_ro_compat", FLDT_UINT32X
, OI(OFF(features_ro_compat
)),
120 { "features_incompat", FLDT_UINT32X
, OI(OFF(features_incompat
)),
122 { "features_log_incompat", FLDT_UINT32X
, OI(OFF(features_log_incompat
)),
124 { "crc", FLDT_CRC
, OI(OFF(crc
)), C1
, 0, TYP_NONE
},
125 { "spino_align", FLDT_EXTLEN
, OI(OFF(spino_align
)), C1
, 0, TYP_NONE
},
126 { "pquotino", FLDT_INO
, OI(OFF(pquotino
)), C1
, 0, TYP_INODE
},
127 { "lsn", FLDT_UINT64X
, OI(OFF(lsn
)), C1
, 0, TYP_NONE
},
128 { "meta_uuid", FLDT_UUID
, OI(OFF(meta_uuid
)), C1
, 0, TYP_NONE
},
129 { "metadirino", FLDT_INO
, OI(OFF(metadirino
)), metadirfld_count
,
130 FLD_COUNT
, TYP_INODE
},
131 { "rgcount", FLDT_RGNUMBER
, OI(OFF(rgcount
)), metadirfld_count
,
132 FLD_COUNT
, TYP_NONE
},
133 { "rgextents", FLDT_RTXLEN
, OI(OFF(rgextents
)), metadirfld_count
,
134 FLD_COUNT
, TYP_NONE
},
135 { "rgblklog", FLDT_UINT8D
, OI(OFF(rgblklog
)), metadirfld_count
,
136 FLD_COUNT
, TYP_NONE
},
137 { "pad", FLDT_UINT8X
, OI(OFF(pad
)), metadirfld_count
,
138 FLD_COUNT
, TYP_NONE
},
142 const field_t sb_hfld
[] = {
143 { "", FLDT_SB
, OI(0), C1
, 0, TYP_NONE
},
152 " set allocation group superblock\n"
156 " 'sb 7' - set location to 7th allocation group superblock, set type to 'sb'\n"
158 " Located in the first sector of each allocation group, the superblock\n"
159 " contains the base information for the filesystem.\n"
160 " The superblock in allocation group 0 is the primary. The copies in the\n"
161 " remaining allocation groups only serve as backup for filesystem recovery.\n"
162 " The icount/ifree/fdblocks/frextents are only updated in superblock 0.\n"
176 agno
= (xfs_agnumber_t
)strtoul(argv
[1], &p
, 0);
177 if (*p
!= '\0' || agno
>= mp
->m_sb
.sb_agcount
) {
178 dbprintf(_("bad allocation group number %s\n"), argv
[1]);
182 } else if (cur_agno
== NULLAGNUMBER
)
184 ASSERT(typtab
[TYP_SB
].typnm
== TYP_SB
);
185 set_cur(&typtab
[TYP_SB
],
186 XFS_AG_DADDR(mp
, cur_agno
, XFS_SB_DADDR
),
187 XFS_FSS_TO_BB(mp
, 1), DB_RING_ADD
, NULL
);
198 return bitize(mp
->m_sb
.sb_sectsize
);
202 get_sb(xfs_agnumber_t agno
, xfs_sb_t
*sb
)
205 set_cur(&typtab
[TYP_SB
],
206 XFS_AG_DADDR(mp
, agno
, XFS_SB_DADDR
),
207 XFS_FSS_TO_BB(mp
, 1), DB_RING_IGN
, NULL
);
209 if (!iocur_top
->data
) {
210 dbprintf(_("can't read superblock for AG %u\n"), agno
);
215 libxfs_sb_from_disk(sb
, iocur_top
->data
);
217 if (sb
->sb_magicnum
!= XFS_SB_MAGIC
) {
218 dbprintf(_("bad sb magic # %#x in AG %u\n"),
219 sb
->sb_magicnum
, agno
);
222 if (!xfs_sb_good_version(sb
)) {
223 dbprintf(_("bad sb version # %#x in AG %u\n"),
224 sb
->sb_versionnum
, agno
);
227 if (agno
== 0 && sb
->sb_inprogress
!= 0) {
228 dbprintf(_("mkfs not completed successfully\n"));
234 /* workaround craziness in the xlog routines */
235 int xlog_recover_do_trans(struct xlog
*log
, struct xlog_recover
*t
, int p
)
245 if (mp
->m_sb
.sb_logstart
) {
246 if (x
.log
.dev
&& x
.log
.dev
!= x
.data
.dev
) {
247 dbprintf(_("aborting - external log specified for FS "
248 "with an internal log\n"));
252 if (!x
.log
.dev
|| (x
.log
.dev
== x
.data
.dev
)) {
253 dbprintf(_("aborting - no external log specified for FS "
254 "with an external log\n"));
259 libxfs_buftarg_init(mp
, &x
);
261 dirty
= xlog_is_dirty(mp
, mp
->m_log
);
263 dbprintf(_("ERROR: cannot find log head/tail, run xfs_repair\n"));
265 } else if (dirty
== 1) {
267 "ERROR: The filesystem has valuable metadata changes in a log which needs to\n"
268 "be replayed. Mount the filesystem to replay the log, and unmount it before\n"
269 "re-running %s. If the filesystem is a snapshot of a mounted filesystem,\n"
270 "you may need to give mount the nouuid option. If you are unable to mount\n"
271 "the filesystem, then use the xfs_repair -L option to destroy the log and\n"
272 "attempt a repair. Note that destroying the log may cause corruption --\n"
273 "please attempt a mount of the filesystem before doing this.\n"), progname
);
281 sb_logzero(uuid_t
*uuidp
)
283 int cycle
= XLOG_INIT_CYCLE
;
290 * The log must always move forward on v5 superblocks. Bump it to the
294 cycle
= mp
->m_log
->l_curr_cycle
+ 1;
296 dbprintf(_("Clearing log and setting UUID\n"));
298 error
= libxfs_log_clear(mp
->m_logdev_targp
, NULL
,
299 XFS_FSB_TO_DADDR(mp
, mp
->m_sb
.sb_logstart
),
300 (xfs_extlen_t
)XFS_FSB_TO_BB(mp
, mp
->m_sb
.sb_logblocks
),
302 xfs_has_logv2(mp
) ? 2 : 1,
303 mp
->m_sb
.sb_logsunit
, XLOG_FMT
, cycle
, true);
305 dbprintf(_("ERROR: cannot clear the log\n"));
318 " write/print FS uuid\n"
322 " 'uuid' - print UUID\n"
323 " 'uuid 01234567-0123-0123-0123-0123456789ab' - write UUID\n"
324 " 'uuid generate' - generate and write\n"
325 " 'uuid rewrite' - copy UUID from SB 0\n"
327 "The print function checks the UUID in each SB and will warn if the UUIDs\n"
328 "differ between AGs (the log is not checked). The write commands will\n"
329 "set the uuid in all AGs to either a specified value, a newly generated\n"
330 "value or the value found in the first superblock (SB 0) respectively.\n"
331 "As a side effect of writing the UUID, the log is cleared (which is fine\n"
332 "on a CLEANLY unmounted FS).\n"
339 struct xfs_mount
*mp
)
343 if (!xfs_has_realtime(mp
) || !xfs_has_rtsb(mp
))
347 error
= set_rt_cur(&typtab
[TYP_RTSB
], XFS_RTSB_DADDR
,
348 XFS_FSB_TO_BB(mp
, 1), DB_RING_ADD
, NULL
);
349 if (error
== ENODEV
) {
350 /* no rt dev means we should just bail out */
361 struct xfs_mount
*mp
,
365 struct xfs_rtsb
*rsb
;
368 if (!xfs_has_rtsb(mp
) || !xfs_has_realtime(mp
))
372 error
= set_rt_cur(&typtab
[TYP_RTSB
], XFS_RTSB_DADDR
,
373 XFS_FSB_TO_BB(mp
, 1), DB_RING_ADD
, NULL
);
374 if (error
== ENODEV
) {
375 /* no rt dev means we should just bail out */
381 rsb
= iocur_top
->data
;
383 size_t len
= check_label(label
, false);
385 memset(&rsb
->rsb_fname
, 0, XFSLABEL_MAX
);
386 memcpy(&rsb
->rsb_fname
, label
, len
);
389 memcpy(&rsb
->rsb_uuid
, uuid
, sizeof(rsb
->rsb_uuid
));
397 do_uuid(xfs_agnumber_t agno
, uuid_t
*uuid
)
402 if (!get_sb(agno
, &tsb
))
405 if (!uuid
) { /* get uuid */
406 memcpy(&uu
, &tsb
.sb_uuid
, sizeof(uuid_t
));
411 if (!xfs_sb_version_hascrc(&tsb
))
414 * If we have CRCs, and this UUID differs from that stamped in the
415 * metadata, set the incompat flag and copy the old one to the
416 * metadata-specific location.
418 * If we are setting the user-visible UUID back to match the metadata
419 * UUID, clear the metadata-specific location and the incompat flag.
421 if (!xfs_sb_version_hasmetauuid(&tsb
) &&
422 !uuid_equal(uuid
, &mp
->m_sb
.sb_meta_uuid
)) {
423 mp
->m_sb
.sb_features_incompat
|= XFS_SB_FEAT_INCOMPAT_META_UUID
;
424 tsb
.sb_features_incompat
|= XFS_SB_FEAT_INCOMPAT_META_UUID
;
425 memcpy(&tsb
.sb_meta_uuid
, &tsb
.sb_uuid
, sizeof(uuid_t
));
426 } else if (xfs_sb_version_hasmetauuid(&tsb
) &&
427 uuid_equal(uuid
, &mp
->m_sb
.sb_meta_uuid
)) {
428 memset(&tsb
.sb_meta_uuid
, 0, sizeof(uuid_t
));
429 /* Write those zeros now; it's ignored once we clear the flag */
430 libxfs_sb_to_disk(iocur_top
->data
, &tsb
);
431 mp
->m_sb
.sb_features_incompat
&=
432 ~XFS_SB_FEAT_INCOMPAT_META_UUID
;
433 tsb
.sb_features_incompat
&= ~XFS_SB_FEAT_INCOMPAT_META_UUID
;
437 memcpy(&tsb
.sb_uuid
, uuid
, sizeof(uuid_t
));
438 libxfs_sb_to_disk(iocur_top
->data
, &tsb
);
440 memcpy(&mp
->m_sb
.sb_uuid
, uuid
, sizeof(uuid_t
));
454 if (argc
!= 1 && argc
!= 2) {
455 dbprintf(_("invalid parameters\n"));
459 if (argc
== 2) { /* WRITE UUID */
461 if ((x
.flags
& LIBXFS_ISREADONLY
) || !expert_mode
) {
462 dbprintf(_("%s: not in expert mode, writing disabled\n"),
466 if (xfs_sb_version_needsrepair(&mp
->m_sb
)) {
467 dbprintf(_("%s: filesystem needs xfs_repair\n"),
472 if (!strcasecmp(argv
[1], "generate")) {
473 platform_uuid_generate(&uu
);
474 } else if (!strcasecmp(argv
[1], "nil")) {
475 platform_uuid_clear(&uu
);
476 } else if (!strcasecmp(argv
[1], "rewrite")) {
477 uup
= do_uuid(0, NULL
);
479 dbprintf(_("failed to read UUID from AG 0\n"));
482 memcpy(&uu
, uup
, sizeof(uuid_t
));
483 platform_uuid_unparse(&uu
, bp
);
484 dbprintf(_("old UUID = %s\n"), bp
);
485 } else if (!strcasecmp(argv
[1], "restore")) {
488 if (!get_sb(0, &tsb
))
491 /* Not set; nothing to do. Success! */
492 if (!xfs_sb_version_hasmetauuid(&tsb
))
495 memcpy(&uu
, mp
->m_sb
.sb_meta_uuid
, sizeof(uuid_t
));
497 if (platform_uuid_parse(argv
[1], &uu
)) {
498 dbprintf(_("invalid UUID\n"));
503 if (check_rtsb(mp
)) {
508 /* clear the log (setting uuid) if it's not dirty */
509 if (!sb_logzero(&uu
))
512 dbprintf(_("writing all SBs\n"));
513 if (update_rtsb(mp
, &uu
, NULL
))
515 for (agno
= 0; agno
< mp
->m_sb
.sb_agcount
; agno
++)
516 if (!do_uuid(agno
, &uu
)) {
517 dbprintf(_("failed to set UUID in AG %d\n"), agno
);
521 platform_uuid_unparse(&uu
, bp
);
522 dbprintf(_("new UUID = %s\n"), bp
);
525 } else { /* READ+CHECK UUID */
527 for (agno
= 0; agno
< mp
->m_sb
.sb_agcount
; agno
++) {
528 uup
= do_uuid(agno
, NULL
);
530 dbprintf(_("failed to read UUID from AG %d\n"),
535 if (memcmp(&uu
, uup
, sizeof(uuid_t
))) {
536 dbprintf(_("warning: UUID in AG %d "
537 "differs to the primary SB\n"),
542 memcpy(&uu
, uup
, sizeof(uuid_t
));
545 if (mp
->m_sb
.sb_logstart
) {
546 if (x
.log
.dev
&& x
.log
.dev
!= x
.data
.dev
)
547 dbprintf(_("warning - external log specified "
548 "for FS with an internal log\n"));
549 } else if (!x
.log
.dev
|| (x
.log
.dev
== x
.data
.dev
)) {
550 dbprintf(_("warning - no external log specified "
551 "for FS with an external log\n"));
554 platform_uuid_unparse(&uu
, bp
);
555 dbprintf(_("UUID = %s\n"), bp
);
567 " write/print FS label\n"
571 " 'label' - print label\n"
572 " 'label 123456789012' - write label\n"
573 " 'label --' - write an empty label\n"
575 "The print function checks the label in each SB and will warn if the labels\n"
576 "differ between AGs. The write commands will set the label in all AGs to the\n"
577 "specified value. The maximum length of a label is 12 characters - use of a\n"
578 "longer label will result in truncation and a warning will be issued.\n"
588 size_t len
= strlen(label
);
590 if (len
> XFSLABEL_MAX
) {
592 dbprintf(_("%s: truncating label length from %d to %d\n"),
593 progname
, (int)len
, XFSLABEL_MAX
);
597 (strcmp(label
, "\"\"") == 0 ||
598 strcmp(label
, "''") == 0 ||
599 strcmp(label
, "--") == 0) )
600 label
[0] = label
[1] = '\0';
605 do_label(xfs_agnumber_t agno
, char *label
)
609 static char lbl
[sizeof(tsb
.sb_fname
) + 1];
611 if (!get_sb(agno
, &tsb
))
614 memset(&lbl
[0], 0, sizeof(lbl
));
616 if (!label
) { /* get label */
618 memcpy(&lbl
[0], &tsb
.sb_fname
, sizeof(tsb
.sb_fname
));
622 len
= check_label(label
, agno
== 0);
623 memset(&tsb
.sb_fname
, 0, sizeof(tsb
.sb_fname
));
624 memcpy(&tsb
.sb_fname
, label
, len
);
625 memcpy(&lbl
[0], &tsb
.sb_fname
, sizeof(tsb
.sb_fname
));
626 libxfs_sb_to_disk(iocur_top
->data
, &tsb
);
628 memcpy(&mp
->m_sb
.sb_fname
, &tsb
.sb_fname
, XFSLABEL_MAX
);
641 if (argc
!= 1 && argc
!= 2) {
642 dbprintf(_("invalid parameters\n"));
646 if (argc
== 2) { /* WRITE LABEL */
648 if ((x
.flags
& LIBXFS_ISREADONLY
) || !expert_mode
) {
649 dbprintf(_("%s: not in expert mode, writing disabled\n"),
654 if (xfs_sb_version_needsrepair(&mp
->m_sb
)) {
655 dbprintf(_("%s: filesystem needs xfs_repair\n"),
660 if (check_rtsb(mp
)) {
665 dbprintf(_("writing all SBs\n"));
666 if (update_rtsb(mp
, NULL
, argv
[1]))
668 for (ag
= 0; ag
< mp
->m_sb
.sb_agcount
; ag
++)
669 if ((p
= do_label(ag
, argv
[1])) == NULL
) {
670 dbprintf(_("failed to set label in AG %d\n"), ag
);
673 dbprintf(_("new label = \"%s\"\n"), p
);
675 } else { /* READ LABEL */
677 for (ag
= 0; ag
< mp
->m_sb
.sb_agcount
; ag
++) {
678 p
= do_label(ag
, NULL
);
680 dbprintf(_("failed to read label in AG %d\n"), ag
);
684 memcpy(&sb
.sb_fname
, p
, sizeof(sb
.sb_fname
));
685 else if (memcmp(&sb
.sb_fname
, p
, sizeof(sb
.sb_fname
)))
686 dbprintf(_("warning: AG %d label differs\n"), ag
);
688 dbprintf(_("label = \"%s\"\n"), p
);
699 " set/print feature bits in sb version\n"
703 " 'version' - print current feature bits\n"
704 " 'version extflg' - enable unwritten extents\n"
705 " 'version attr1' - enable v1 inline extended attributes\n"
706 " 'version attr2' - enable v2 inline extended attributes\n"
707 " 'version log2' - enable v2 log format\n"
709 "The version function prints currently enabled features for a filesystem\n"
710 "according to the version field of its primary superblock.\n"
711 "It can also be used to enable selected features, such as support for\n"
712 "unwritten extents. The updated version is written into all AGs.\n"
718 do_version(xfs_agnumber_t agno
, uint16_t version
, uint32_t features
)
722 if (!get_sb(agno
, &tsb
))
725 if (xfs_sb_has_mismatched_features2(&tsb
)) {
726 dbprintf(_("Superblock has mismatched features2 fields, "
727 "skipping modification\n"));
731 if ((version
& XFS_SB_VERSION_LOGV2BIT
) &&
732 !xfs_sb_version_haslogv2(&tsb
)) {
736 tsb
.sb_versionnum
= version
;
737 tsb
.sb_features2
= features
;
738 tsb
.sb_bad_features2
= features
;
739 libxfs_sb_to_disk(iocur_top
->data
, &tsb
);
746 struct xfs_mount
*mp
)
750 if (XFS_SB_VERSION_NUM(&mp
->m_sb
) == XFS_SB_VERSION_1
)
752 else if (XFS_SB_VERSION_NUM(&mp
->m_sb
) == XFS_SB_VERSION_2
)
754 else if (XFS_SB_VERSION_NUM(&mp
->m_sb
) == XFS_SB_VERSION_3
)
756 else if (XFS_SB_VERSION_NUM(&mp
->m_sb
) == XFS_SB_VERSION_4
)
758 else if (XFS_SB_VERSION_NUM(&mp
->m_sb
) == XFS_SB_VERSION_5
)
762 * We assume the state of these features now, so macros don't exist for
765 if (xfs_has_nlink(mp
))
767 if (mp
->m_sb
.sb_versionnum
& XFS_SB_VERSION_SHAREDBIT
)
768 strcat(s
, ",SHARED");
769 if (mp
->m_sb
.sb_versionnum
& XFS_SB_VERSION_DIRV2BIT
)
772 if (xfs_has_attr(mp
))
774 if (xfs_has_quota(mp
))
776 if (xfs_has_align(mp
))
778 if (xfs_has_dalign(mp
))
779 strcat(s
, ",DALIGN");
780 if (xfs_has_logv2(mp
))
782 /* This feature is required now as well */
783 if (xfs_has_extflg(mp
))
784 strcat(s
, ",EXTFLG");
785 if (xfs_has_sector(mp
))
786 strcat(s
, ",SECTOR");
787 if (xfs_has_asciici(mp
))
788 strcat(s
, ",ASCII_CI");
789 if (mp
->m_sb
.sb_versionnum
& XFS_SB_VERSION_MOREBITSBIT
)
790 strcat(s
, ",MOREBITS");
791 if (xfs_has_attr2(mp
))
793 if (xfs_has_lazysbcount(mp
))
794 strcat(s
, ",LAZYSBCOUNT");
795 if (xfs_has_projid32(mp
))
796 strcat(s
, ",PROJID32BIT");
799 if (xfs_has_ftype(mp
))
801 if (xfs_has_finobt(mp
))
802 strcat(s
, ",FINOBT");
803 if (xfs_has_sparseinodes(mp
))
804 strcat(s
, ",SPARSE_INODES");
805 if (xfs_has_metauuid(mp
))
806 strcat(s
, ",META_UUID");
807 if (xfs_has_rmapbt(mp
))
808 strcat(s
, ",RMAPBT");
809 if (xfs_has_reflink(mp
))
810 strcat(s
, ",REFLINK");
811 if (xfs_has_inobtcounts(mp
))
812 strcat(s
, ",INOBTCNT");
813 if (xfs_has_bigtime(mp
))
814 strcat(s
, ",BIGTIME");
815 if (xfs_has_needsrepair(mp
))
816 strcat(s
, ",NEEDSREPAIR");
817 if (xfs_has_large_extent_counts(mp
))
818 strcat(s
, ",NREXT64");
819 if (xfs_has_exchange_range(mp
))
820 strcat(s
, ",EXCHANGE");
821 if (xfs_has_parent(mp
))
822 strcat(s
, ",PARENT");
823 if (xfs_has_metadir(mp
))
824 strcat(s
, ",METADIR");
829 * XXX: this only supports reading and writing to version 4 superblock fields.
830 * V5 superblocks always define certain V4 feature bits - they are blocked from
831 * being changed if a V5 sb is detected, but otherwise v5 superblock features
832 * are not handled here.
839 uint16_t version
= 0;
840 uint32_t features
= 0;
841 unsigned long old_mfeatures
= 0;
844 if (argc
== 2) { /* WRITE VERSION */
846 if ((x
.flags
& LIBXFS_ISREADONLY
) || !expert_mode
) {
847 dbprintf(_("%s: not in expert mode, writing disabled\n"),
852 /* Logic here derived from the IRIX xfs_chver(1M) script. */
853 if (!strcasecmp(argv
[1], "extflg")) {
854 switch (XFS_SB_VERSION_NUM(&mp
->m_sb
)) {
855 case XFS_SB_VERSION_1
:
856 version
= 0x0004 | XFS_SB_VERSION_EXTFLGBIT
;
858 case XFS_SB_VERSION_2
:
859 version
= 0x0014 | XFS_SB_VERSION_EXTFLGBIT
;
861 case XFS_SB_VERSION_3
:
862 version
= 0x0034 | XFS_SB_VERSION_EXTFLGBIT
;
864 case XFS_SB_VERSION_4
:
865 if (mp
->m_sb
.sb_versionnum
&
866 XFS_SB_VERSION_EXTFLGBIT
)
868 _("unwritten extents flag is already enabled\n"));
870 version
= mp
->m_sb
.sb_versionnum
|
871 XFS_SB_VERSION_EXTFLGBIT
;
873 case XFS_SB_VERSION_5
:
875 _("unwritten extents always enabled for v5 superblocks.\n"));
878 } else if (!strcasecmp(argv
[1], "log2")) {
879 switch (XFS_SB_VERSION_NUM(&mp
->m_sb
)) {
880 case XFS_SB_VERSION_1
:
881 version
= 0x0004 | XFS_SB_VERSION_LOGV2BIT
;
883 case XFS_SB_VERSION_2
:
884 version
= 0x0014 | XFS_SB_VERSION_LOGV2BIT
;
886 case XFS_SB_VERSION_3
:
887 version
= 0x0034 | XFS_SB_VERSION_LOGV2BIT
;
889 case XFS_SB_VERSION_4
:
890 if (xfs_has_logv2(mp
))
892 _("version 2 log format is already in use\n"));
894 version
= mp
->m_sb
.sb_versionnum
|
895 XFS_SB_VERSION_LOGV2BIT
;
897 case XFS_SB_VERSION_5
:
899 _("Version 2 logs always enabled for v5 superblocks.\n"));
902 } else if (XFS_SB_VERSION_NUM(&mp
->m_sb
) == XFS_SB_VERSION_5
) {
904 _("%s: Cannot change %s on v5 superblocks.\n"),
907 } else if (!strcasecmp(argv
[1], "attr1")) {
909 if (xfs_has_attr2(mp
)) {
910 if (!(mp
->m_sb
.sb_features2
&=
911 ~XFS_SB_VERSION2_ATTR2BIT
))
912 mp
->m_sb
.sb_versionnum
&=
913 ~XFS_SB_VERSION_MOREBITSBIT
;
915 xfs_sb_version_addattr(&mp
->m_sb
);
916 version
= mp
->m_sb
.sb_versionnum
;
917 features
= mp
->m_sb
.sb_features2
;
918 } else if (!strcasecmp(argv
[1], "attr2")) {
919 xfs_sb_version_addattr(&mp
->m_sb
);
920 xfs_sb_version_addattr2(&mp
->m_sb
);
921 version
= mp
->m_sb
.sb_versionnum
;
922 features
= mp
->m_sb
.sb_features2
;
923 } else if (!strcasecmp(argv
[1], "projid32bit")) {
924 xfs_sb_version_addprojid32(&mp
->m_sb
);
925 version
= mp
->m_sb
.sb_versionnum
;
926 features
= mp
->m_sb
.sb_features2
;
928 dbprintf(_("%s: invalid version change command \"%s\"\n"),
934 dbprintf(_("writing all SBs\n"));
935 for (ag
= 0; ag
< mp
->m_sb
.sb_agcount
; ag
++)
936 if (!do_version(ag
, version
, features
)) {
937 dbprintf(_("failed to set versionnum "
941 mp
->m_sb
.sb_versionnum
= version
;
942 mp
->m_sb
.sb_features2
= features
;
943 mp
->m_features
&= ~XFS_FEAT_ATTR2
;
944 mp
->m_features
|= libxfs_sb_version_to_features(&mp
->m_sb
);
948 if (argc
== 3) { /* VERSIONNUM + FEATURES2 */
951 version
= mp
->m_sb
.sb_versionnum
;
952 features
= mp
->m_sb
.sb_features2
;
953 mp
->m_sb
.sb_versionnum
= strtoul(argv
[1], &sp
, 0);
954 mp
->m_sb
.sb_features2
= strtoul(argv
[2], &sp
, 0);
955 old_mfeatures
= mp
->m_features
;
956 mp
->m_features
= libxfs_sb_version_to_features(&mp
->m_sb
);
959 dbprintf(_("versionnum [0x%x+0x%x] = %s\n"), mp
->m_sb
.sb_versionnum
,
960 mp
->m_sb
.sb_features2
, version_string(mp
));
962 if (argc
== 3) { /* now reset... */
963 mp
->m_sb
.sb_versionnum
= version
;
964 mp
->m_sb
.sb_features2
= features
;
965 mp
->m_features
= old_mfeatures
;