]>
git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - db/sb.c
2 * Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved.
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of version 2 of the GNU General Public License as
6 * published by the Free Software Foundation.
8 * This program is distributed in the hope that it would be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 * Further, this software is distributed without any warranty that it is
13 * free of the rightful claim of any third person regarding infringement
14 * or the like. Any license provided herein, whether implied or
15 * otherwise, applies only to this software file. Patent licenses, if
16 * any, provided herein do not apply to combinations of this program with
17 * other software, or any other product whatsoever.
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write the Free Software Foundation, Inc., 59
21 * Temple Place - Suite 330, Boston MA 02111-1307, USA.
23 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24 * Mountain View, CA 94043, or:
28 * For further information regarding this notice, see:
30 * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
46 static int sb_f(int argc
, char **argv
);
47 static void sb_help(void);
48 static int uuid_f(int argc
, char **argv
);
49 static void uuid_help(void);
50 static int label_f(int argc
, char **argv
);
51 static void label_help(void);
52 static int version_f(int argc
, char **argv
);
53 static void version_help(void);
55 static const cmdinfo_t sb_cmd
=
56 { "sb", NULL
, sb_f
, 0, 1, 1, "[agno]",
57 "set current address to sb header", sb_help
};
58 static const cmdinfo_t uuid_cmd
=
59 { "uuid", NULL
, uuid_f
, 0, 1, 1, "[uuid]",
60 "write/print FS uuid", uuid_help
};
61 static const cmdinfo_t label_cmd
=
62 { "label", NULL
, label_f
, 0, 1, 1, "[label]",
63 "write/print FS label", label_help
};
64 static const cmdinfo_t version_cmd
=
65 { "version", NULL
, version_f
, 0, 1, 1, "[feature]",
66 "set feature bit(s) in the sb version field", version_help
};
72 add_command(&uuid_cmd
);
73 add_command(&label_cmd
);
74 add_command(&version_cmd
);
77 #define OFF(f) bitize(offsetof(xfs_sb_t, sb_ ## f))
78 #define SZC(f) szcount(xfs_sb_t, sb_ ## f)
79 const field_t sb_flds
[] = {
80 { "magicnum", FLDT_UINT32X
, OI(OFF(magicnum
)), C1
, 0, TYP_NONE
},
81 { "blocksize", FLDT_UINT32D
, OI(OFF(blocksize
)), C1
, 0, TYP_NONE
},
82 { "dblocks", FLDT_DRFSBNO
, OI(OFF(dblocks
)), C1
, 0, TYP_NONE
},
83 { "rblocks", FLDT_DRFSBNO
, OI(OFF(rblocks
)), C1
, 0, TYP_NONE
},
84 { "rextents", FLDT_DRTBNO
, OI(OFF(rextents
)), C1
, 0, TYP_NONE
},
85 { "uuid", FLDT_UUID
, OI(OFF(uuid
)), C1
, 0, TYP_NONE
},
86 { "logstart", FLDT_DFSBNO
, OI(OFF(logstart
)), C1
, 0, TYP_LOG
},
87 { "rootino", FLDT_INO
, OI(OFF(rootino
)), C1
, 0, TYP_INODE
},
88 { "rbmino", FLDT_INO
, OI(OFF(rbmino
)), C1
, 0, TYP_INODE
},
89 { "rsumino", FLDT_INO
, OI(OFF(rsumino
)), C1
, 0, TYP_INODE
},
90 { "rextsize", FLDT_AGBLOCK
, OI(OFF(rextsize
)), C1
, 0, TYP_NONE
},
91 { "agblocks", FLDT_AGBLOCK
, OI(OFF(agblocks
)), C1
, 0, TYP_NONE
},
92 { "agcount", FLDT_AGNUMBER
, OI(OFF(agcount
)), C1
, 0, TYP_NONE
},
93 { "rbmblocks", FLDT_EXTLEN
, OI(OFF(rbmblocks
)), C1
, 0, TYP_NONE
},
94 { "logblocks", FLDT_EXTLEN
, OI(OFF(logblocks
)), C1
, 0, TYP_NONE
},
95 { "versionnum", FLDT_UINT16X
, OI(OFF(versionnum
)), C1
, 0, TYP_NONE
},
96 { "sectsize", FLDT_UINT16D
, OI(OFF(sectsize
)), C1
, 0, TYP_NONE
},
97 { "inodesize", FLDT_UINT16D
, OI(OFF(inodesize
)), C1
, 0, TYP_NONE
},
98 { "inopblock", FLDT_UINT16D
, OI(OFF(inopblock
)), C1
, 0, TYP_NONE
},
99 { "fname", FLDT_CHARNS
, OI(OFF(fname
)), CI(SZC(fname
)), 0, TYP_NONE
},
100 { "blocklog", FLDT_UINT8D
, OI(OFF(blocklog
)), C1
, 0, TYP_NONE
},
101 { "sectlog", FLDT_UINT8D
, OI(OFF(sectlog
)), C1
, 0, TYP_NONE
},
102 { "inodelog", FLDT_UINT8D
, OI(OFF(inodelog
)), C1
, 0, TYP_NONE
},
103 { "inopblog", FLDT_UINT8D
, OI(OFF(inopblog
)), C1
, 0, TYP_NONE
},
104 { "agblklog", FLDT_UINT8D
, OI(OFF(agblklog
)), C1
, 0, TYP_NONE
},
105 { "rextslog", FLDT_UINT8D
, OI(OFF(rextslog
)), C1
, 0, TYP_NONE
},
106 { "inprogress", FLDT_UINT8D
, OI(OFF(inprogress
)), C1
, 0, TYP_NONE
},
107 { "imax_pct", FLDT_UINT8D
, OI(OFF(imax_pct
)), C1
, 0, TYP_NONE
},
108 { "icount", FLDT_UINT64D
, OI(OFF(icount
)), C1
, 0, TYP_NONE
},
109 { "ifree", FLDT_UINT64D
, OI(OFF(ifree
)), C1
, 0, TYP_NONE
},
110 { "fdblocks", FLDT_UINT64D
, OI(OFF(fdblocks
)), C1
, 0, TYP_NONE
},
111 { "frextents", FLDT_UINT64D
, OI(OFF(frextents
)), C1
, 0, TYP_NONE
},
112 { "uquotino", FLDT_INO
, OI(OFF(uquotino
)), C1
, 0, TYP_INODE
},
113 { "gquotino", FLDT_INO
, OI(OFF(gquotino
)), C1
, 0, TYP_INODE
},
114 { "qflags", FLDT_UINT16X
, OI(OFF(qflags
)), C1
, 0, TYP_NONE
},
115 { "flags", FLDT_UINT8X
, OI(OFF(flags
)), C1
, 0, TYP_NONE
},
116 { "shared_vn", FLDT_UINT8D
, OI(OFF(shared_vn
)), C1
, 0, TYP_NONE
},
117 { "inoalignmt", FLDT_EXTLEN
, OI(OFF(inoalignmt
)), C1
, 0, TYP_NONE
},
118 { "unit", FLDT_UINT32D
, OI(OFF(unit
)), C1
, 0, TYP_NONE
},
119 { "width", FLDT_UINT32D
, OI(OFF(width
)), C1
, 0, TYP_NONE
},
120 { "dirblklog", FLDT_UINT8D
, OI(OFF(dirblklog
)), C1
, 0, TYP_NONE
},
121 { "logsectlog", FLDT_UINT8D
, OI(OFF(logsectlog
)), C1
, 0, TYP_NONE
},
122 { "logsectsize", FLDT_UINT16D
, OI(OFF(logsectsize
)), C1
, 0, TYP_NONE
},
123 { "logsunit", FLDT_UINT32D
, OI(OFF(logsunit
)), C1
, 0, TYP_NONE
},
127 const field_t sb_hfld
[] = {
128 { "", FLDT_SB
, OI(0), C1
, 0, TYP_NONE
},
137 " set allocation group superblock\n"
141 " 'sb 7' - set location to 7th allocation group superblock, set type to 'sb'\n"
143 " Located in the first sector of each allocation group, the superblock\n"
144 " contains the base information for the filesystem.\n"
145 " The superblock in allocation group 0 is the primary. The copies in the\n"
146 " remaining allocation groups only serve as backup for filesystem recovery.\n"
147 " The icount/ifree/fdblocks/frextents are only updated in superblock 0.\n"
161 agno
= (xfs_agnumber_t
)strtoul(argv
[1], &p
, 0);
162 if (*p
!= '\0' || agno
>= mp
->m_sb
.sb_agcount
) {
163 dbprintf("bad allocation group number %s\n", argv
[1]);
167 } else if (cur_agno
== NULLAGNUMBER
)
169 ASSERT(typtab
[TYP_SB
].typnm
== TYP_SB
);
170 set_cur(&typtab
[TYP_SB
],
171 XFS_AG_DADDR(mp
, cur_agno
, XFS_SB_DADDR
),
172 XFS_FSS_TO_BB(mp
, 1), DB_RING_ADD
, NULL
);
183 return bitize(mp
->m_sb
.sb_sectsize
);
187 get_sb(xfs_agnumber_t agno
, xfs_sb_t
*sb
)
190 set_cur(&typtab
[TYP_SB
],
191 XFS_AG_DADDR(mp
, agno
, XFS_SB_DADDR
),
192 XFS_FSS_TO_BB(mp
, 1), DB_RING_IGN
, NULL
);
194 if (!iocur_top
->data
) {
195 dbprintf("can't read superblock for AG %u\n", agno
);
200 libxfs_xlate_sb(iocur_top
->data
, sb
, 1, ARCH_CONVERT
, XFS_SB_ALL_BITS
);
202 if (sb
->sb_magicnum
!= XFS_SB_MAGIC
) {
203 dbprintf("bad sb magic # %#x in AG %u\n",
204 sb
->sb_magicnum
, agno
);
207 if (!XFS_SB_GOOD_VERSION(sb
)) {
208 dbprintf("bad sb version # %#x in AG %u\n",
209 sb
->sb_versionnum
, agno
);
212 if (agno
== 0 && sb
->sb_inprogress
!= 0) {
213 dbprintf("mkfs not completed successfully\n");
219 /* workaround craziness in the xlog routines */
220 int xlog_recover_do_trans(xlog_t
*log
, xlog_recover_t
*t
, int p
) { return 0; }
223 zero_log(uuid_t
*uuidp
)
226 xfs_daddr_t head_blk
, tail_blk
;
228 if (mp
->m_sb
.sb_logstart
) {
229 if (x
.logdev
&& x
.logdev
!= x
.ddev
) {
230 dbprintf("aborting - external log specified for FS "
231 "with an internal log\n");
235 if (!x
.logdev
|| (x
.logdev
== x
.ddev
)) {
236 dbprintf("aborting - no external log specified for FS "
237 "with an external log\n");
242 memset(&log
, 0, sizeof(log
));
245 x
.logBBsize
= XFS_FSB_TO_BB(mp
, mp
->m_sb
.sb_logblocks
);
246 x
.logBBstart
= XFS_FSB_TO_DADDR(mp
, mp
->m_sb
.sb_logstart
);
247 log
.l_dev
= (mp
->m_sb
.sb_logstart
== 0) ? x
.logdev
: x
.ddev
;
248 log
.l_logsize
= BBTOB(log
.l_logBBsize
);
249 log
.l_logBBsize
= x
.logBBsize
;
250 log
.l_logBBstart
= x
.logBBstart
;
253 if (xlog_find_tail(&log
, &head_blk
, &tail_blk
, 0)) {
254 dbprintf("ERROR: cannot find log head/tail, run xfs_repair\n");
257 if (head_blk
!= tail_blk
) {
259 "ERROR: The filesystem has valuable metadata changes in a log which needs to\n"
260 "be replayed. Mount the filesystem to replay the log, and unmount it before\n"
261 "re-running %s. If you are unable to mount the filesystem, then use\n"
262 "the xfs_repair -L option to destroy the log and attempt a repair.\n"
263 "Note that destroying the log may cause corruption -- please attempt a mount\n"
264 "of the filesystem before doing this.\n", progname
);
268 dbprintf("Clearing log and setting UUID\n");
270 if (libxfs_log_clear(log
.l_dev
,
271 XFS_FSB_TO_DADDR(mp
, mp
->m_sb
.sb_logstart
),
272 (xfs_extlen_t
)XFS_FSB_TO_BB(mp
, mp
->m_sb
.sb_logblocks
),
274 XFS_SB_VERSION_HASLOGV2(&mp
->m_sb
) ? 2 : 1,
275 mp
->m_sb
.sb_logsunit
, XLOG_FMT
)) {
276 dbprintf("ERROR: cannot clear the log\n");
288 " write/print FS uuid\n"
292 " 'uuid' - print UUID\n"
293 " 'uuid 01234567-0123-0123-0123-0123456789ab' - write UUID\n"
294 " 'uuid generate' - generate and write\n"
295 " 'uuid rewrite' - copy UUID from SB 0\n"
297 "The print function checks the UUID in each SB and will warn if the UUIDs\n"
298 "differ between AGs (the log is not checked). The write commands will\n"
299 "set the uuid in all AGs to either a specified value, a newly generated\n"
300 "value or the value found in the first superblock (SB 0) respectively.\n"
301 "As a side effect of writing the UUID, the log is cleared (which is fine\n"
302 "on a CLEANLY unmounted FS).\n"
308 do_uuid(xfs_agnumber_t agno
, uuid_t
*uuid
)
313 if (!get_sb(agno
, &tsb
))
316 if (!uuid
) { /* get uuid */
317 memcpy(&uu
, &tsb
.sb_uuid
, sizeof(uuid_t
));
322 memcpy(&tsb
.sb_uuid
, uuid
, sizeof(uuid_t
));
323 libxfs_xlate_sb(iocur_top
->data
, &tsb
, -1, ARCH_CONVERT
, XFS_SB_UUID
);
338 if (argc
!= 1 && argc
!= 2) {
339 dbprintf("invalid parameters\n");
343 if (argc
== 2) { /* WRITE UUID */
345 if ((x
.isreadonly
& LIBXFS_ISREADONLY
) || !expert_mode
) {
346 dbprintf("%s: not in expert mode, writing disabled\n",
351 if (!strcasecmp(argv
[1], "generate")) {
353 } else if (!strcasecmp(argv
[1], "nil")) {
355 } else if (!strcasecmp(argv
[1], "rewrite")) {
356 uup
= do_uuid(0, NULL
);
358 dbprintf("failed to read UUID from AG 0\n");
361 memcpy(&uu
, *uup
, sizeof(uuid_t
));
362 uuid_unparse(uu
, bp
);
363 dbprintf("old UUID = %s\n", bp
);
365 if (uuid_parse(argv
[1], uu
)) {
366 dbprintf("invalid UUID\n");
371 /* clear the log (setting uuid) if its not dirty */
375 dbprintf("writing all SBs\n");
376 for (agno
= 0; agno
< mp
->m_sb
.sb_agcount
; agno
++)
377 if (!do_uuid(agno
, &uu
)) {
378 dbprintf("failed to set UUID in AG %d\n", agno
);
382 uuid_unparse(uu
, bp
);
383 dbprintf("new UUID = %s\n", bp
);
386 } else { /* READ+CHECK UUID */
388 for (agno
= 0; agno
< mp
->m_sb
.sb_agcount
; agno
++) {
389 uup
= do_uuid(agno
, NULL
);
391 dbprintf("failed to read UUID from AG %d\n",
396 if (memcmp(&uu
, uup
, sizeof(uuid_t
))) {
397 dbprintf("warning: UUID in AG %d "
398 "differs to the primary SB\n",
403 memcpy(uu
, uup
, sizeof(uuid_t
));
406 if (mp
->m_sb
.sb_logstart
) {
407 if (x
.logdev
&& x
.logdev
!= x
.ddev
)
408 dbprintf("warning - external log specified "
409 "for FS with an internal log\n");
410 } else if (!x
.logdev
|| (x
.logdev
== x
.ddev
)) {
411 dbprintf("warning - no external log specified "
412 "for FS with an external log\n");
415 uuid_unparse(uu
, bp
);
416 dbprintf("UUID = %s\n", bp
);
428 " write/print FS label\n"
432 " 'label' - print label\n"
433 " 'label 123456789012' - write label\n"
434 " 'label --' - write an empty label\n"
436 "The print function checks the label in each SB and will warn if the labels\n"
437 "differ between AGs. The write commands will set the label in all AGs to the\n"
438 "specified value. The maximum length of a label is 12 characters - use of a\n"
439 "longer label will result in truncation and a warning will be issued.\n"
445 do_label(xfs_agnumber_t agno
, char *label
)
449 static char lbl
[sizeof(tsb
.sb_fname
) + 1];
451 if (!get_sb(agno
, &tsb
))
454 memset(&lbl
[0], 0, sizeof(lbl
));
456 if (!label
) { /* get label */
458 memcpy(&lbl
[0], &tsb
.sb_fname
, sizeof(tsb
.sb_fname
));
462 if ((len
= strlen(label
)) > sizeof(tsb
.sb_fname
)) {
464 dbprintf("%s: truncating label length from %d to %d\n",
465 progname
, (int)len
, (int)sizeof(tsb
.sb_fname
));
466 len
= sizeof(tsb
.sb_fname
);
469 (strcmp(label
, "\"\"") == 0 ||
470 strcmp(label
, "''") == 0 ||
471 strcmp(label
, "--") == 0) )
472 label
[0] = label
[1] = '\0';
473 memset(&tsb
.sb_fname
, 0, sizeof(tsb
.sb_fname
));
474 memcpy(&tsb
.sb_fname
, label
, len
);
475 memcpy(&lbl
[0], &tsb
.sb_fname
, sizeof(tsb
.sb_fname
));
476 libxfs_xlate_sb(iocur_top
->data
, &tsb
, -1, ARCH_CONVERT
, XFS_SB_FNAME
);
490 if (argc
!= 1 && argc
!= 2) {
491 dbprintf("invalid parameters\n");
495 if (argc
== 2) { /* WRITE LABEL */
497 if ((x
.isreadonly
& LIBXFS_ISREADONLY
) || !expert_mode
) {
498 dbprintf("%s: not in expert mode, writing disabled\n",
503 dbprintf("writing all SBs\n");
504 for (ag
= 0; ag
< mp
->m_sb
.sb_agcount
; ag
++)
505 if ((p
= do_label(ag
, argv
[1])) == NULL
) {
506 dbprintf("failed to set label in AG %d\n", ag
);
509 dbprintf("new label = \"%s\"\n", p
);
511 } else { /* READ LABEL */
513 for (ag
= 0; ag
< mp
->m_sb
.sb_agcount
; ag
++) {
514 p
= do_label(ag
, NULL
);
516 dbprintf("failed to read label in AG %d\n", ag
);
520 memcpy(&sb
.sb_fname
, p
, sizeof(sb
.sb_fname
));
521 else if (memcmp(&sb
.sb_fname
, p
, sizeof(sb
.sb_fname
)))
522 dbprintf("warning: AG %d label differs\n", ag
);
524 dbprintf("label = \"%s\"\n", p
);
535 " set/print feature bits in sb version\n"
539 " 'version' - print current feature bits\n"
540 " 'version extflg' - enable unwritten extents\n"
542 "The version function prints currently enabled features for a filesystem\n"
543 "according to its the version field of the primary superblock.\n"
544 "It can also be used to enable selected features, such as support for\n"
545 "unwritten extents. The upated version is written into to all AGs.\n"
551 do_version(xfs_agnumber_t agno
, __uint16_t versionnum
)
555 if (!get_sb(agno
, &tsb
))
558 tsb
.sb_versionnum
= versionnum
;
559 libxfs_xlate_sb(iocur_top
->data
, &tsb
,
560 -1, ARCH_CONVERT
, XFS_SB_VERSIONNUM
);
571 if (XFS_SB_VERSION_NUM(sbp
) == XFS_SB_VERSION_1
)
573 else if (XFS_SB_VERSION_NUM(sbp
) == XFS_SB_VERSION_2
)
575 else if (XFS_SB_VERSION_NUM(sbp
) == XFS_SB_VERSION_3
)
577 else if (XFS_SB_VERSION_NUM(sbp
) == XFS_SB_VERSION_4
)
580 if (XFS_SB_VERSION_HASATTR(sbp
))
582 if (XFS_SB_VERSION_HASNLINK(sbp
))
584 if (XFS_SB_VERSION_HASQUOTA(sbp
))
586 if (XFS_SB_VERSION_HASALIGN(sbp
))
588 if (XFS_SB_VERSION_HASDALIGN(sbp
))
589 strcat(s
, ",DALIGN");
590 if (XFS_SB_VERSION_HASSHARED(sbp
))
591 strcat(s
, ",SHARED");
592 if (XFS_SB_VERSION_HASDIRV2(sbp
))
594 if (XFS_SB_VERSION_HASLOGV2(sbp
))
596 if (XFS_SB_VERSION_HASEXTFLGBIT(sbp
))
597 strcat(s
, ",EXTFLG");
598 if (XFS_SB_VERSION_HASSECTOR(sbp
))
599 strcat(s
, ",SECTOR");
608 __uint16_t version
= 0;
611 if (argc
== 2) { /* WRITE VERSION */
613 if ((x
.isreadonly
& LIBXFS_ISREADONLY
) || !expert_mode
) {
614 dbprintf("%s: not in expert mode, writing disabled\n",
619 /* Logic here derived from the IRIX xfs_chver(1M) script. */
620 if (!strcasecmp(argv
[1], "extflg")) {
621 switch (XFS_SB_VERSION_NUM(&mp
->m_sb
)) {
622 case XFS_SB_VERSION_1
:
623 version
= 0x0004 | XFS_SB_VERSION_EXTFLGBIT
;
625 case XFS_SB_VERSION_2
:
626 version
= 0x0014 | XFS_SB_VERSION_EXTFLGBIT
;
628 case XFS_SB_VERSION_3
:
629 version
= 0x0034 | XFS_SB_VERSION_EXTFLGBIT
;
631 case XFS_SB_VERSION_4
:
632 if (XFS_SB_VERSION_HASEXTFLGBIT(&mp
->m_sb
))
633 dbprintf("unwritten extents flag"
634 " is already enabled\n");
636 version
= mp
->m_sb
.sb_versionnum
|
637 XFS_SB_VERSION_EXTFLGBIT
;
641 dbprintf("%s: invalid version change command \"%s\"\n",
647 dbprintf("writing all SBs\n");
648 for (ag
= 0; ag
< mp
->m_sb
.sb_agcount
; ag
++)
649 if (!do_version(ag
, version
)) {
650 dbprintf("failed to set versionnum "
654 mp
->m_sb
.sb_versionnum
= version
;
657 dbprintf("versionnum [0x%x] = %s\n", mp
->m_sb
.sb_versionnum
,
658 version_string(&mp
->m_sb
));