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