]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - db/sb.c
xfsprogs debian change
[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 =
42 { "sb", NULL, sb_f, 0, 1, 1, "[agno]",
43 "set current address to sb header", sb_help };
4ca431fc
NS
44static const cmdinfo_t uuid_cmd =
45 { "uuid", NULL, uuid_f, 0, 1, 1, "[uuid]",
46 "write/print FS uuid", uuid_help };
47static const cmdinfo_t label_cmd =
48 { "label", NULL, label_f, 0, 1, 1, "[label]",
49 "write/print FS label", label_help };
50static const cmdinfo_t version_cmd =
d2df702b 51 { "version", NULL, version_f, 0, -1, 1, "[feature | [vnum fnum]]",
4ca431fc 52 "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 },
45935737 111 { "bad_features2", FLDT_UINT32X, OI(OFF(bad_features2)), C1, 0, TYP_NONE },
2bd0ea18
NS
112 { NULL }
113};
114
4ca431fc
NS
115const field_t sb_hfld[] = {
116 { "", FLDT_SB, OI(0), C1, 0, TYP_NONE },
117 { NULL }
118};
119
2bd0ea18
NS
120static void
121sb_help(void)
122{
123 dbprintf(
124"\n"
125" set allocation group superblock\n"
126"\n"
127" Example:\n"
128"\n"
129" 'sb 7' - set location to 7th allocation group superblock, set type to 'sb'\n"
130"\n"
9440d84d
NS
131" Located in the first sector of each allocation group, the superblock\n"
132" contains the base information for the filesystem.\n"
2bd0ea18
NS
133" The superblock in allocation group 0 is the primary. The copies in the\n"
134" remaining allocation groups only serve as backup for filesystem recovery.\n"
135" The icount/ifree/fdblocks/frextents are only updated in superblock 0.\n"
136"\n"
137);
138}
139
140static int
141sb_f(
142 int argc,
143 char **argv)
144{
145 xfs_agnumber_t agno;
146 char *p;
147
148 if (argc > 1) {
149 agno = (xfs_agnumber_t)strtoul(argv[1], &p, 0);
150 if (*p != '\0' || agno >= mp->m_sb.sb_agcount) {
151 dbprintf("bad allocation group number %s\n", argv[1]);
152 return 0;
153 }
154 cur_agno = agno;
155 } else if (cur_agno == NULLAGNUMBER)
156 cur_agno = 0;
157 ASSERT(typtab[TYP_SB].typnm == TYP_SB);
9440d84d
NS
158 set_cur(&typtab[TYP_SB],
159 XFS_AG_DADDR(mp, cur_agno, XFS_SB_DADDR),
160 XFS_FSS_TO_BB(mp, 1), DB_RING_ADD, NULL);
2bd0ea18
NS
161 return 0;
162}
163
2bd0ea18
NS
164/*ARGSUSED*/
165int
166sb_size(
167 void *obj,
168 int startoff,
169 int idx)
170{
171 return bitize(mp->m_sb.sb_sectsize);
172}
4ca431fc
NS
173
174static int
175get_sb(xfs_agnumber_t agno, xfs_sb_t *sb)
176{
177 push_cur();
178 set_cur(&typtab[TYP_SB],
179 XFS_AG_DADDR(mp, agno, XFS_SB_DADDR),
180 XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL);
dfc130f3 181
4ca431fc
NS
182 if (!iocur_top->data) {
183 dbprintf("can't read superblock for AG %u\n", agno);
184 pop_cur();
185 return 0;
186 }
187
46eca962 188 libxfs_xlate_sb(iocur_top->data, sb, 1, XFS_SB_ALL_BITS);
dfc130f3 189
4ca431fc
NS
190 if (sb->sb_magicnum != XFS_SB_MAGIC) {
191 dbprintf("bad sb magic # %#x in AG %u\n",
192 sb->sb_magicnum, agno);
dfc130f3 193 return 0;
4ca431fc
NS
194 }
195 if (!XFS_SB_GOOD_VERSION(sb)) {
196 dbprintf("bad sb version # %#x in AG %u\n",
197 sb->sb_versionnum, agno);
dfc130f3 198 return 0;
4ca431fc
NS
199 }
200 if (agno == 0 && sb->sb_inprogress != 0) {
201 dbprintf("mkfs not completed successfully\n");
dfc130f3 202 return 0;
4ca431fc
NS
203 }
204 return 1;
205}
206
207/* workaround craziness in the xlog routines */
208int xlog_recover_do_trans(xlog_t *log, xlog_recover_t *t, int p) { return 0; }
209
add013da
NS
210int
211sb_logcheck(void)
4ca431fc
NS
212{
213 xlog_t log;
214 xfs_daddr_t head_blk, tail_blk;
215
216 if (mp->m_sb.sb_logstart) {
217 if (x.logdev && x.logdev != x.ddev) {
218 dbprintf("aborting - external log specified for FS "
219 "with an internal log\n");
220 return 0;
221 }
222 } else {
223 if (!x.logdev || (x.logdev == x.ddev)) {
224 dbprintf("aborting - no external log specified for FS "
225 "with an external log\n");
226 return 0;
227 }
228 }
229
230 memset(&log, 0, sizeof(log));
231 if (!x.logdev)
232 x.logdev = x.ddev;
233 x.logBBsize = XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks);
234 x.logBBstart = XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart);
235 log.l_dev = (mp->m_sb.sb_logstart == 0) ? x.logdev : x.ddev;
236 log.l_logsize = BBTOB(log.l_logBBsize);
237 log.l_logBBsize = x.logBBsize;
238 log.l_logBBstart = x.logBBstart;
239 log.l_mp = mp;
240
241 if (xlog_find_tail(&log, &head_blk, &tail_blk, 0)) {
242 dbprintf("ERROR: cannot find log head/tail, run xfs_repair\n");
243 return 0;
244 }
245 if (head_blk != tail_blk) {
246 dbprintf(
247"ERROR: The filesystem has valuable metadata changes in a log which needs to\n"
248"be replayed. Mount the filesystem to replay the log, and unmount it before\n"
249"re-running %s. If you are unable to mount the filesystem, then use\n"
250"the xfs_repair -L option to destroy the log and attempt a repair.\n"
251"Note that destroying the log may cause corruption -- please attempt a mount\n"
252"of the filesystem before doing this.\n", progname);
253 return 0;
254 }
add013da
NS
255 return 1;
256}
257
258static int
259sb_logzero(uuid_t *uuidp)
260{
261 if (!sb_logcheck())
262 return 0;
4ca431fc
NS
263
264 dbprintf("Clearing log and setting UUID\n");
265
add013da
NS
266 if (libxfs_log_clear(
267 (mp->m_sb.sb_logstart == 0) ? x.logdev : x.ddev,
4ca431fc
NS
268 XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart),
269 (xfs_extlen_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks),
270 uuidp,
271 XFS_SB_VERSION_HASLOGV2(&mp->m_sb) ? 2 : 1,
272 mp->m_sb.sb_logsunit, XLOG_FMT)) {
273 dbprintf("ERROR: cannot clear the log\n");
274 return 0;
275 }
276 return 1;
277}
278
279
280static void
281uuid_help(void)
282{
283 dbprintf(
284"\n"
285" write/print FS uuid\n"
286"\n"
287" Example:\n"
288"\n"
289" 'uuid' - print UUID\n"
290" 'uuid 01234567-0123-0123-0123-0123456789ab' - write UUID\n"
291" 'uuid generate' - generate and write\n"
292" 'uuid rewrite' - copy UUID from SB 0\n"
293"\n"
294"The print function checks the UUID in each SB and will warn if the UUIDs\n"
295"differ between AGs (the log is not checked). The write commands will\n"
296"set the uuid in all AGs to either a specified value, a newly generated\n"
297"value or the value found in the first superblock (SB 0) respectively.\n"
298"As a side effect of writing the UUID, the log is cleared (which is fine\n"
299"on a CLEANLY unmounted FS).\n"
300"\n"
301);
302}
303
304static uuid_t *
305do_uuid(xfs_agnumber_t agno, uuid_t *uuid)
306{
307 xfs_sb_t tsb;
308 static uuid_t uu;
309
310 if (!get_sb(agno, &tsb))
311 return NULL;
312
313 if (!uuid) { /* get uuid */
314 memcpy(&uu, &tsb.sb_uuid, sizeof(uuid_t));
315 pop_cur();
316 return &uu;
317 }
318 /* set uuid */
319 memcpy(&tsb.sb_uuid, uuid, sizeof(uuid_t));
46eca962 320 libxfs_xlate_sb(iocur_top->data, &tsb, -1, XFS_SB_UUID);
4ca431fc
NS
321 write_cur();
322 return uuid;
323}
324
325static int
326uuid_f(
327 int argc,
328 char **argv)
329{
330 char bp[40];
331 xfs_agnumber_t agno;
332 uuid_t uu;
333 uuid_t *uup = NULL;
334
335 if (argc != 1 && argc != 2) {
336 dbprintf("invalid parameters\n");
337 return 0;
338 }
339
340 if (argc == 2) { /* WRITE UUID */
341
342 if ((x.isreadonly & LIBXFS_ISREADONLY) || !expert_mode) {
343 dbprintf("%s: not in expert mode, writing disabled\n",
344 progname);
345 return 0;
346 }
347
348 if (!strcasecmp(argv[1], "generate")) {
4d32d744 349 platform_uuid_generate(&uu);
4ca431fc 350 } else if (!strcasecmp(argv[1], "nil")) {
4d32d744 351 platform_uuid_clear(&uu);
4ca431fc
NS
352 } else if (!strcasecmp(argv[1], "rewrite")) {
353 uup = do_uuid(0, NULL);
354 if (!uup) {
355 dbprintf("failed to read UUID from AG 0\n");
356 return 0;
357 }
6699422d 358 memcpy(&uu, uup, sizeof(uuid_t));
4d32d744 359 platform_uuid_unparse(&uu, bp);
4ca431fc
NS
360 dbprintf("old UUID = %s\n", bp);
361 } else {
4d32d744 362 if (platform_uuid_parse(argv[1], &uu)) {
4ca431fc
NS
363 dbprintf("invalid UUID\n");
364 return 0;
365 }
366 }
367
368 /* clear the log (setting uuid) if its not dirty */
add013da 369 if (!sb_logzero(&uu))
4ca431fc
NS
370 return 0;
371
372 dbprintf("writing all SBs\n");
373 for (agno = 0; agno < mp->m_sb.sb_agcount; agno++)
374 if (!do_uuid(agno, &uu)) {
375 dbprintf("failed to set UUID in AG %d\n", agno);
376 break;
377 }
378
4d32d744 379 platform_uuid_unparse(&uu, bp);
4ca431fc
NS
380 dbprintf("new UUID = %s\n", bp);
381 return 0;
382
383 } else { /* READ+CHECK UUID */
dfc130f3 384
4ca431fc
NS
385 for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
386 uup = do_uuid(agno, NULL);
387 if (!uup) {
388 dbprintf("failed to read UUID from AG %d\n",
389 agno);
390 return 0;
391 }
392 if (agno) {
393 if (memcmp(&uu, uup, sizeof(uuid_t))) {
394 dbprintf("warning: UUID in AG %d "
395 "differs to the primary SB\n",
396 agno);
397 break;
398 }
399 } else {
6699422d 400 memcpy(&uu, uup, sizeof(uuid_t));
4ca431fc
NS
401 }
402 }
403 if (mp->m_sb.sb_logstart) {
404 if (x.logdev && x.logdev != x.ddev)
405 dbprintf("warning - external log specified "
406 "for FS with an internal log\n");
407 } else if (!x.logdev || (x.logdev == x.ddev)) {
408 dbprintf("warning - no external log specified "
409 "for FS with an external log\n");
410 }
411
4d32d744 412 platform_uuid_unparse(&uu, bp);
4ca431fc
NS
413 dbprintf("UUID = %s\n", bp);
414 }
415
416 return 0;
417}
418
419
420static void
421label_help(void)
422{
423 dbprintf(
424"\n"
425" write/print FS label\n"
426"\n"
427" Example:\n"
428"\n"
429" 'label' - print label\n"
430" 'label 123456789012' - write label\n"
431" 'label --' - write an empty label\n"
432"\n"
433"The print function checks the label in each SB and will warn if the labels\n"
434"differ between AGs. The write commands will set the label in all AGs to the\n"
435"specified value. The maximum length of a label is 12 characters - use of a\n"
436"longer label will result in truncation and a warning will be issued.\n"
437"\n"
438);
439}
440
441static char *
442do_label(xfs_agnumber_t agno, char *label)
443{
444 size_t len;
445 xfs_sb_t tsb;
dfc130f3 446 static char lbl[sizeof(tsb.sb_fname) + 1];
4ca431fc
NS
447
448 if (!get_sb(agno, &tsb))
449 return NULL;
450
451 memset(&lbl[0], 0, sizeof(lbl));
452
453 if (!label) { /* get label */
454 pop_cur();
455 memcpy(&lbl[0], &tsb.sb_fname, sizeof(tsb.sb_fname));
456 return &lbl[0];
457 }
458 /* set label */
459 if ((len = strlen(label)) > sizeof(tsb.sb_fname)) {
460 if (agno == 0)
461 dbprintf("%s: truncating label length from %d to %d\n",
462 progname, (int)len, (int)sizeof(tsb.sb_fname));
463 len = sizeof(tsb.sb_fname);
464 }
465 if ( len == 2 &&
466 (strcmp(label, "\"\"") == 0 ||
467 strcmp(label, "''") == 0 ||
468 strcmp(label, "--") == 0) )
469 label[0] = label[1] = '\0';
470 memset(&tsb.sb_fname, 0, sizeof(tsb.sb_fname));
471 memcpy(&tsb.sb_fname, label, len);
472 memcpy(&lbl[0], &tsb.sb_fname, sizeof(tsb.sb_fname));
46eca962 473 libxfs_xlate_sb(iocur_top->data, &tsb, -1, XFS_SB_FNAME);
4ca431fc
NS
474 write_cur();
475 return &lbl[0];
476}
477
478static int
479label_f(
480 int argc,
481 char **argv)
482{
483 char *p = NULL;
484 xfs_sb_t sb;
485 xfs_agnumber_t ag;
486
487 if (argc != 1 && argc != 2) {
488 dbprintf("invalid parameters\n");
489 return 0;
490 }
491
492 if (argc == 2) { /* WRITE LABEL */
493
494 if ((x.isreadonly & LIBXFS_ISREADONLY) || !expert_mode) {
495 dbprintf("%s: not in expert mode, writing disabled\n",
496 progname);
497 return 0;
498 }
499
500 dbprintf("writing all SBs\n");
501 for (ag = 0; ag < mp->m_sb.sb_agcount; ag++)
502 if ((p = do_label(ag, argv[1])) == NULL) {
503 dbprintf("failed to set label in AG %d\n", ag);
504 break;
505 }
506 dbprintf("new label = \"%s\"\n", p);
507
508 } else { /* READ LABEL */
509
510 for (ag = 0; ag < mp->m_sb.sb_agcount; ag++) {
511 p = do_label(ag, NULL);
512 if (!p) {
513 dbprintf("failed to read label in AG %d\n", ag);
514 return 0;
515 }
516 if (!ag)
517 memcpy(&sb.sb_fname, p, sizeof(sb.sb_fname));
518 else if (memcmp(&sb.sb_fname, p, sizeof(sb.sb_fname)))
519 dbprintf("warning: AG %d label differs\n", ag);
520 }
521 dbprintf("label = \"%s\"\n", p);
522 }
523 return 0;
524}
525
526
527static void
528version_help(void)
529{
530 dbprintf(
531"\n"
532" set/print feature bits in sb version\n"
533"\n"
534" Example:\n"
535"\n"
536" 'version' - print current feature bits\n"
537" 'version extflg' - enable unwritten extents\n"
70476e54
NS
538" 'version attr1' - enable v1 inline extended attributes\n"
539" 'version attr2' - enable v2 inline extended attributes\n"
66997473 540" 'version log2' - enable v2 log format\n"
4ca431fc
NS
541"\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"
66997473 545"unwritten extents. The upated version is written into all AGs.\n"
4ca431fc
NS
546"\n"
547);
548}
549
550static int
70476e54 551do_version(xfs_agnumber_t agno, __uint16_t version, __uint32_t features)
4ca431fc
NS
552{
553 xfs_sb_t tsb;
66997473 554 __int64_t fields = 0;
4ca431fc
NS
555
556 if (!get_sb(agno, &tsb))
557 return 0;
558
66997473
NS
559 if ((version & XFS_SB_VERSION_LOGV2BIT) &&
560 !XFS_SB_VERSION_HASLOGV2(&tsb)) {
561 tsb.sb_logsunit = 1;
562 fields |= (1LL << XFS_SBS_LOGSUNIT);
563 }
564
70476e54
NS
565 tsb.sb_versionnum = version;
566 tsb.sb_features2 = features;
66997473
NS
567 fields |= XFS_SB_VERSIONNUM | XFS_SB_FEATURES2;
568 libxfs_xlate_sb(iocur_top->data, &tsb, -1, fields);
4ca431fc
NS
569 write_cur();
570 return 1;
571}
572
573static char *
574version_string(
575 xfs_sb_t *sbp)
576{
577 static char s[1024];
578
579 if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_1)
580 strcpy(s, "V1");
581 else if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_2)
582 strcpy(s, "V2");
583 else if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_3)
584 strcpy(s, "V3");
585 else if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4)
586 strcpy(s, "V4");
587
588 if (XFS_SB_VERSION_HASATTR(sbp))
589 strcat(s, ",ATTR");
590 if (XFS_SB_VERSION_HASNLINK(sbp))
591 strcat(s, ",NLINK");
592 if (XFS_SB_VERSION_HASQUOTA(sbp))
593 strcat(s, ",QUOTA");
594 if (XFS_SB_VERSION_HASALIGN(sbp))
595 strcat(s, ",ALIGN");
596 if (XFS_SB_VERSION_HASDALIGN(sbp))
597 strcat(s, ",DALIGN");
598 if (XFS_SB_VERSION_HASSHARED(sbp))
599 strcat(s, ",SHARED");
600 if (XFS_SB_VERSION_HASDIRV2(sbp))
601 strcat(s, ",DIRV2");
602 if (XFS_SB_VERSION_HASLOGV2(sbp))
603 strcat(s, ",LOGV2");
604 if (XFS_SB_VERSION_HASEXTFLGBIT(sbp))
605 strcat(s, ",EXTFLG");
606 if (XFS_SB_VERSION_HASSECTOR(sbp))
607 strcat(s, ",SECTOR");
ca86e759
NS
608 if (XFS_SB_VERSION_HASMOREBITS(sbp))
609 strcat(s, ",MOREBITS");
610 if (XFS_SB_VERSION_HASATTR2(sbp))
611 strcat(s, ",ATTR2");
cdded3d8
DC
612 if (XFS_SB_VERSION_LAZYSBCOUNT(sbp))
613 strcat(s, ",LAZYSBCOUNT");
4ca431fc
NS
614 return s;
615}
616
617static int
618version_f(
619 int argc,
620 char **argv)
621{
622 __uint16_t version = 0;
70476e54 623 __uint32_t features = 0;
4ca431fc
NS
624 xfs_agnumber_t ag;
625
626 if (argc == 2) { /* WRITE VERSION */
627
628 if ((x.isreadonly & LIBXFS_ISREADONLY) || !expert_mode) {
629 dbprintf("%s: not in expert mode, writing disabled\n",
630 progname);
631 return 0;
632 }
633
634 /* Logic here derived from the IRIX xfs_chver(1M) script. */
635 if (!strcasecmp(argv[1], "extflg")) {
636 switch (XFS_SB_VERSION_NUM(&mp->m_sb)) {
637 case XFS_SB_VERSION_1:
638 version = 0x0004 | XFS_SB_VERSION_EXTFLGBIT;
639 break;
640 case XFS_SB_VERSION_2:
641 version = 0x0014 | XFS_SB_VERSION_EXTFLGBIT;
642 break;
643 case XFS_SB_VERSION_3:
644 version = 0x0034 | XFS_SB_VERSION_EXTFLGBIT;
645 break;
646 case XFS_SB_VERSION_4:
647 if (XFS_SB_VERSION_HASEXTFLGBIT(&mp->m_sb))
648 dbprintf("unwritten extents flag"
649 " is already enabled\n");
650 else
651 version = mp->m_sb.sb_versionnum |
652 XFS_SB_VERSION_EXTFLGBIT;
653 break;
654 }
66997473
NS
655 } else if (!strcasecmp(argv[1], "log2")) {
656 switch (XFS_SB_VERSION_NUM(&mp->m_sb)) {
657 case XFS_SB_VERSION_1:
658 version = 0x0004 | XFS_SB_VERSION_LOGV2BIT;
659 break;
660 case XFS_SB_VERSION_2:
661 version = 0x0014 | XFS_SB_VERSION_LOGV2BIT;
662 break;
663 case XFS_SB_VERSION_3:
664 version = 0x0034 | XFS_SB_VERSION_LOGV2BIT;
665 break;
666 case XFS_SB_VERSION_4:
667 if (XFS_SB_VERSION_HASLOGV2(&mp->m_sb))
668 dbprintf("version 2 log format"
669 " is already in use\n");
670 else
671 version = mp->m_sb.sb_versionnum |
672 XFS_SB_VERSION_LOGV2BIT;
673 break;
674 }
70476e54
NS
675 } else if (!strcasecmp(argv[1], "attr1")) {
676 if (XFS_SB_VERSION_HASATTR2(&mp->m_sb)) {
677 if (!(mp->m_sb.sb_features2 &=
678 ~XFS_SB_VERSION2_ATTR2BIT))
679 mp->m_sb.sb_versionnum &=
680 ~XFS_SB_VERSION_MOREBITSBIT;
681 }
682 XFS_SB_VERSION_ADDATTR(&mp->m_sb);
683 version = mp->m_sb.sb_versionnum;
684 features = mp->m_sb.sb_features2;
685 } else if (!strcasecmp(argv[1], "attr2")) {
686 XFS_SB_VERSION_ADDATTR(&mp->m_sb);
687 XFS_SB_VERSION_ADDATTR2(&mp->m_sb);
688 version = mp->m_sb.sb_versionnum;
689 features = mp->m_sb.sb_features2;
4ca431fc
NS
690 } else {
691 dbprintf("%s: invalid version change command \"%s\"\n",
692 progname, argv[1]);
693 return 0;
694 }
695
696 if (version) {
697 dbprintf("writing all SBs\n");
698 for (ag = 0; ag < mp->m_sb.sb_agcount; ag++)
70476e54 699 if (!do_version(ag, version, features)) {
4ca431fc
NS
700 dbprintf("failed to set versionnum "
701 "in AG %d\n", ag);
702 break;
703 }
704 mp->m_sb.sb_versionnum = version;
70476e54 705 mp->m_sb.sb_features2 = features;
4ca431fc
NS
706 }
707 }
d2df702b
NS
708
709 if (argc == 3) { /* VERSIONNUM + FEATURES2 */
710 char *sp;
711
712 version = mp->m_sb.sb_versionnum;
713 features = mp->m_sb.sb_features2;
714 mp->m_sb.sb_versionnum = strtoul(argv[1], &sp, 0);
715 mp->m_sb.sb_features2 = strtoul(argv[2], &sp, 0);
716 }
717
ca86e759
NS
718 dbprintf("versionnum [0x%x+0x%x] = %s\n", mp->m_sb.sb_versionnum,
719 mp->m_sb.sb_features2, version_string(&mp->m_sb));
d2df702b
NS
720
721 if (argc == 3) { /* now reset... */
722 mp->m_sb.sb_versionnum = version;
723 mp->m_sb.sb_features2 = features;
724 return 0;
725 }
726
4ca431fc
NS
727 return 0;
728}