2 * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
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
7 * published by the Free Software Foundation.
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.
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
32 #define uuid_equal(s,d) (platform_uuid_compare((s),(d)) == 0)
34 static int sb_f(int argc
, char **argv
);
35 static void sb_help(void);
36 static int uuid_f(int argc
, char **argv
);
37 static void uuid_help(void);
38 static int label_f(int argc
, char **argv
);
39 static void label_help(void);
40 static int version_f(int argc
, char **argv
);
41 static void version_help(void);
43 static const cmdinfo_t sb_cmd
=
44 { "sb", NULL
, sb_f
, 0, 1, 1, N_("[agno]"),
45 N_("set current address to sb header"), sb_help
};
46 static const cmdinfo_t uuid_cmd
=
47 { "uuid", NULL
, uuid_f
, 0, 1, 1, N_("[uuid]"),
48 N_("write/print FS uuid"), uuid_help
};
49 static const cmdinfo_t label_cmd
=
50 { "label", NULL
, label_f
, 0, 1, 1, N_("[label]"),
51 N_("write/print FS label"), label_help
};
52 static const cmdinfo_t version_cmd
=
53 { "version", NULL
, version_f
, 0, -1, 1, N_("[feature | [vnum fnum]]"),
54 N_("set feature bit(s) in the sb version field"), version_help
};
60 add_command(&uuid_cmd
);
61 add_command(&label_cmd
);
62 add_command(&version_cmd
);
65 #define OFF(f) bitize(offsetof(xfs_sb_t, sb_ ## f))
66 #define SZC(f) szcount(xfs_sb_t, sb_ ## f)
67 const field_t sb_flds
[] = {
68 { "magicnum", FLDT_UINT32X
, OI(OFF(magicnum
)), C1
, 0, TYP_NONE
},
69 { "blocksize", FLDT_UINT32D
, OI(OFF(blocksize
)), C1
, 0, TYP_NONE
},
70 { "dblocks", FLDT_DRFSBNO
, OI(OFF(dblocks
)), C1
, 0, TYP_NONE
},
71 { "rblocks", FLDT_DRFSBNO
, OI(OFF(rblocks
)), C1
, 0, TYP_NONE
},
72 { "rextents", FLDT_DRTBNO
, OI(OFF(rextents
)), C1
, 0, TYP_NONE
},
73 { "uuid", FLDT_UUID
, OI(OFF(uuid
)), C1
, 0, TYP_NONE
},
74 { "logstart", FLDT_DFSBNO
, OI(OFF(logstart
)), C1
, 0, TYP_LOG
},
75 { "rootino", FLDT_INO
, OI(OFF(rootino
)), C1
, 0, TYP_INODE
},
76 { "rbmino", FLDT_INO
, OI(OFF(rbmino
)), C1
, 0, TYP_INODE
},
77 { "rsumino", FLDT_INO
, OI(OFF(rsumino
)), C1
, 0, TYP_INODE
},
78 { "rextsize", FLDT_AGBLOCK
, OI(OFF(rextsize
)), C1
, 0, TYP_NONE
},
79 { "agblocks", FLDT_AGBLOCK
, OI(OFF(agblocks
)), C1
, 0, TYP_NONE
},
80 { "agcount", FLDT_AGNUMBER
, OI(OFF(agcount
)), C1
, 0, TYP_NONE
},
81 { "rbmblocks", FLDT_EXTLEN
, OI(OFF(rbmblocks
)), C1
, 0, TYP_NONE
},
82 { "logblocks", FLDT_EXTLEN
, OI(OFF(logblocks
)), C1
, 0, TYP_NONE
},
83 { "versionnum", FLDT_UINT16X
, OI(OFF(versionnum
)), C1
, 0, TYP_NONE
},
84 { "sectsize", FLDT_UINT16D
, OI(OFF(sectsize
)), C1
, 0, TYP_NONE
},
85 { "inodesize", FLDT_UINT16D
, OI(OFF(inodesize
)), C1
, 0, TYP_NONE
},
86 { "inopblock", FLDT_UINT16D
, OI(OFF(inopblock
)), C1
, 0, TYP_NONE
},
87 { "fname", FLDT_CHARNS
, OI(OFF(fname
)), CI(SZC(fname
)), 0, TYP_NONE
},
88 { "blocklog", FLDT_UINT8D
, OI(OFF(blocklog
)), C1
, 0, TYP_NONE
},
89 { "sectlog", FLDT_UINT8D
, OI(OFF(sectlog
)), C1
, 0, TYP_NONE
},
90 { "inodelog", FLDT_UINT8D
, OI(OFF(inodelog
)), C1
, 0, TYP_NONE
},
91 { "inopblog", FLDT_UINT8D
, OI(OFF(inopblog
)), C1
, 0, TYP_NONE
},
92 { "agblklog", FLDT_UINT8D
, OI(OFF(agblklog
)), C1
, 0, TYP_NONE
},
93 { "rextslog", FLDT_UINT8D
, OI(OFF(rextslog
)), C1
, 0, TYP_NONE
},
94 { "inprogress", FLDT_UINT8D
, OI(OFF(inprogress
)), C1
, 0, TYP_NONE
},
95 { "imax_pct", FLDT_UINT8D
, OI(OFF(imax_pct
)), C1
, 0, TYP_NONE
},
96 { "icount", FLDT_UINT64D
, OI(OFF(icount
)), C1
, 0, TYP_NONE
},
97 { "ifree", FLDT_UINT64D
, OI(OFF(ifree
)), C1
, 0, TYP_NONE
},
98 { "fdblocks", FLDT_UINT64D
, OI(OFF(fdblocks
)), C1
, 0, TYP_NONE
},
99 { "frextents", FLDT_UINT64D
, OI(OFF(frextents
)), C1
, 0, TYP_NONE
},
100 { "uquotino", FLDT_INO
, OI(OFF(uquotino
)), C1
, 0, TYP_INODE
},
101 { "gquotino", FLDT_INO
, OI(OFF(gquotino
)), C1
, 0, TYP_INODE
},
102 { "qflags", FLDT_UINT16X
, OI(OFF(qflags
)), C1
, 0, TYP_NONE
},
103 { "flags", FLDT_UINT8X
, OI(OFF(flags
)), C1
, 0, TYP_NONE
},
104 { "shared_vn", FLDT_UINT8D
, OI(OFF(shared_vn
)), C1
, 0, TYP_NONE
},
105 { "inoalignmt", FLDT_EXTLEN
, OI(OFF(inoalignmt
)), C1
, 0, TYP_NONE
},
106 { "unit", FLDT_UINT32D
, OI(OFF(unit
)), C1
, 0, TYP_NONE
},
107 { "width", FLDT_UINT32D
, OI(OFF(width
)), C1
, 0, TYP_NONE
},
108 { "dirblklog", FLDT_UINT8D
, OI(OFF(dirblklog
)), C1
, 0, TYP_NONE
},
109 { "logsectlog", FLDT_UINT8D
, OI(OFF(logsectlog
)), C1
, 0, TYP_NONE
},
110 { "logsectsize", FLDT_UINT16D
, OI(OFF(logsectsize
)), C1
, 0, TYP_NONE
},
111 { "logsunit", FLDT_UINT32D
, OI(OFF(logsunit
)), C1
, 0, TYP_NONE
},
112 { "features2", FLDT_UINT32X
, OI(OFF(features2
)), C1
, 0, TYP_NONE
},
113 { "bad_features2", FLDT_UINT32X
, OI(OFF(bad_features2
)),
115 { "features_compat", FLDT_UINT32X
, OI(OFF(features_compat
)),
117 { "features_ro_compat", FLDT_UINT32X
, OI(OFF(features_ro_compat
)),
119 { "features_incompat", FLDT_UINT32X
, OI(OFF(features_incompat
)),
121 { "features_log_incompat", FLDT_UINT32X
, OI(OFF(features_log_incompat
)),
123 { "crc", FLDT_CRC
, OI(OFF(crc
)), C1
, 0, TYP_NONE
},
124 { "spino_align", FLDT_EXTLEN
, OI(OFF(spino_align
)), C1
, 0, TYP_NONE
},
125 { "pquotino", FLDT_INO
, OI(OFF(pquotino
)), C1
, 0, TYP_INODE
},
126 { "lsn", FLDT_UINT64X
, OI(OFF(lsn
)), C1
, 0, TYP_NONE
},
127 { "meta_uuid", FLDT_UUID
, OI(OFF(meta_uuid
)), C1
, 0, TYP_NONE
},
131 const field_t sb_hfld
[] = {
132 { "", FLDT_SB
, OI(0), C1
, 0, TYP_NONE
},
141 " set allocation group superblock\n"
145 " 'sb 7' - set location to 7th allocation group superblock, set type to 'sb'\n"
147 " Located in the first sector of each allocation group, the superblock\n"
148 " contains the base information for the filesystem.\n"
149 " The superblock in allocation group 0 is the primary. The copies in the\n"
150 " remaining allocation groups only serve as backup for filesystem recovery.\n"
151 " The icount/ifree/fdblocks/frextents are only updated in superblock 0.\n"
165 agno
= (xfs_agnumber_t
)strtoul(argv
[1], &p
, 0);
166 if (*p
!= '\0' || agno
>= mp
->m_sb
.sb_agcount
) {
167 dbprintf(_("bad allocation group number %s\n"), argv
[1]);
171 } else if (cur_agno
== NULLAGNUMBER
)
173 ASSERT(typtab
[TYP_SB
].typnm
== TYP_SB
);
174 set_cur(&typtab
[TYP_SB
],
175 XFS_AG_DADDR(mp
, cur_agno
, XFS_SB_DADDR
),
176 XFS_FSS_TO_BB(mp
, 1), DB_RING_ADD
, NULL
);
187 return bitize(mp
->m_sb
.sb_sectsize
);
191 get_sb(xfs_agnumber_t agno
, xfs_sb_t
*sb
)
194 set_cur(&typtab
[TYP_SB
],
195 XFS_AG_DADDR(mp
, agno
, XFS_SB_DADDR
),
196 XFS_FSS_TO_BB(mp
, 1), DB_RING_IGN
, NULL
);
198 if (!iocur_top
->data
) {
199 dbprintf(_("can't read superblock for AG %u\n"), agno
);
204 libxfs_sb_from_disk(sb
, iocur_top
->data
);
206 if (sb
->sb_magicnum
!= XFS_SB_MAGIC
) {
207 dbprintf(_("bad sb magic # %#x in AG %u\n"),
208 sb
->sb_magicnum
, agno
);
211 if (!xfs_sb_good_version(sb
)) {
212 dbprintf(_("bad sb version # %#x in AG %u\n"),
213 sb
->sb_versionnum
, agno
);
216 if (agno
== 0 && sb
->sb_inprogress
!= 0) {
217 dbprintf(_("mkfs not completed successfully\n"));
223 /* workaround craziness in the xlog routines */
224 int xlog_recover_do_trans(struct xlog
*log
, xlog_recover_t
*t
, int p
)
234 if (mp
->m_sb
.sb_logstart
) {
235 if (x
.logdev
&& x
.logdev
!= x
.ddev
) {
236 dbprintf(_("aborting - external log specified for FS "
237 "with an internal log\n"));
241 if (!x
.logdev
|| (x
.logdev
== x
.ddev
)) {
242 dbprintf(_("aborting - no external log specified for FS "
243 "with an external log\n"));
248 libxfs_buftarg_init(mp
, x
.ddev
, x
.logdev
, x
.rtdev
);
250 dirty
= xlog_is_dirty(mp
, mp
->m_log
, &x
, 0);
252 dbprintf(_("ERROR: cannot find log head/tail, run xfs_repair\n"));
254 } else if (dirty
== 1) {
256 "ERROR: The filesystem has valuable metadata changes in a log which needs to\n"
257 "be replayed. Mount the filesystem to replay the log, and unmount it before\n"
258 "re-running %s. If you are unable to mount the filesystem, then use\n"
259 "the xfs_repair -L option to destroy the log and attempt a repair.\n"
260 "Note that destroying the log may cause corruption -- please attempt a mount\n"
261 "of the filesystem before doing this.\n"), progname
);
269 sb_logzero(uuid_t
*uuidp
)
271 int cycle
= XLOG_INIT_CYCLE
;
278 * The log must always move forward on v5 superblocks. Bump it to the
281 if (xfs_sb_version_hascrc(&mp
->m_sb
))
282 cycle
= mp
->m_log
->l_curr_cycle
+ 1;
284 dbprintf(_("Clearing log and setting UUID\n"));
286 error
= libxfs_log_clear(mp
->m_logdev_targp
, NULL
,
287 XFS_FSB_TO_DADDR(mp
, mp
->m_sb
.sb_logstart
),
288 (xfs_extlen_t
)XFS_FSB_TO_BB(mp
, mp
->m_sb
.sb_logblocks
),
290 xfs_sb_version_haslogv2(&mp
->m_sb
) ? 2 : 1,
291 mp
->m_sb
.sb_logsunit
, XLOG_FMT
, cycle
, true);
293 dbprintf(_("ERROR: cannot clear the log\n"));
306 " write/print FS uuid\n"
310 " 'uuid' - print UUID\n"
311 " 'uuid 01234567-0123-0123-0123-0123456789ab' - write UUID\n"
312 " 'uuid generate' - generate and write\n"
313 " 'uuid rewrite' - copy UUID from SB 0\n"
315 "The print function checks the UUID in each SB and will warn if the UUIDs\n"
316 "differ between AGs (the log is not checked). The write commands will\n"
317 "set the uuid in all AGs to either a specified value, a newly generated\n"
318 "value or the value found in the first superblock (SB 0) respectively.\n"
319 "As a side effect of writing the UUID, the log is cleared (which is fine\n"
320 "on a CLEANLY unmounted FS).\n"
326 do_uuid(xfs_agnumber_t agno
, uuid_t
*uuid
)
331 if (!get_sb(agno
, &tsb
))
334 if (!uuid
) { /* get uuid */
335 memcpy(&uu
, &tsb
.sb_uuid
, sizeof(uuid_t
));
340 if (!xfs_sb_version_hascrc(&tsb
))
343 * If we have CRCs, and this UUID differs from that stamped in the
344 * metadata, set the incompat flag and copy the old one to the
345 * metadata-specific location.
347 * If we are setting the user-visible UUID back to match the metadata
348 * UUID, clear the metadata-specific location and the incompat flag.
350 if (!xfs_sb_version_hasmetauuid(&tsb
) &&
351 !uuid_equal(uuid
, &mp
->m_sb
.sb_meta_uuid
)) {
352 mp
->m_sb
.sb_features_incompat
|= XFS_SB_FEAT_INCOMPAT_META_UUID
;
353 tsb
.sb_features_incompat
|= XFS_SB_FEAT_INCOMPAT_META_UUID
;
354 memcpy(&tsb
.sb_meta_uuid
, &tsb
.sb_uuid
, sizeof(uuid_t
));
355 } else if (xfs_sb_version_hasmetauuid(&tsb
) &&
356 uuid_equal(uuid
, &mp
->m_sb
.sb_meta_uuid
)) {
357 memset(&tsb
.sb_meta_uuid
, 0, sizeof(uuid_t
));
358 /* Write those zeros now; it's ignored once we clear the flag */
359 libxfs_sb_to_disk(iocur_top
->data
, &tsb
);
360 mp
->m_sb
.sb_features_incompat
&=
361 ~XFS_SB_FEAT_INCOMPAT_META_UUID
;
362 tsb
.sb_features_incompat
&= ~XFS_SB_FEAT_INCOMPAT_META_UUID
;
366 memcpy(&tsb
.sb_uuid
, uuid
, sizeof(uuid_t
));
367 libxfs_sb_to_disk(iocur_top
->data
, &tsb
);
382 if (argc
!= 1 && argc
!= 2) {
383 dbprintf(_("invalid parameters\n"));
387 if (argc
== 2) { /* WRITE UUID */
389 if ((x
.isreadonly
& LIBXFS_ISREADONLY
) || !expert_mode
) {
390 dbprintf(_("%s: not in expert mode, writing disabled\n"),
395 if (!strcasecmp(argv
[1], "generate")) {
396 platform_uuid_generate(&uu
);
397 } else if (!strcasecmp(argv
[1], "nil")) {
398 platform_uuid_clear(&uu
);
399 } else if (!strcasecmp(argv
[1], "rewrite")) {
400 uup
= do_uuid(0, NULL
);
402 dbprintf(_("failed to read UUID from AG 0\n"));
405 memcpy(&uu
, uup
, sizeof(uuid_t
));
406 platform_uuid_unparse(&uu
, bp
);
407 dbprintf(_("old UUID = %s\n"), bp
);
408 } else if (!strcasecmp(argv
[1], "restore")) {
411 if (!get_sb(0, &tsb
))
414 /* Not set; nothing to do. Success! */
415 if (!xfs_sb_version_hasmetauuid(&tsb
))
418 memcpy(&uu
, mp
->m_sb
.sb_meta_uuid
, sizeof(uuid_t
));
420 if (platform_uuid_parse(argv
[1], &uu
)) {
421 dbprintf(_("invalid UUID\n"));
426 /* clear the log (setting uuid) if it's not dirty */
427 if (!sb_logzero(&uu
))
430 dbprintf(_("writing all SBs\n"));
431 for (agno
= 0; agno
< mp
->m_sb
.sb_agcount
; agno
++)
432 if (!do_uuid(agno
, &uu
)) {
433 dbprintf(_("failed to set UUID in AG %d\n"), agno
);
437 platform_uuid_unparse(&uu
, bp
);
438 dbprintf(_("new UUID = %s\n"), bp
);
441 } else { /* READ+CHECK UUID */
443 for (agno
= 0; agno
< mp
->m_sb
.sb_agcount
; agno
++) {
444 uup
= do_uuid(agno
, NULL
);
446 dbprintf(_("failed to read UUID from AG %d\n"),
451 if (memcmp(&uu
, uup
, sizeof(uuid_t
))) {
452 dbprintf(_("warning: UUID in AG %d "
453 "differs to the primary SB\n"),
458 memcpy(&uu
, uup
, sizeof(uuid_t
));
461 if (mp
->m_sb
.sb_logstart
) {
462 if (x
.logdev
&& x
.logdev
!= x
.ddev
)
463 dbprintf(_("warning - external log specified "
464 "for FS with an internal log\n"));
465 } else if (!x
.logdev
|| (x
.logdev
== x
.ddev
)) {
466 dbprintf(_("warning - no external log specified "
467 "for FS with an external log\n"));
470 platform_uuid_unparse(&uu
, bp
);
471 dbprintf(_("UUID = %s\n"), bp
);
483 " write/print FS label\n"
487 " 'label' - print label\n"
488 " 'label 123456789012' - write label\n"
489 " 'label --' - write an empty label\n"
491 "The print function checks the label in each SB and will warn if the labels\n"
492 "differ between AGs. The write commands will set the label in all AGs to the\n"
493 "specified value. The maximum length of a label is 12 characters - use of a\n"
494 "longer label will result in truncation and a warning will be issued.\n"
500 do_label(xfs_agnumber_t agno
, char *label
)
504 static char lbl
[sizeof(tsb
.sb_fname
) + 1];
506 if (!get_sb(agno
, &tsb
))
509 memset(&lbl
[0], 0, sizeof(lbl
));
511 if (!label
) { /* get label */
513 memcpy(&lbl
[0], &tsb
.sb_fname
, sizeof(tsb
.sb_fname
));
517 if ((len
= strlen(label
)) > sizeof(tsb
.sb_fname
)) {
519 dbprintf(_("%s: truncating label length from %d to %d\n"),
520 progname
, (int)len
, (int)sizeof(tsb
.sb_fname
));
521 len
= sizeof(tsb
.sb_fname
);
524 (strcmp(label
, "\"\"") == 0 ||
525 strcmp(label
, "''") == 0 ||
526 strcmp(label
, "--") == 0) )
527 label
[0] = label
[1] = '\0';
528 memset(&tsb
.sb_fname
, 0, sizeof(tsb
.sb_fname
));
529 memcpy(&tsb
.sb_fname
, label
, len
);
530 memcpy(&lbl
[0], &tsb
.sb_fname
, sizeof(tsb
.sb_fname
));
531 libxfs_sb_to_disk(iocur_top
->data
, &tsb
);
545 if (argc
!= 1 && argc
!= 2) {
546 dbprintf(_("invalid parameters\n"));
550 if (argc
== 2) { /* WRITE LABEL */
552 if ((x
.isreadonly
& LIBXFS_ISREADONLY
) || !expert_mode
) {
553 dbprintf(_("%s: not in expert mode, writing disabled\n"),
558 dbprintf(_("writing all SBs\n"));
559 for (ag
= 0; ag
< mp
->m_sb
.sb_agcount
; ag
++)
560 if ((p
= do_label(ag
, argv
[1])) == NULL
) {
561 dbprintf(_("failed to set label in AG %d\n"), ag
);
564 dbprintf(_("new label = \"%s\"\n"), p
);
566 } else { /* READ LABEL */
568 for (ag
= 0; ag
< mp
->m_sb
.sb_agcount
; ag
++) {
569 p
= do_label(ag
, NULL
);
571 dbprintf(_("failed to read label in AG %d\n"), ag
);
575 memcpy(&sb
.sb_fname
, p
, sizeof(sb
.sb_fname
));
576 else if (memcmp(&sb
.sb_fname
, p
, sizeof(sb
.sb_fname
)))
577 dbprintf(_("warning: AG %d label differs\n"), ag
);
579 dbprintf(_("label = \"%s\"\n"), p
);
590 " set/print feature bits in sb version\n"
594 " 'version' - print current feature bits\n"
595 " 'version extflg' - enable unwritten extents\n"
596 " 'version attr1' - enable v1 inline extended attributes\n"
597 " 'version attr2' - enable v2 inline extended attributes\n"
598 " 'version log2' - enable v2 log format\n"
600 "The version function prints currently enabled features for a filesystem\n"
601 "according to the version field of its primary superblock.\n"
602 "It can also be used to enable selected features, such as support for\n"
603 "unwritten extents. The updated version is written into all AGs.\n"
609 do_version(xfs_agnumber_t agno
, uint16_t version
, uint32_t features
)
613 if (!get_sb(agno
, &tsb
))
616 if (xfs_sb_has_mismatched_features2(&tsb
)) {
617 dbprintf(_("Superblock has mismatched features2 fields, "
618 "skipping modification\n"));
622 if ((version
& XFS_SB_VERSION_LOGV2BIT
) &&
623 !xfs_sb_version_haslogv2(&tsb
)) {
627 tsb
.sb_versionnum
= version
;
628 tsb
.sb_features2
= features
;
629 tsb
.sb_bad_features2
= features
;
630 libxfs_sb_to_disk(iocur_top
->data
, &tsb
);
641 if (XFS_SB_VERSION_NUM(sbp
) == XFS_SB_VERSION_1
)
643 else if (XFS_SB_VERSION_NUM(sbp
) == XFS_SB_VERSION_2
)
645 else if (XFS_SB_VERSION_NUM(sbp
) == XFS_SB_VERSION_3
)
647 else if (XFS_SB_VERSION_NUM(sbp
) == XFS_SB_VERSION_4
)
649 else if (XFS_SB_VERSION_NUM(sbp
) == XFS_SB_VERSION_5
)
653 * We assume the state of these features now, so macros don't exist for
656 if (sbp
->sb_versionnum
& XFS_SB_VERSION_NLINKBIT
)
658 if (sbp
->sb_versionnum
& XFS_SB_VERSION_SHAREDBIT
)
659 strcat(s
, ",SHARED");
660 if (sbp
->sb_versionnum
& XFS_SB_VERSION_DIRV2BIT
)
663 if (xfs_sb_version_hasattr(sbp
))
665 if (xfs_sb_version_hasquota(sbp
))
667 if (xfs_sb_version_hasalign(sbp
))
669 if (xfs_sb_version_hasdalign(sbp
))
670 strcat(s
, ",DALIGN");
671 if (xfs_sb_version_haslogv2(sbp
))
673 if (xfs_sb_version_hasextflgbit(sbp
))
674 strcat(s
, ",EXTFLG");
675 if (xfs_sb_version_hassector(sbp
))
676 strcat(s
, ",SECTOR");
677 if (xfs_sb_version_hasasciici(sbp
))
678 strcat(s
, ",ASCII_CI");
679 if (xfs_sb_version_hasmorebits(sbp
))
680 strcat(s
, ",MOREBITS");
681 if (xfs_sb_version_hasattr2(sbp
))
683 if (xfs_sb_version_haslazysbcount(sbp
))
684 strcat(s
, ",LAZYSBCOUNT");
685 if (xfs_sb_version_hasprojid32bit(sbp
))
686 strcat(s
, ",PROJID32BIT");
687 if (xfs_sb_version_hascrc(sbp
))
689 if (xfs_sb_version_hasftype(sbp
))
691 if (xfs_sb_version_hasfinobt(sbp
))
692 strcat(s
, ",FINOBT");
693 if (xfs_sb_version_hassparseinodes(sbp
))
694 strcat(s
, ",SPARSE_INODES");
695 if (xfs_sb_version_hasmetauuid(sbp
))
696 strcat(s
, ",META_UUID");
697 if (xfs_sb_version_hasreflink(sbp
))
698 strcat(s
, ",REFLINK");
703 * XXX: this only supports reading and writing to version 4 superblock fields.
704 * V5 superblocks always define certain V4 feature bits - they are blocked from
705 * being changed if a V5 sb is detected, but otherwise v5 superblock features
706 * are not handled here.
713 uint16_t version
= 0;
714 uint32_t features
= 0;
717 if (argc
== 2) { /* WRITE VERSION */
719 if ((x
.isreadonly
& LIBXFS_ISREADONLY
) || !expert_mode
) {
720 dbprintf(_("%s: not in expert mode, writing disabled\n"),
725 /* Logic here derived from the IRIX xfs_chver(1M) script. */
726 if (!strcasecmp(argv
[1], "extflg")) {
727 switch (XFS_SB_VERSION_NUM(&mp
->m_sb
)) {
728 case XFS_SB_VERSION_1
:
729 version
= 0x0004 | XFS_SB_VERSION_EXTFLGBIT
;
731 case XFS_SB_VERSION_2
:
732 version
= 0x0014 | XFS_SB_VERSION_EXTFLGBIT
;
734 case XFS_SB_VERSION_3
:
735 version
= 0x0034 | XFS_SB_VERSION_EXTFLGBIT
;
737 case XFS_SB_VERSION_4
:
738 if (xfs_sb_version_hasextflgbit(&mp
->m_sb
))
740 _("unwritten extents flag is already enabled\n"));
742 version
= mp
->m_sb
.sb_versionnum
|
743 XFS_SB_VERSION_EXTFLGBIT
;
745 case XFS_SB_VERSION_5
:
747 _("unwritten extents always enabled for v5 superblocks.\n"));
750 } else if (!strcasecmp(argv
[1], "log2")) {
751 switch (XFS_SB_VERSION_NUM(&mp
->m_sb
)) {
752 case XFS_SB_VERSION_1
:
753 version
= 0x0004 | XFS_SB_VERSION_LOGV2BIT
;
755 case XFS_SB_VERSION_2
:
756 version
= 0x0014 | XFS_SB_VERSION_LOGV2BIT
;
758 case XFS_SB_VERSION_3
:
759 version
= 0x0034 | XFS_SB_VERSION_LOGV2BIT
;
761 case XFS_SB_VERSION_4
:
762 if (xfs_sb_version_haslogv2(&mp
->m_sb
))
764 _("version 2 log format is already in use\n"));
766 version
= mp
->m_sb
.sb_versionnum
|
767 XFS_SB_VERSION_LOGV2BIT
;
769 case XFS_SB_VERSION_5
:
771 _("Version 2 logs always enabled for v5 superblocks.\n"));
774 } else if (XFS_SB_VERSION_NUM(&mp
->m_sb
) == XFS_SB_VERSION_5
) {
776 _("%s: Cannot change %s on v5 superblocks.\n"),
779 } else if (!strcasecmp(argv
[1], "attr1")) {
781 if (xfs_sb_version_hasattr2(&mp
->m_sb
)) {
782 if (!(mp
->m_sb
.sb_features2
&=
783 ~XFS_SB_VERSION2_ATTR2BIT
))
784 mp
->m_sb
.sb_versionnum
&=
785 ~XFS_SB_VERSION_MOREBITSBIT
;
787 xfs_sb_version_addattr(&mp
->m_sb
);
788 version
= mp
->m_sb
.sb_versionnum
;
789 features
= mp
->m_sb
.sb_features2
;
790 } else if (!strcasecmp(argv
[1], "attr2")) {
791 xfs_sb_version_addattr(&mp
->m_sb
);
792 xfs_sb_version_addattr2(&mp
->m_sb
);
793 version
= mp
->m_sb
.sb_versionnum
;
794 features
= mp
->m_sb
.sb_features2
;
795 } else if (!strcasecmp(argv
[1], "projid32bit")) {
796 xfs_sb_version_addprojid32bit(&mp
->m_sb
);
797 version
= mp
->m_sb
.sb_versionnum
;
798 features
= mp
->m_sb
.sb_features2
;
800 dbprintf(_("%s: invalid version change command \"%s\"\n"),
806 dbprintf(_("writing all SBs\n"));
807 for (ag
= 0; ag
< mp
->m_sb
.sb_agcount
; ag
++)
808 if (!do_version(ag
, version
, features
)) {
809 dbprintf(_("failed to set versionnum "
813 mp
->m_sb
.sb_versionnum
= version
;
814 mp
->m_sb
.sb_features2
= features
;
818 if (argc
== 3) { /* VERSIONNUM + FEATURES2 */
821 version
= mp
->m_sb
.sb_versionnum
;
822 features
= mp
->m_sb
.sb_features2
;
823 mp
->m_sb
.sb_versionnum
= strtoul(argv
[1], &sp
, 0);
824 mp
->m_sb
.sb_features2
= strtoul(argv
[2], &sp
, 0);
827 dbprintf(_("versionnum [0x%x+0x%x] = %s\n"), mp
->m_sb
.sb_versionnum
,
828 mp
->m_sb
.sb_features2
, version_string(&mp
->m_sb
));
830 if (argc
== 3) { /* now reset... */
831 mp
->m_sb
.sb_versionnum
= version
;
832 mp
->m_sb
.sb_features2
= features
;