]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - db/sb.c
mkfs: sparse inode chunk support
[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));
19ebedcf 325 libxfs_sb_to_disk(iocur_top->data, &tsb);
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));
19ebedcf 490 libxfs_sb_to_disk(iocur_top->data, &tsb);
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;
571
572 if (!get_sb(agno, &tsb))
573 return 0;
574
72f11257
ES
575 if (xfs_sb_has_mismatched_features2(&tsb)) {
576 dbprintf(_("Superblock has mismatched features2 fields, "
577 "skipping modification\n"));
578 return 0;
579 }
580
66997473 581 if ((version & XFS_SB_VERSION_LOGV2BIT) &&
5e656dbb 582 !xfs_sb_version_haslogv2(&tsb)) {
66997473 583 tsb.sb_logsunit = 1;
66997473
NS
584 }
585
70476e54
NS
586 tsb.sb_versionnum = version;
587 tsb.sb_features2 = features;
72f11257 588 tsb.sb_bad_features2 = features;
19ebedcf 589 libxfs_sb_to_disk(iocur_top->data, &tsb);
4ca431fc
NS
590 write_cur();
591 return 1;
592}
593
594static char *
595version_string(
596 xfs_sb_t *sbp)
597{
598 static char s[1024];
599
600 if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_1)
601 strcpy(s, "V1");
602 else if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_2)
603 strcpy(s, "V2");
604 else if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_3)
605 strcpy(s, "V3");
606 else if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4)
607 strcpy(s, "V4");
a23fa047
DC
608 else if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5)
609 strcpy(s, "V5");
4ca431fc 610
5f6f3660
DC
611 /*
612 * We assume the state of these features now, so macros don't exist for
613 * them any more.
614 */
615 if (sbp->sb_versionnum & XFS_SB_VERSION_NLINKBIT)
616 strcat(s, ",NLINK");
617 if (sbp->sb_versionnum & XFS_SB_VERSION_SHAREDBIT)
618 strcat(s, ",SHARED");
619 if (sbp->sb_versionnum & XFS_SB_VERSION_DIRV2BIT)
620 strcat(s, ",DIRV2");
621
5e656dbb 622 if (xfs_sb_version_hasattr(sbp))
4ca431fc 623 strcat(s, ",ATTR");
5e656dbb 624 if (xfs_sb_version_hasquota(sbp))
4ca431fc 625 strcat(s, ",QUOTA");
5e656dbb 626 if (xfs_sb_version_hasalign(sbp))
4ca431fc 627 strcat(s, ",ALIGN");
5e656dbb 628 if (xfs_sb_version_hasdalign(sbp))
4ca431fc 629 strcat(s, ",DALIGN");
5e656dbb 630 if (xfs_sb_version_haslogv2(sbp))
4ca431fc 631 strcat(s, ",LOGV2");
5e656dbb 632 if (xfs_sb_version_hasextflgbit(sbp))
4ca431fc 633 strcat(s, ",EXTFLG");
5e656dbb 634 if (xfs_sb_version_hassector(sbp))
4ca431fc 635 strcat(s, ",SECTOR");
51ca7008
BN
636 if (xfs_sb_version_hasasciici(sbp))
637 strcat(s, ",ASCII_CI");
5e656dbb 638 if (xfs_sb_version_hasmorebits(sbp))
ca86e759 639 strcat(s, ",MOREBITS");
5e656dbb 640 if (xfs_sb_version_hasattr2(sbp))
ca86e759 641 strcat(s, ",ATTR2");
5e656dbb 642 if (xfs_sb_version_haslazysbcount(sbp))
cdded3d8 643 strcat(s, ",LAZYSBCOUNT");
22bc10ed
AM
644 if (xfs_sb_version_hasprojid32bit(sbp))
645 strcat(s, ",PROJID32BIT");
a23fa047
DC
646 if (xfs_sb_version_hascrc(sbp))
647 strcat(s, ",CRC");
42737f1a
MT
648 if (xfs_sb_version_hasftype(sbp))
649 strcat(s, ",FTYPE");
b7fc3b36
ES
650 if (xfs_sb_version_hasfinobt(sbp))
651 strcat(s, ",FINOBT");
4ca431fc
NS
652 return s;
653}
654
a23fa047
DC
655/*
656 * XXX: this only supports reading and writing to version 4 superblock fields.
657 * V5 superblocks always define certain V4 feature bits - they are blocked from
658 * being changed if a V5 sb is detected, but otherwise v5 superblock features
659 * are not handled here.
660 */
4ca431fc
NS
661static int
662version_f(
663 int argc,
664 char **argv)
665{
666 __uint16_t version = 0;
70476e54 667 __uint32_t features = 0;
4ca431fc
NS
668 xfs_agnumber_t ag;
669
670 if (argc == 2) { /* WRITE VERSION */
671
672 if ((x.isreadonly & LIBXFS_ISREADONLY) || !expert_mode) {
9ee7055c 673 dbprintf(_("%s: not in expert mode, writing disabled\n"),
4ca431fc
NS
674 progname);
675 return 0;
676 }
677
678 /* Logic here derived from the IRIX xfs_chver(1M) script. */
679 if (!strcasecmp(argv[1], "extflg")) {
680 switch (XFS_SB_VERSION_NUM(&mp->m_sb)) {
681 case XFS_SB_VERSION_1:
682 version = 0x0004 | XFS_SB_VERSION_EXTFLGBIT;
683 break;
684 case XFS_SB_VERSION_2:
685 version = 0x0014 | XFS_SB_VERSION_EXTFLGBIT;
686 break;
687 case XFS_SB_VERSION_3:
688 version = 0x0034 | XFS_SB_VERSION_EXTFLGBIT;
689 break;
690 case XFS_SB_VERSION_4:
5e656dbb 691 if (xfs_sb_version_hasextflgbit(&mp->m_sb))
a23fa047
DC
692 dbprintf(
693 _("unwritten extents flag is already enabled\n"));
4ca431fc
NS
694 else
695 version = mp->m_sb.sb_versionnum |
696 XFS_SB_VERSION_EXTFLGBIT;
697 break;
a23fa047
DC
698 case XFS_SB_VERSION_5:
699 dbprintf(
700 _("unwritten extents always enabled for v5 superblocks.\n"));
701 break;
4ca431fc 702 }
66997473
NS
703 } else if (!strcasecmp(argv[1], "log2")) {
704 switch (XFS_SB_VERSION_NUM(&mp->m_sb)) {
705 case XFS_SB_VERSION_1:
706 version = 0x0004 | XFS_SB_VERSION_LOGV2BIT;
707 break;
708 case XFS_SB_VERSION_2:
709 version = 0x0014 | XFS_SB_VERSION_LOGV2BIT;
710 break;
711 case XFS_SB_VERSION_3:
712 version = 0x0034 | XFS_SB_VERSION_LOGV2BIT;
713 break;
714 case XFS_SB_VERSION_4:
5e656dbb 715 if (xfs_sb_version_haslogv2(&mp->m_sb))
a23fa047
DC
716 dbprintf(
717 _("version 2 log format is already in use\n"));
66997473
NS
718 else
719 version = mp->m_sb.sb_versionnum |
720 XFS_SB_VERSION_LOGV2BIT;
721 break;
a23fa047
DC
722 case XFS_SB_VERSION_5:
723 dbprintf(
724 _("Version 2 logs always enabled for v5 superblocks.\n"));
725 break;
66997473 726 }
a23fa047
DC
727 } else if (XFS_SB_VERSION_NUM(&mp->m_sb) == XFS_SB_VERSION_5) {
728 dbprintf(
729 _("%s: Cannot change %s on v5 superblocks.\n"),
730 progname, argv[1]);
731 return 0;
70476e54 732 } else if (!strcasecmp(argv[1], "attr1")) {
a23fa047 733
5e656dbb 734 if (xfs_sb_version_hasattr2(&mp->m_sb)) {
70476e54
NS
735 if (!(mp->m_sb.sb_features2 &=
736 ~XFS_SB_VERSION2_ATTR2BIT))
737 mp->m_sb.sb_versionnum &=
738 ~XFS_SB_VERSION_MOREBITSBIT;
739 }
5e656dbb 740 xfs_sb_version_addattr(&mp->m_sb);
70476e54
NS
741 version = mp->m_sb.sb_versionnum;
742 features = mp->m_sb.sb_features2;
743 } else if (!strcasecmp(argv[1], "attr2")) {
5e656dbb
BN
744 xfs_sb_version_addattr(&mp->m_sb);
745 xfs_sb_version_addattr2(&mp->m_sb);
22bc10ed
AM
746 version = mp->m_sb.sb_versionnum;
747 features = mp->m_sb.sb_features2;
748 } else if (!strcasecmp(argv[1], "projid32bit")) {
749 xfs_sb_version_addprojid32bit(&mp->m_sb);
70476e54
NS
750 version = mp->m_sb.sb_versionnum;
751 features = mp->m_sb.sb_features2;
4ca431fc 752 } else {
9ee7055c 753 dbprintf(_("%s: invalid version change command \"%s\"\n"),
4ca431fc
NS
754 progname, argv[1]);
755 return 0;
756 }
757
758 if (version) {
9ee7055c 759 dbprintf(_("writing all SBs\n"));
4ca431fc 760 for (ag = 0; ag < mp->m_sb.sb_agcount; ag++)
70476e54 761 if (!do_version(ag, version, features)) {
9ee7055c
AM
762 dbprintf(_("failed to set versionnum "
763 "in AG %d\n"), ag);
4ca431fc
NS
764 break;
765 }
766 mp->m_sb.sb_versionnum = version;
70476e54 767 mp->m_sb.sb_features2 = features;
4ca431fc
NS
768 }
769 }
d2df702b
NS
770
771 if (argc == 3) { /* VERSIONNUM + FEATURES2 */
772 char *sp;
773
774 version = mp->m_sb.sb_versionnum;
775 features = mp->m_sb.sb_features2;
776 mp->m_sb.sb_versionnum = strtoul(argv[1], &sp, 0);
777 mp->m_sb.sb_features2 = strtoul(argv[2], &sp, 0);
778 }
779
9ee7055c 780 dbprintf(_("versionnum [0x%x+0x%x] = %s\n"), mp->m_sb.sb_versionnum,
ca86e759 781 mp->m_sb.sb_features2, version_string(&mp->m_sb));
d2df702b
NS
782
783 if (argc == 3) { /* now reset... */
784 mp->m_sb.sb_versionnum = version;
785 mp->m_sb.sb_features2 = features;
786 return 0;
787 }
788
4ca431fc
NS
789 return 0;
790}