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