]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - db/sb.c
Fix includes to not be relative to paths provided by -I directives, for
[thirdparty/xfsprogs-dev.git] / db / sb.c
1 /*
2 * Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved.
3 *
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.
7 *
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.
11 *
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.
18 *
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.
22 *
23 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24 * Mountain View, CA 94043, or:
25 *
26 * http://www.sgi.com
27 *
28 * For further information regarding this notice, see:
29 *
30 * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
31 */
32
33 #include <xfs/libxfs.h>
34 #include <xfs/libxlog.h>
35 #include "command.h"
36 #include "type.h"
37 #include "faddr.h"
38 #include "fprint.h"
39 #include "field.h"
40 #include "io.h"
41 #include "sb.h"
42 #include "bit.h"
43 #include "output.h"
44 #include "init.h"
45
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);
54
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 };
67
68 void
69 sb_init(void)
70 {
71 add_command(&sb_cmd);
72 add_command(&uuid_cmd);
73 add_command(&label_cmd);
74 add_command(&version_cmd);
75 }
76
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 },
124 { NULL }
125 };
126
127 const field_t sb_hfld[] = {
128 { "", FLDT_SB, OI(0), C1, 0, TYP_NONE },
129 { NULL }
130 };
131
132 static void
133 sb_help(void)
134 {
135 dbprintf(
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"
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"
148 "\n"
149 );
150 }
151
152 static int
153 sb_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) {
163 dbprintf("bad allocation group number %s\n", argv[1]);
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);
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);
173 return 0;
174 }
175
176 /*ARGSUSED*/
177 int
178 sb_size(
179 void *obj,
180 int startoff,
181 int idx)
182 {
183 return bitize(mp->m_sb.sb_sectsize);
184 }
185
186 static int
187 get_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);
193
194 if (!iocur_top->data) {
195 dbprintf("can't read superblock for AG %u\n", agno);
196 pop_cur();
197 return 0;
198 }
199
200 libxfs_xlate_sb(iocur_top->data, sb, 1, ARCH_CONVERT, XFS_SB_ALL_BITS);
201
202 if (sb->sb_magicnum != XFS_SB_MAGIC) {
203 dbprintf("bad sb magic # %#x in AG %u\n",
204 sb->sb_magicnum, agno);
205 return 0;
206 }
207 if (!XFS_SB_GOOD_VERSION(sb)) {
208 dbprintf("bad sb version # %#x in AG %u\n",
209 sb->sb_versionnum, agno);
210 return 0;
211 }
212 if (agno == 0 && sb->sb_inprogress != 0) {
213 dbprintf("mkfs not completed successfully\n");
214 return 0;
215 }
216 return 1;
217 }
218
219 /* workaround craziness in the xlog routines */
220 int xlog_recover_do_trans(xlog_t *log, xlog_recover_t *t, int p) { return 0; }
221
222 static int
223 zero_log(uuid_t *uuidp)
224 {
225 xlog_t log;
226 xfs_daddr_t head_blk, tail_blk;
227
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");
232 return 0;
233 }
234 } else {
235 if (!x.logdev || (x.logdev == x.ddev)) {
236 dbprintf("aborting - no external log specified for FS "
237 "with an external log\n");
238 return 0;
239 }
240 }
241
242 memset(&log, 0, sizeof(log));
243 if (!x.logdev)
244 x.logdev = x.ddev;
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;
251 log.l_mp = mp;
252
253 if (xlog_find_tail(&log, &head_blk, &tail_blk, 0)) {
254 dbprintf("ERROR: cannot find log head/tail, run xfs_repair\n");
255 return 0;
256 }
257 if (head_blk != tail_blk) {
258 dbprintf(
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);
265 return 0;
266 }
267
268 dbprintf("Clearing log and setting UUID\n");
269
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),
273 uuidp,
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");
277 return 0;
278 }
279 return 1;
280 }
281
282
283 static void
284 uuid_help(void)
285 {
286 dbprintf(
287 "\n"
288 " write/print FS uuid\n"
289 "\n"
290 " Example:\n"
291 "\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"
296 "\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"
303 "\n"
304 );
305 }
306
307 static uuid_t *
308 do_uuid(xfs_agnumber_t agno, uuid_t *uuid)
309 {
310 xfs_sb_t tsb;
311 static uuid_t uu;
312
313 if (!get_sb(agno, &tsb))
314 return NULL;
315
316 if (!uuid) { /* get uuid */
317 memcpy(&uu, &tsb.sb_uuid, sizeof(uuid_t));
318 pop_cur();
319 return &uu;
320 }
321 /* set uuid */
322 memcpy(&tsb.sb_uuid, uuid, sizeof(uuid_t));
323 libxfs_xlate_sb(iocur_top->data, &tsb, -1, ARCH_CONVERT, XFS_SB_UUID);
324 write_cur();
325 return uuid;
326 }
327
328 static int
329 uuid_f(
330 int argc,
331 char **argv)
332 {
333 char bp[40];
334 xfs_agnumber_t agno;
335 uuid_t uu;
336 uuid_t *uup = NULL;
337
338 if (argc != 1 && argc != 2) {
339 dbprintf("invalid parameters\n");
340 return 0;
341 }
342
343 if (argc == 2) { /* WRITE UUID */
344
345 if ((x.isreadonly & LIBXFS_ISREADONLY) || !expert_mode) {
346 dbprintf("%s: not in expert mode, writing disabled\n",
347 progname);
348 return 0;
349 }
350
351 if (!strcasecmp(argv[1], "generate")) {
352 uuid_generate(uu);
353 } else if (!strcasecmp(argv[1], "nil")) {
354 uuid_clear(uu);
355 } else if (!strcasecmp(argv[1], "rewrite")) {
356 uup = do_uuid(0, NULL);
357 if (!uup) {
358 dbprintf("failed to read UUID from AG 0\n");
359 return 0;
360 }
361 memcpy(&uu, *uup, sizeof(uuid_t));
362 uuid_unparse(uu, bp);
363 dbprintf("old UUID = %s\n", bp);
364 } else {
365 if (uuid_parse(argv[1], uu)) {
366 dbprintf("invalid UUID\n");
367 return 0;
368 }
369 }
370
371 /* clear the log (setting uuid) if its not dirty */
372 if (!zero_log(&uu))
373 return 0;
374
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);
379 break;
380 }
381
382 uuid_unparse(uu, bp);
383 dbprintf("new UUID = %s\n", bp);
384 return 0;
385
386 } else { /* READ+CHECK UUID */
387
388 for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
389 uup = do_uuid(agno, NULL);
390 if (!uup) {
391 dbprintf("failed to read UUID from AG %d\n",
392 agno);
393 return 0;
394 }
395 if (agno) {
396 if (memcmp(&uu, uup, sizeof(uuid_t))) {
397 dbprintf("warning: UUID in AG %d "
398 "differs to the primary SB\n",
399 agno);
400 break;
401 }
402 } else {
403 memcpy(uu, uup, sizeof(uuid_t));
404 }
405 }
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");
413 }
414
415 uuid_unparse(uu, bp);
416 dbprintf("UUID = %s\n", bp);
417 }
418
419 return 0;
420 }
421
422
423 static void
424 label_help(void)
425 {
426 dbprintf(
427 "\n"
428 " write/print FS label\n"
429 "\n"
430 " Example:\n"
431 "\n"
432 " 'label' - print label\n"
433 " 'label 123456789012' - write label\n"
434 " 'label --' - write an empty label\n"
435 "\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"
440 "\n"
441 );
442 }
443
444 static char *
445 do_label(xfs_agnumber_t agno, char *label)
446 {
447 size_t len;
448 xfs_sb_t tsb;
449 static char lbl[sizeof(tsb.sb_fname) + 1];
450
451 if (!get_sb(agno, &tsb))
452 return NULL;
453
454 memset(&lbl[0], 0, sizeof(lbl));
455
456 if (!label) { /* get label */
457 pop_cur();
458 memcpy(&lbl[0], &tsb.sb_fname, sizeof(tsb.sb_fname));
459 return &lbl[0];
460 }
461 /* set label */
462 if ((len = strlen(label)) > sizeof(tsb.sb_fname)) {
463 if (agno == 0)
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);
467 }
468 if ( len == 2 &&
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);
477 write_cur();
478 return &lbl[0];
479 }
480
481 static int
482 label_f(
483 int argc,
484 char **argv)
485 {
486 char *p = NULL;
487 xfs_sb_t sb;
488 xfs_agnumber_t ag;
489
490 if (argc != 1 && argc != 2) {
491 dbprintf("invalid parameters\n");
492 return 0;
493 }
494
495 if (argc == 2) { /* WRITE LABEL */
496
497 if ((x.isreadonly & LIBXFS_ISREADONLY) || !expert_mode) {
498 dbprintf("%s: not in expert mode, writing disabled\n",
499 progname);
500 return 0;
501 }
502
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);
507 break;
508 }
509 dbprintf("new label = \"%s\"\n", p);
510
511 } else { /* READ LABEL */
512
513 for (ag = 0; ag < mp->m_sb.sb_agcount; ag++) {
514 p = do_label(ag, NULL);
515 if (!p) {
516 dbprintf("failed to read label in AG %d\n", ag);
517 return 0;
518 }
519 if (!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);
523 }
524 dbprintf("label = \"%s\"\n", p);
525 }
526 return 0;
527 }
528
529
530 static void
531 version_help(void)
532 {
533 dbprintf(
534 "\n"
535 " set/print feature bits in sb version\n"
536 "\n"
537 " Example:\n"
538 "\n"
539 " 'version' - print current feature bits\n"
540 " 'version extflg' - enable unwritten extents\n"
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"
545 "unwritten extents. The upated version is written into to all AGs.\n"
546 "\n"
547 );
548 }
549
550 static int
551 do_version(xfs_agnumber_t agno, __uint16_t versionnum)
552 {
553 xfs_sb_t tsb;
554
555 if (!get_sb(agno, &tsb))
556 return 0;
557
558 tsb.sb_versionnum = versionnum;
559 libxfs_xlate_sb(iocur_top->data, &tsb,
560 -1, ARCH_CONVERT, XFS_SB_VERSIONNUM);
561 write_cur();
562 return 1;
563 }
564
565 static char *
566 version_string(
567 xfs_sb_t *sbp)
568 {
569 static char s[1024];
570
571 if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_1)
572 strcpy(s, "V1");
573 else if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_2)
574 strcpy(s, "V2");
575 else if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_3)
576 strcpy(s, "V3");
577 else if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4)
578 strcpy(s, "V4");
579
580 if (XFS_SB_VERSION_HASATTR(sbp))
581 strcat(s, ",ATTR");
582 if (XFS_SB_VERSION_HASNLINK(sbp))
583 strcat(s, ",NLINK");
584 if (XFS_SB_VERSION_HASQUOTA(sbp))
585 strcat(s, ",QUOTA");
586 if (XFS_SB_VERSION_HASALIGN(sbp))
587 strcat(s, ",ALIGN");
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))
593 strcat(s, ",DIRV2");
594 if (XFS_SB_VERSION_HASLOGV2(sbp))
595 strcat(s, ",LOGV2");
596 if (XFS_SB_VERSION_HASEXTFLGBIT(sbp))
597 strcat(s, ",EXTFLG");
598 if (XFS_SB_VERSION_HASSECTOR(sbp))
599 strcat(s, ",SECTOR");
600 return s;
601 }
602
603 static int
604 version_f(
605 int argc,
606 char **argv)
607 {
608 __uint16_t version = 0;
609 xfs_agnumber_t ag;
610
611 if (argc == 2) { /* WRITE VERSION */
612
613 if ((x.isreadonly & LIBXFS_ISREADONLY) || !expert_mode) {
614 dbprintf("%s: not in expert mode, writing disabled\n",
615 progname);
616 return 0;
617 }
618
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;
624 break;
625 case XFS_SB_VERSION_2:
626 version = 0x0014 | XFS_SB_VERSION_EXTFLGBIT;
627 break;
628 case XFS_SB_VERSION_3:
629 version = 0x0034 | XFS_SB_VERSION_EXTFLGBIT;
630 break;
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");
635 else
636 version = mp->m_sb.sb_versionnum |
637 XFS_SB_VERSION_EXTFLGBIT;
638 break;
639 }
640 } else {
641 dbprintf("%s: invalid version change command \"%s\"\n",
642 progname, argv[1]);
643 return 0;
644 }
645
646 if (version) {
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 "
651 "in AG %d\n", ag);
652 break;
653 }
654 mp->m_sb.sb_versionnum = version;
655 }
656 }
657 dbprintf("versionnum [0x%x] = %s\n", mp->m_sb.sb_versionnum,
658 version_string(&mp->m_sb));
659 return 0;
660 }