]>
Commit | Line | Data |
---|---|---|
959ef981 | 1 | // SPDX-License-Identifier: GPL-2.0 |
2bd0ea18 | 2 | /* |
da23017d NS |
3 | * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. |
4 | * All Rights Reserved. | |
2bd0ea18 NS |
5 | */ |
6 | ||
6b803e5a CH |
7 | #include "libxfs.h" |
8 | #include "libxlog.h" | |
2bd0ea18 | 9 | #include "command.h" |
2bd0ea18 NS |
10 | #include "type.h" |
11 | #include "faddr.h" | |
12 | #include "fprint.h" | |
13 | #include "field.h" | |
14 | #include "io.h" | |
15 | #include "sb.h" | |
16 | #include "bit.h" | |
17 | #include "output.h" | |
4ca431fc | 18 | #include "init.h" |
2bd0ea18 | 19 | |
9c4e12fb ES |
20 | #define uuid_equal(s,d) (platform_uuid_compare((s),(d)) == 0) |
21 | ||
2bd0ea18 NS |
22 | static int sb_f(int argc, char **argv); |
23 | static void sb_help(void); | |
4ca431fc NS |
24 | static int uuid_f(int argc, char **argv); |
25 | static void uuid_help(void); | |
26 | static int label_f(int argc, char **argv); | |
27 | static void label_help(void); | |
28 | static int version_f(int argc, char **argv); | |
29 | static void version_help(void); | |
2bd0ea18 NS |
30 | |
31 | static const cmdinfo_t sb_cmd = | |
9ee7055c AM |
32 | { "sb", NULL, sb_f, 0, 1, 1, N_("[agno]"), |
33 | N_("set current address to sb header"), sb_help }; | |
4ca431fc | 34 | static const cmdinfo_t uuid_cmd = |
9ee7055c AM |
35 | { "uuid", NULL, uuid_f, 0, 1, 1, N_("[uuid]"), |
36 | N_("write/print FS uuid"), uuid_help }; | |
4ca431fc | 37 | static const cmdinfo_t label_cmd = |
9ee7055c AM |
38 | { "label", NULL, label_f, 0, 1, 1, N_("[label]"), |
39 | N_("write/print FS label"), label_help }; | |
4ca431fc | 40 | static const cmdinfo_t version_cmd = |
9ee7055c AM |
41 | { "version", NULL, version_f, 0, -1, 1, N_("[feature | [vnum fnum]]"), |
42 | N_("set feature bit(s) in the sb version field"), version_help }; | |
2bd0ea18 | 43 | |
4ca431fc NS |
44 | void |
45 | sb_init(void) | |
46 | { | |
47 | add_command(&sb_cmd); | |
48 | add_command(&uuid_cmd); | |
49 | add_command(&label_cmd); | |
50 | add_command(&version_cmd); | |
51 | } | |
2bd0ea18 NS |
52 | |
53 | #define OFF(f) bitize(offsetof(xfs_sb_t, sb_ ## f)) | |
54 | #define SZC(f) szcount(xfs_sb_t, sb_ ## f) | |
55 | const field_t sb_flds[] = { | |
56 | { "magicnum", FLDT_UINT32X, OI(OFF(magicnum)), C1, 0, TYP_NONE }, | |
57 | { "blocksize", FLDT_UINT32D, OI(OFF(blocksize)), C1, 0, TYP_NONE }, | |
58 | { "dblocks", FLDT_DRFSBNO, OI(OFF(dblocks)), C1, 0, TYP_NONE }, | |
59 | { "rblocks", FLDT_DRFSBNO, OI(OFF(rblocks)), C1, 0, TYP_NONE }, | |
60 | { "rextents", FLDT_DRTBNO, OI(OFF(rextents)), C1, 0, TYP_NONE }, | |
61 | { "uuid", FLDT_UUID, OI(OFF(uuid)), C1, 0, TYP_NONE }, | |
62 | { "logstart", FLDT_DFSBNO, OI(OFF(logstart)), C1, 0, TYP_LOG }, | |
63 | { "rootino", FLDT_INO, OI(OFF(rootino)), C1, 0, TYP_INODE }, | |
64 | { "rbmino", FLDT_INO, OI(OFF(rbmino)), C1, 0, TYP_INODE }, | |
65 | { "rsumino", FLDT_INO, OI(OFF(rsumino)), C1, 0, TYP_INODE }, | |
66 | { "rextsize", FLDT_AGBLOCK, OI(OFF(rextsize)), C1, 0, TYP_NONE }, | |
67 | { "agblocks", FLDT_AGBLOCK, OI(OFF(agblocks)), C1, 0, TYP_NONE }, | |
68 | { "agcount", FLDT_AGNUMBER, OI(OFF(agcount)), C1, 0, TYP_NONE }, | |
69 | { "rbmblocks", FLDT_EXTLEN, OI(OFF(rbmblocks)), C1, 0, TYP_NONE }, | |
70 | { "logblocks", FLDT_EXTLEN, OI(OFF(logblocks)), C1, 0, TYP_NONE }, | |
71 | { "versionnum", FLDT_UINT16X, OI(OFF(versionnum)), C1, 0, TYP_NONE }, | |
72 | { "sectsize", FLDT_UINT16D, OI(OFF(sectsize)), C1, 0, TYP_NONE }, | |
73 | { "inodesize", FLDT_UINT16D, OI(OFF(inodesize)), C1, 0, TYP_NONE }, | |
74 | { "inopblock", FLDT_UINT16D, OI(OFF(inopblock)), C1, 0, TYP_NONE }, | |
75 | { "fname", FLDT_CHARNS, OI(OFF(fname)), CI(SZC(fname)), 0, TYP_NONE }, | |
76 | { "blocklog", FLDT_UINT8D, OI(OFF(blocklog)), C1, 0, TYP_NONE }, | |
77 | { "sectlog", FLDT_UINT8D, OI(OFF(sectlog)), C1, 0, TYP_NONE }, | |
78 | { "inodelog", FLDT_UINT8D, OI(OFF(inodelog)), C1, 0, TYP_NONE }, | |
79 | { "inopblog", FLDT_UINT8D, OI(OFF(inopblog)), C1, 0, TYP_NONE }, | |
80 | { "agblklog", FLDT_UINT8D, OI(OFF(agblklog)), C1, 0, TYP_NONE }, | |
81 | { "rextslog", FLDT_UINT8D, OI(OFF(rextslog)), C1, 0, TYP_NONE }, | |
82 | { "inprogress", FLDT_UINT8D, OI(OFF(inprogress)), C1, 0, TYP_NONE }, | |
83 | { "imax_pct", FLDT_UINT8D, OI(OFF(imax_pct)), C1, 0, TYP_NONE }, | |
84 | { "icount", FLDT_UINT64D, OI(OFF(icount)), C1, 0, TYP_NONE }, | |
85 | { "ifree", FLDT_UINT64D, OI(OFF(ifree)), C1, 0, TYP_NONE }, | |
86 | { "fdblocks", FLDT_UINT64D, OI(OFF(fdblocks)), C1, 0, TYP_NONE }, | |
87 | { "frextents", FLDT_UINT64D, OI(OFF(frextents)), C1, 0, TYP_NONE }, | |
88 | { "uquotino", FLDT_INO, OI(OFF(uquotino)), C1, 0, TYP_INODE }, | |
b36eef04 | 89 | { "gquotino", FLDT_INO, OI(OFF(gquotino)), C1, 0, TYP_INODE }, |
2bd0ea18 NS |
90 | { "qflags", FLDT_UINT16X, OI(OFF(qflags)), C1, 0, TYP_NONE }, |
91 | { "flags", FLDT_UINT8X, OI(OFF(flags)), C1, 0, TYP_NONE }, | |
92 | { "shared_vn", FLDT_UINT8D, OI(OFF(shared_vn)), C1, 0, TYP_NONE }, | |
93 | { "inoalignmt", FLDT_EXTLEN, OI(OFF(inoalignmt)), C1, 0, TYP_NONE }, | |
94 | { "unit", FLDT_UINT32D, OI(OFF(unit)), C1, 0, TYP_NONE }, | |
95 | { "width", FLDT_UINT32D, OI(OFF(width)), C1, 0, TYP_NONE }, | |
96 | { "dirblklog", FLDT_UINT8D, OI(OFF(dirblklog)), C1, 0, TYP_NONE }, | |
9440d84d NS |
97 | { "logsectlog", FLDT_UINT8D, OI(OFF(logsectlog)), C1, 0, TYP_NONE }, |
98 | { "logsectsize", FLDT_UINT16D, OI(OFF(logsectsize)), C1, 0, TYP_NONE }, | |
73bf5988 | 99 | { "logsunit", FLDT_UINT32D, OI(OFF(logsunit)), C1, 0, TYP_NONE }, |
465e76a9 | 100 | { "features2", FLDT_UINT32X, OI(OFF(features2)), C1, 0, TYP_NONE }, |
a23fa047 DC |
101 | { "bad_features2", FLDT_UINT32X, OI(OFF(bad_features2)), |
102 | C1, 0, TYP_NONE }, | |
103 | { "features_compat", FLDT_UINT32X, OI(OFF(features_compat)), | |
104 | C1, 0, TYP_NONE }, | |
105 | { "features_ro_compat", FLDT_UINT32X, OI(OFF(features_ro_compat)), | |
106 | C1, 0, TYP_NONE }, | |
107 | { "features_incompat", FLDT_UINT32X, OI(OFF(features_incompat)), | |
108 | C1, 0, TYP_NONE }, | |
109 | { "features_log_incompat", FLDT_UINT32X, OI(OFF(features_log_incompat)), | |
110 | C1, 0, TYP_NONE }, | |
0522f1cc | 111 | { "crc", FLDT_CRC, OI(OFF(crc)), C1, 0, TYP_NONE }, |
061e316e | 112 | { "spino_align", FLDT_EXTLEN, OI(OFF(spino_align)), C1, 0, TYP_NONE }, |
a23fa047 DC |
113 | { "pquotino", FLDT_INO, OI(OFF(pquotino)), C1, 0, TYP_INODE }, |
114 | { "lsn", FLDT_UINT64X, OI(OFF(lsn)), C1, 0, TYP_NONE }, | |
9c4e12fb | 115 | { "meta_uuid", FLDT_UUID, OI(OFF(meta_uuid)), C1, 0, TYP_NONE }, |
2bd0ea18 NS |
116 | { NULL } |
117 | }; | |
118 | ||
4ca431fc NS |
119 | const field_t sb_hfld[] = { |
120 | { "", FLDT_SB, OI(0), C1, 0, TYP_NONE }, | |
121 | { NULL } | |
122 | }; | |
123 | ||
2bd0ea18 NS |
124 | static void |
125 | sb_help(void) | |
126 | { | |
9ee7055c | 127 | dbprintf(_( |
2bd0ea18 NS |
128 | "\n" |
129 | " set allocation group superblock\n" | |
130 | "\n" | |
131 | " Example:\n" | |
132 | "\n" | |
133 | " 'sb 7' - set location to 7th allocation group superblock, set type to 'sb'\n" | |
134 | "\n" | |
9440d84d NS |
135 | " Located in the first sector of each allocation group, the superblock\n" |
136 | " contains the base information for the filesystem.\n" | |
2bd0ea18 NS |
137 | " The superblock in allocation group 0 is the primary. The copies in the\n" |
138 | " remaining allocation groups only serve as backup for filesystem recovery.\n" | |
139 | " The icount/ifree/fdblocks/frextents are only updated in superblock 0.\n" | |
140 | "\n" | |
9ee7055c | 141 | )); |
2bd0ea18 NS |
142 | } |
143 | ||
144 | static int | |
145 | sb_f( | |
146 | int argc, | |
147 | char **argv) | |
148 | { | |
149 | xfs_agnumber_t agno; | |
150 | char *p; | |
151 | ||
152 | if (argc > 1) { | |
153 | agno = (xfs_agnumber_t)strtoul(argv[1], &p, 0); | |
154 | if (*p != '\0' || agno >= mp->m_sb.sb_agcount) { | |
9ee7055c | 155 | dbprintf(_("bad allocation group number %s\n"), argv[1]); |
2bd0ea18 NS |
156 | return 0; |
157 | } | |
158 | cur_agno = agno; | |
159 | } else if (cur_agno == NULLAGNUMBER) | |
160 | cur_agno = 0; | |
161 | ASSERT(typtab[TYP_SB].typnm == TYP_SB); | |
9440d84d NS |
162 | set_cur(&typtab[TYP_SB], |
163 | XFS_AG_DADDR(mp, cur_agno, XFS_SB_DADDR), | |
164 | XFS_FSS_TO_BB(mp, 1), DB_RING_ADD, NULL); | |
2bd0ea18 NS |
165 | return 0; |
166 | } | |
167 | ||
2bd0ea18 NS |
168 | /*ARGSUSED*/ |
169 | int | |
170 | sb_size( | |
171 | void *obj, | |
172 | int startoff, | |
173 | int idx) | |
174 | { | |
175 | return bitize(mp->m_sb.sb_sectsize); | |
176 | } | |
4ca431fc NS |
177 | |
178 | static int | |
179 | get_sb(xfs_agnumber_t agno, xfs_sb_t *sb) | |
180 | { | |
181 | push_cur(); | |
182 | set_cur(&typtab[TYP_SB], | |
183 | XFS_AG_DADDR(mp, agno, XFS_SB_DADDR), | |
184 | XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL); | |
dfc130f3 | 185 | |
4ca431fc | 186 | if (!iocur_top->data) { |
9ee7055c | 187 | dbprintf(_("can't read superblock for AG %u\n"), agno); |
4ca431fc NS |
188 | pop_cur(); |
189 | return 0; | |
190 | } | |
191 | ||
5e656dbb | 192 | libxfs_sb_from_disk(sb, iocur_top->data); |
dfc130f3 | 193 | |
4ca431fc | 194 | if (sb->sb_magicnum != XFS_SB_MAGIC) { |
9ee7055c | 195 | dbprintf(_("bad sb magic # %#x in AG %u\n"), |
4ca431fc | 196 | sb->sb_magicnum, agno); |
dfc130f3 | 197 | return 0; |
4ca431fc | 198 | } |
5e656dbb | 199 | if (!xfs_sb_good_version(sb)) { |
9ee7055c | 200 | dbprintf(_("bad sb version # %#x in AG %u\n"), |
4ca431fc | 201 | sb->sb_versionnum, agno); |
dfc130f3 | 202 | return 0; |
4ca431fc NS |
203 | } |
204 | if (agno == 0 && sb->sb_inprogress != 0) { | |
9ee7055c | 205 | dbprintf(_("mkfs not completed successfully\n")); |
dfc130f3 | 206 | return 0; |
4ca431fc NS |
207 | } |
208 | return 1; | |
209 | } | |
210 | ||
211 | /* workaround craziness in the xlog routines */ | |
19879397 | 212 | int xlog_recover_do_trans(struct xlog *log, struct xlog_recover *t, int p) |
999f0b9c DC |
213 | { |
214 | return 0; | |
215 | } | |
4ca431fc | 216 | |
add013da NS |
217 | int |
218 | sb_logcheck(void) | |
4ca431fc | 219 | { |
7ac353a9 | 220 | int dirty; |
4ca431fc NS |
221 | |
222 | if (mp->m_sb.sb_logstart) { | |
fc83c757 | 223 | if (x.log.dev && x.log.dev != x.data.dev) { |
9ee7055c AM |
224 | dbprintf(_("aborting - external log specified for FS " |
225 | "with an internal log\n")); | |
4ca431fc NS |
226 | return 0; |
227 | } | |
228 | } else { | |
fc83c757 | 229 | if (!x.log.dev || (x.log.dev == x.data.dev)) { |
9ee7055c AM |
230 | dbprintf(_("aborting - no external log specified for FS " |
231 | "with an external log\n")); | |
4ca431fc NS |
232 | return 0; |
233 | } | |
234 | } | |
235 | ||
ca8cc76e | 236 | libxfs_buftarg_init(mp, &x); |
999f0b9c | 237 | |
c42edb2e | 238 | dirty = xlog_is_dirty(mp, mp->m_log); |
7ac353a9 | 239 | if (dirty == -1) { |
9ee7055c | 240 | dbprintf(_("ERROR: cannot find log head/tail, run xfs_repair\n")); |
4ca431fc | 241 | return 0; |
7ac353a9 | 242 | } else if (dirty == 1) { |
9ee7055c | 243 | dbprintf(_( |
4ca431fc NS |
244 | "ERROR: The filesystem has valuable metadata changes in a log which needs to\n" |
245 | "be replayed. Mount the filesystem to replay the log, and unmount it before\n" | |
246 | "re-running %s. If you are unable to mount the filesystem, then use\n" | |
247 | "the xfs_repair -L option to destroy the log and attempt a repair.\n" | |
248 | "Note that destroying the log may cause corruption -- please attempt a mount\n" | |
9ee7055c | 249 | "of the filesystem before doing this.\n"), progname); |
4ca431fc NS |
250 | return 0; |
251 | } | |
7ac353a9 | 252 | /* Log is clean */ |
add013da NS |
253 | return 1; |
254 | } | |
255 | ||
256 | static int | |
257 | sb_logzero(uuid_t *uuidp) | |
258 | { | |
7f725646 BF |
259 | int cycle = XLOG_INIT_CYCLE; |
260 | int error; | |
261 | ||
add013da NS |
262 | if (!sb_logcheck()) |
263 | return 0; | |
4ca431fc | 264 | |
7f725646 BF |
265 | /* |
266 | * The log must always move forward on v5 superblocks. Bump it to the | |
267 | * next cycle. | |
268 | */ | |
2660e653 | 269 | if (xfs_has_crc(mp)) |
7f725646 BF |
270 | cycle = mp->m_log->l_curr_cycle + 1; |
271 | ||
9ee7055c | 272 | dbprintf(_("Clearing log and setting UUID\n")); |
4ca431fc | 273 | |
1c12a814 | 274 | error = libxfs_log_clear(mp->m_logdev_targp, NULL, |
4ca431fc NS |
275 | XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart), |
276 | (xfs_extlen_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks), | |
277 | uuidp, | |
2660e653 | 278 | xfs_has_logv2(mp) ? 2 : 1, |
571a78a7 | 279 | mp->m_sb.sb_logsunit, XLOG_FMT, cycle, true); |
7f725646 | 280 | if (error) { |
9ee7055c | 281 | dbprintf(_("ERROR: cannot clear the log\n")); |
4ca431fc NS |
282 | return 0; |
283 | } | |
7f725646 | 284 | |
4ca431fc NS |
285 | return 1; |
286 | } | |
287 | ||
288 | ||
289 | static void | |
290 | uuid_help(void) | |
291 | { | |
9ee7055c | 292 | dbprintf(_( |
4ca431fc NS |
293 | "\n" |
294 | " write/print FS uuid\n" | |
295 | "\n" | |
296 | " Example:\n" | |
297 | "\n" | |
298 | " 'uuid' - print UUID\n" | |
299 | " 'uuid 01234567-0123-0123-0123-0123456789ab' - write UUID\n" | |
300 | " 'uuid generate' - generate and write\n" | |
301 | " 'uuid rewrite' - copy UUID from SB 0\n" | |
302 | "\n" | |
303 | "The print function checks the UUID in each SB and will warn if the UUIDs\n" | |
304 | "differ between AGs (the log is not checked). The write commands will\n" | |
305 | "set the uuid in all AGs to either a specified value, a newly generated\n" | |
306 | "value or the value found in the first superblock (SB 0) respectively.\n" | |
307 | "As a side effect of writing the UUID, the log is cleared (which is fine\n" | |
308 | "on a CLEANLY unmounted FS).\n" | |
309 | "\n" | |
9ee7055c | 310 | )); |
4ca431fc NS |
311 | } |
312 | ||
313 | static uuid_t * | |
314 | do_uuid(xfs_agnumber_t agno, uuid_t *uuid) | |
315 | { | |
316 | xfs_sb_t tsb; | |
317 | static uuid_t uu; | |
318 | ||
319 | if (!get_sb(agno, &tsb)) | |
320 | return NULL; | |
321 | ||
322 | if (!uuid) { /* get uuid */ | |
323 | memcpy(&uu, &tsb.sb_uuid, sizeof(uuid_t)); | |
324 | pop_cur(); | |
325 | return &uu; | |
326 | } | |
327 | /* set uuid */ | |
9c4e12fb ES |
328 | if (!xfs_sb_version_hascrc(&tsb)) |
329 | goto write; | |
330 | /* | |
331 | * If we have CRCs, and this UUID differs from that stamped in the | |
332 | * metadata, set the incompat flag and copy the old one to the | |
333 | * metadata-specific location. | |
334 | * | |
335 | * If we are setting the user-visible UUID back to match the metadata | |
336 | * UUID, clear the metadata-specific location and the incompat flag. | |
337 | */ | |
338 | if (!xfs_sb_version_hasmetauuid(&tsb) && | |
339 | !uuid_equal(uuid, &mp->m_sb.sb_meta_uuid)) { | |
340 | mp->m_sb.sb_features_incompat |= XFS_SB_FEAT_INCOMPAT_META_UUID; | |
341 | tsb.sb_features_incompat |= XFS_SB_FEAT_INCOMPAT_META_UUID; | |
342 | memcpy(&tsb.sb_meta_uuid, &tsb.sb_uuid, sizeof(uuid_t)); | |
343 | } else if (xfs_sb_version_hasmetauuid(&tsb) && | |
344 | uuid_equal(uuid, &mp->m_sb.sb_meta_uuid)) { | |
345 | memset(&tsb.sb_meta_uuid, 0, sizeof(uuid_t)); | |
346 | /* Write those zeros now; it's ignored once we clear the flag */ | |
347 | libxfs_sb_to_disk(iocur_top->data, &tsb); | |
348 | mp->m_sb.sb_features_incompat &= | |
349 | ~XFS_SB_FEAT_INCOMPAT_META_UUID; | |
350 | tsb.sb_features_incompat &= ~XFS_SB_FEAT_INCOMPAT_META_UUID; | |
351 | } | |
352 | ||
353 | write: | |
4ca431fc | 354 | memcpy(&tsb.sb_uuid, uuid, sizeof(uuid_t)); |
19ebedcf | 355 | libxfs_sb_to_disk(iocur_top->data, &tsb); |
4ca431fc NS |
356 | write_cur(); |
357 | return uuid; | |
358 | } | |
359 | ||
360 | static int | |
361 | uuid_f( | |
362 | int argc, | |
363 | char **argv) | |
364 | { | |
365 | char bp[40]; | |
366 | xfs_agnumber_t agno; | |
367 | uuid_t uu; | |
368 | uuid_t *uup = NULL; | |
369 | ||
370 | if (argc != 1 && argc != 2) { | |
9ee7055c | 371 | dbprintf(_("invalid parameters\n")); |
4ca431fc NS |
372 | return 0; |
373 | } | |
374 | ||
375 | if (argc == 2) { /* WRITE UUID */ | |
376 | ||
23d88955 | 377 | if ((x.flags & LIBXFS_ISREADONLY) || !expert_mode) { |
9ee7055c | 378 | dbprintf(_("%s: not in expert mode, writing disabled\n"), |
4ca431fc NS |
379 | progname); |
380 | return 0; | |
381 | } | |
b95b770f DW |
382 | if (xfs_sb_version_needsrepair(&mp->m_sb)) { |
383 | dbprintf(_("%s: filesystem needs xfs_repair\n"), | |
384 | progname); | |
385 | return 0; | |
386 | } | |
4ca431fc NS |
387 | |
388 | if (!strcasecmp(argv[1], "generate")) { | |
4d32d744 | 389 | platform_uuid_generate(&uu); |
4ca431fc | 390 | } else if (!strcasecmp(argv[1], "nil")) { |
4d32d744 | 391 | platform_uuid_clear(&uu); |
4ca431fc NS |
392 | } else if (!strcasecmp(argv[1], "rewrite")) { |
393 | uup = do_uuid(0, NULL); | |
394 | if (!uup) { | |
9ee7055c | 395 | dbprintf(_("failed to read UUID from AG 0\n")); |
4ca431fc NS |
396 | return 0; |
397 | } | |
6699422d | 398 | memcpy(&uu, uup, sizeof(uuid_t)); |
4d32d744 | 399 | platform_uuid_unparse(&uu, bp); |
9ee7055c | 400 | dbprintf(_("old UUID = %s\n"), bp); |
9c4e12fb ES |
401 | } else if (!strcasecmp(argv[1], "restore")) { |
402 | xfs_sb_t tsb; | |
403 | ||
404 | if (!get_sb(0, &tsb)) | |
405 | return 0; | |
406 | ||
407 | /* Not set; nothing to do. Success! */ | |
408 | if (!xfs_sb_version_hasmetauuid(&tsb)) | |
409 | return 0; | |
f8149110 | 410 | |
9c4e12fb | 411 | memcpy(&uu, mp->m_sb.sb_meta_uuid, sizeof(uuid_t)); |
4ca431fc | 412 | } else { |
4d32d744 | 413 | if (platform_uuid_parse(argv[1], &uu)) { |
9ee7055c | 414 | dbprintf(_("invalid UUID\n")); |
4ca431fc NS |
415 | return 0; |
416 | } | |
417 | } | |
418 | ||
ff1f79a7 | 419 | /* clear the log (setting uuid) if it's not dirty */ |
add013da | 420 | if (!sb_logzero(&uu)) |
4ca431fc NS |
421 | return 0; |
422 | ||
9ee7055c | 423 | dbprintf(_("writing all SBs\n")); |
4ca431fc NS |
424 | for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) |
425 | if (!do_uuid(agno, &uu)) { | |
9ee7055c | 426 | dbprintf(_("failed to set UUID in AG %d\n"), agno); |
4ca431fc NS |
427 | break; |
428 | } | |
429 | ||
4d32d744 | 430 | platform_uuid_unparse(&uu, bp); |
9ee7055c | 431 | dbprintf(_("new UUID = %s\n"), bp); |
4ca431fc NS |
432 | return 0; |
433 | ||
434 | } else { /* READ+CHECK UUID */ | |
dfc130f3 | 435 | |
4ca431fc NS |
436 | for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) { |
437 | uup = do_uuid(agno, NULL); | |
438 | if (!uup) { | |
9ee7055c | 439 | dbprintf(_("failed to read UUID from AG %d\n"), |
4ca431fc NS |
440 | agno); |
441 | return 0; | |
442 | } | |
443 | if (agno) { | |
444 | if (memcmp(&uu, uup, sizeof(uuid_t))) { | |
9ee7055c AM |
445 | dbprintf(_("warning: UUID in AG %d " |
446 | "differs to the primary SB\n"), | |
4ca431fc NS |
447 | agno); |
448 | break; | |
449 | } | |
450 | } else { | |
6699422d | 451 | memcpy(&uu, uup, sizeof(uuid_t)); |
4ca431fc NS |
452 | } |
453 | } | |
454 | if (mp->m_sb.sb_logstart) { | |
fc83c757 | 455 | if (x.log.dev && x.log.dev != x.data.dev) |
9ee7055c AM |
456 | dbprintf(_("warning - external log specified " |
457 | "for FS with an internal log\n")); | |
fc83c757 | 458 | } else if (!x.log.dev || (x.log.dev == x.data.dev)) { |
9ee7055c AM |
459 | dbprintf(_("warning - no external log specified " |
460 | "for FS with an external log\n")); | |
4ca431fc NS |
461 | } |
462 | ||
4d32d744 | 463 | platform_uuid_unparse(&uu, bp); |
9ee7055c | 464 | dbprintf(_("UUID = %s\n"), bp); |
4ca431fc NS |
465 | } |
466 | ||
467 | return 0; | |
468 | } | |
469 | ||
470 | ||
471 | static void | |
472 | label_help(void) | |
473 | { | |
9ee7055c | 474 | dbprintf(_( |
4ca431fc NS |
475 | "\n" |
476 | " write/print FS label\n" | |
477 | "\n" | |
478 | " Example:\n" | |
479 | "\n" | |
480 | " 'label' - print label\n" | |
481 | " 'label 123456789012' - write label\n" | |
482 | " 'label --' - write an empty label\n" | |
483 | "\n" | |
484 | "The print function checks the label in each SB and will warn if the labels\n" | |
485 | "differ between AGs. The write commands will set the label in all AGs to the\n" | |
486 | "specified value. The maximum length of a label is 12 characters - use of a\n" | |
487 | "longer label will result in truncation and a warning will be issued.\n" | |
488 | "\n" | |
9ee7055c | 489 | )); |
4ca431fc NS |
490 | } |
491 | ||
492 | static char * | |
493 | do_label(xfs_agnumber_t agno, char *label) | |
494 | { | |
495 | size_t len; | |
496 | xfs_sb_t tsb; | |
dfc130f3 | 497 | static char lbl[sizeof(tsb.sb_fname) + 1]; |
4ca431fc NS |
498 | |
499 | if (!get_sb(agno, &tsb)) | |
500 | return NULL; | |
501 | ||
502 | memset(&lbl[0], 0, sizeof(lbl)); | |
503 | ||
504 | if (!label) { /* get label */ | |
505 | pop_cur(); | |
506 | memcpy(&lbl[0], &tsb.sb_fname, sizeof(tsb.sb_fname)); | |
507 | return &lbl[0]; | |
508 | } | |
509 | /* set label */ | |
510 | if ((len = strlen(label)) > sizeof(tsb.sb_fname)) { | |
511 | if (agno == 0) | |
9ee7055c | 512 | dbprintf(_("%s: truncating label length from %d to %d\n"), |
4ca431fc NS |
513 | progname, (int)len, (int)sizeof(tsb.sb_fname)); |
514 | len = sizeof(tsb.sb_fname); | |
515 | } | |
516 | if ( len == 2 && | |
517 | (strcmp(label, "\"\"") == 0 || | |
518 | strcmp(label, "''") == 0 || | |
519 | strcmp(label, "--") == 0) ) | |
520 | label[0] = label[1] = '\0'; | |
521 | memset(&tsb.sb_fname, 0, sizeof(tsb.sb_fname)); | |
522 | memcpy(&tsb.sb_fname, label, len); | |
523 | memcpy(&lbl[0], &tsb.sb_fname, sizeof(tsb.sb_fname)); | |
19ebedcf | 524 | libxfs_sb_to_disk(iocur_top->data, &tsb); |
4ca431fc NS |
525 | write_cur(); |
526 | return &lbl[0]; | |
527 | } | |
528 | ||
529 | static int | |
530 | label_f( | |
531 | int argc, | |
532 | char **argv) | |
533 | { | |
534 | char *p = NULL; | |
535 | xfs_sb_t sb; | |
536 | xfs_agnumber_t ag; | |
537 | ||
538 | if (argc != 1 && argc != 2) { | |
9ee7055c | 539 | dbprintf(_("invalid parameters\n")); |
4ca431fc NS |
540 | return 0; |
541 | } | |
542 | ||
543 | if (argc == 2) { /* WRITE LABEL */ | |
544 | ||
23d88955 | 545 | if ((x.flags & LIBXFS_ISREADONLY) || !expert_mode) { |
9ee7055c | 546 | dbprintf(_("%s: not in expert mode, writing disabled\n"), |
4ca431fc NS |
547 | progname); |
548 | return 0; | |
549 | } | |
550 | ||
b95b770f DW |
551 | if (xfs_sb_version_needsrepair(&mp->m_sb)) { |
552 | dbprintf(_("%s: filesystem needs xfs_repair\n"), | |
553 | progname); | |
554 | return 0; | |
555 | } | |
556 | ||
9ee7055c | 557 | dbprintf(_("writing all SBs\n")); |
4ca431fc NS |
558 | for (ag = 0; ag < mp->m_sb.sb_agcount; ag++) |
559 | if ((p = do_label(ag, argv[1])) == NULL) { | |
9ee7055c | 560 | dbprintf(_("failed to set label in AG %d\n"), ag); |
4ca431fc NS |
561 | break; |
562 | } | |
9ee7055c | 563 | dbprintf(_("new label = \"%s\"\n"), p); |
4ca431fc NS |
564 | |
565 | } else { /* READ LABEL */ | |
566 | ||
567 | for (ag = 0; ag < mp->m_sb.sb_agcount; ag++) { | |
568 | p = do_label(ag, NULL); | |
569 | if (!p) { | |
9ee7055c | 570 | dbprintf(_("failed to read label in AG %d\n"), ag); |
4ca431fc NS |
571 | return 0; |
572 | } | |
573 | if (!ag) | |
574 | memcpy(&sb.sb_fname, p, sizeof(sb.sb_fname)); | |
575 | else if (memcmp(&sb.sb_fname, p, sizeof(sb.sb_fname))) | |
9ee7055c | 576 | dbprintf(_("warning: AG %d label differs\n"), ag); |
4ca431fc | 577 | } |
9ee7055c | 578 | dbprintf(_("label = \"%s\"\n"), p); |
4ca431fc NS |
579 | } |
580 | return 0; | |
581 | } | |
582 | ||
583 | ||
584 | static void | |
585 | version_help(void) | |
586 | { | |
9ee7055c | 587 | dbprintf(_( |
4ca431fc NS |
588 | "\n" |
589 | " set/print feature bits in sb version\n" | |
590 | "\n" | |
591 | " Example:\n" | |
592 | "\n" | |
593 | " 'version' - print current feature bits\n" | |
594 | " 'version extflg' - enable unwritten extents\n" | |
70476e54 NS |
595 | " 'version attr1' - enable v1 inline extended attributes\n" |
596 | " 'version attr2' - enable v2 inline extended attributes\n" | |
66997473 | 597 | " 'version log2' - enable v2 log format\n" |
4ca431fc NS |
598 | "\n" |
599 | "The version function prints currently enabled features for a filesystem\n" | |
ff1f79a7 | 600 | "according to the version field of its primary superblock.\n" |
4ca431fc | 601 | "It can also be used to enable selected features, such as support for\n" |
ff1f79a7 | 602 | "unwritten extents. The updated version is written into all AGs.\n" |
4ca431fc | 603 | "\n" |
9ee7055c | 604 | )); |
4ca431fc NS |
605 | } |
606 | ||
607 | static int | |
14f8b681 | 608 | do_version(xfs_agnumber_t agno, uint16_t version, uint32_t features) |
4ca431fc NS |
609 | { |
610 | xfs_sb_t tsb; | |
611 | ||
612 | if (!get_sb(agno, &tsb)) | |
613 | return 0; | |
614 | ||
72f11257 ES |
615 | if (xfs_sb_has_mismatched_features2(&tsb)) { |
616 | dbprintf(_("Superblock has mismatched features2 fields, " | |
617 | "skipping modification\n")); | |
618 | return 0; | |
619 | } | |
620 | ||
66997473 | 621 | if ((version & XFS_SB_VERSION_LOGV2BIT) && |
5e656dbb | 622 | !xfs_sb_version_haslogv2(&tsb)) { |
66997473 | 623 | tsb.sb_logsunit = 1; |
66997473 NS |
624 | } |
625 | ||
70476e54 NS |
626 | tsb.sb_versionnum = version; |
627 | tsb.sb_features2 = features; | |
72f11257 | 628 | tsb.sb_bad_features2 = features; |
19ebedcf | 629 | libxfs_sb_to_disk(iocur_top->data, &tsb); |
4ca431fc NS |
630 | write_cur(); |
631 | return 1; | |
632 | } | |
633 | ||
634 | static char * | |
635 | version_string( | |
575f24e5 | 636 | struct xfs_mount *mp) |
4ca431fc | 637 | { |
575f24e5 | 638 | static char s[1024]; |
4ca431fc | 639 | |
575f24e5 | 640 | if (XFS_SB_VERSION_NUM(&mp->m_sb) == XFS_SB_VERSION_1) |
4ca431fc | 641 | strcpy(s, "V1"); |
575f24e5 | 642 | else if (XFS_SB_VERSION_NUM(&mp->m_sb) == XFS_SB_VERSION_2) |
4ca431fc | 643 | strcpy(s, "V2"); |
575f24e5 | 644 | else if (XFS_SB_VERSION_NUM(&mp->m_sb) == XFS_SB_VERSION_3) |
4ca431fc | 645 | strcpy(s, "V3"); |
575f24e5 | 646 | else if (XFS_SB_VERSION_NUM(&mp->m_sb) == XFS_SB_VERSION_4) |
4ca431fc | 647 | strcpy(s, "V4"); |
575f24e5 | 648 | else if (XFS_SB_VERSION_NUM(&mp->m_sb) == XFS_SB_VERSION_5) |
a23fa047 | 649 | strcpy(s, "V5"); |
4ca431fc | 650 | |
5f6f3660 DC |
651 | /* |
652 | * We assume the state of these features now, so macros don't exist for | |
653 | * them any more. | |
654 | */ | |
2660e653 | 655 | if (xfs_has_nlink(mp)) |
5f6f3660 | 656 | strcat(s, ",NLINK"); |
575f24e5 | 657 | if (mp->m_sb.sb_versionnum & XFS_SB_VERSION_SHAREDBIT) |
5f6f3660 | 658 | strcat(s, ",SHARED"); |
575f24e5 | 659 | if (mp->m_sb.sb_versionnum & XFS_SB_VERSION_DIRV2BIT) |
5f6f3660 DC |
660 | strcat(s, ",DIRV2"); |
661 | ||
2660e653 | 662 | if (xfs_has_attr(mp)) |
4ca431fc | 663 | strcat(s, ",ATTR"); |
2660e653 | 664 | if (xfs_has_quota(mp)) |
4ca431fc | 665 | strcat(s, ",QUOTA"); |
2660e653 | 666 | if (xfs_has_align(mp)) |
4ca431fc | 667 | strcat(s, ",ALIGN"); |
2660e653 | 668 | if (xfs_has_dalign(mp)) |
4ca431fc | 669 | strcat(s, ",DALIGN"); |
2660e653 | 670 | if (xfs_has_logv2(mp)) |
4ca431fc | 671 | strcat(s, ",LOGV2"); |
b7fdeb4d | 672 | /* This feature is required now as well */ |
2660e653 | 673 | if (xfs_has_extflg(mp)) |
4ca431fc | 674 | strcat(s, ",EXTFLG"); |
2660e653 | 675 | if (xfs_has_sector(mp)) |
4ca431fc | 676 | strcat(s, ",SECTOR"); |
2660e653 | 677 | if (xfs_has_asciici(mp)) |
51ca7008 | 678 | strcat(s, ",ASCII_CI"); |
2660e653 | 679 | if (mp->m_sb.sb_versionnum & XFS_SB_VERSION_MOREBITSBIT) |
ca86e759 | 680 | strcat(s, ",MOREBITS"); |
2660e653 | 681 | if (xfs_has_attr2(mp)) |
ca86e759 | 682 | strcat(s, ",ATTR2"); |
2660e653 | 683 | if (xfs_has_lazysbcount(mp)) |
cdded3d8 | 684 | strcat(s, ",LAZYSBCOUNT"); |
2660e653 | 685 | if (xfs_has_projid32(mp)) |
22bc10ed | 686 | strcat(s, ",PROJID32BIT"); |
2660e653 | 687 | if (xfs_has_crc(mp)) |
a23fa047 | 688 | strcat(s, ",CRC"); |
2660e653 | 689 | if (xfs_has_ftype(mp)) |
42737f1a | 690 | strcat(s, ",FTYPE"); |
2660e653 | 691 | if (xfs_has_finobt(mp)) |
b7fc3b36 | 692 | strcat(s, ",FINOBT"); |
2660e653 | 693 | if (xfs_has_sparseinodes(mp)) |
b8db0171 | 694 | strcat(s, ",SPARSE_INODES"); |
2660e653 | 695 | if (xfs_has_metauuid(mp)) |
9c4e12fb | 696 | strcat(s, ",META_UUID"); |
2660e653 | 697 | if (xfs_has_rmapbt(mp)) |
f810b1bc | 698 | strcat(s, ",RMAPBT"); |
2660e653 | 699 | if (xfs_has_reflink(mp)) |
9fb2cb27 | 700 | strcat(s, ",REFLINK"); |
2660e653 | 701 | if (xfs_has_inobtcounts(mp)) |
13b89172 | 702 | strcat(s, ",INOBTCNT"); |
2660e653 | 703 | if (xfs_has_bigtime(mp)) |
344f38a9 | 704 | strcat(s, ",BIGTIME"); |
2660e653 | 705 | if (xfs_has_needsrepair(mp)) |
67b8ca98 | 706 | strcat(s, ",NEEDSREPAIR"); |
d7eb8fbd CB |
707 | if (xfs_has_large_extent_counts(mp)) |
708 | strcat(s, ",NREXT64"); | |
a4bdbcab DW |
709 | if (xfs_has_exchange_range(mp)) |
710 | strcat(s, ",EXCHANGE"); | |
d5c47fe4 DW |
711 | if (xfs_has_parent(mp)) |
712 | strcat(s, ",PARENT"); | |
4ca431fc NS |
713 | return s; |
714 | } | |
715 | ||
a23fa047 DC |
716 | /* |
717 | * XXX: this only supports reading and writing to version 4 superblock fields. | |
718 | * V5 superblocks always define certain V4 feature bits - they are blocked from | |
719 | * being changed if a V5 sb is detected, but otherwise v5 superblock features | |
720 | * are not handled here. | |
721 | */ | |
4ca431fc NS |
722 | static int |
723 | version_f( | |
724 | int argc, | |
725 | char **argv) | |
726 | { | |
14f8b681 DW |
727 | uint16_t version = 0; |
728 | uint32_t features = 0; | |
3bc1fdd4 | 729 | unsigned long old_mfeatures = 0; |
4ca431fc NS |
730 | xfs_agnumber_t ag; |
731 | ||
732 | if (argc == 2) { /* WRITE VERSION */ | |
733 | ||
23d88955 | 734 | if ((x.flags & LIBXFS_ISREADONLY) || !expert_mode) { |
9ee7055c | 735 | dbprintf(_("%s: not in expert mode, writing disabled\n"), |
4ca431fc NS |
736 | progname); |
737 | return 0; | |
738 | } | |
739 | ||
740 | /* Logic here derived from the IRIX xfs_chver(1M) script. */ | |
741 | if (!strcasecmp(argv[1], "extflg")) { | |
742 | switch (XFS_SB_VERSION_NUM(&mp->m_sb)) { | |
743 | case XFS_SB_VERSION_1: | |
744 | version = 0x0004 | XFS_SB_VERSION_EXTFLGBIT; | |
745 | break; | |
746 | case XFS_SB_VERSION_2: | |
747 | version = 0x0014 | XFS_SB_VERSION_EXTFLGBIT; | |
748 | break; | |
749 | case XFS_SB_VERSION_3: | |
750 | version = 0x0034 | XFS_SB_VERSION_EXTFLGBIT; | |
751 | break; | |
752 | case XFS_SB_VERSION_4: | |
b7fdeb4d CH |
753 | if (mp->m_sb.sb_versionnum & |
754 | XFS_SB_VERSION_EXTFLGBIT) | |
a23fa047 DC |
755 | dbprintf( |
756 | _("unwritten extents flag is already enabled\n")); | |
4ca431fc NS |
757 | else |
758 | version = mp->m_sb.sb_versionnum | | |
759 | XFS_SB_VERSION_EXTFLGBIT; | |
760 | break; | |
a23fa047 DC |
761 | case XFS_SB_VERSION_5: |
762 | dbprintf( | |
763 | _("unwritten extents always enabled for v5 superblocks.\n")); | |
764 | break; | |
4ca431fc | 765 | } |
66997473 NS |
766 | } else if (!strcasecmp(argv[1], "log2")) { |
767 | switch (XFS_SB_VERSION_NUM(&mp->m_sb)) { | |
768 | case XFS_SB_VERSION_1: | |
769 | version = 0x0004 | XFS_SB_VERSION_LOGV2BIT; | |
770 | break; | |
771 | case XFS_SB_VERSION_2: | |
772 | version = 0x0014 | XFS_SB_VERSION_LOGV2BIT; | |
773 | break; | |
774 | case XFS_SB_VERSION_3: | |
775 | version = 0x0034 | XFS_SB_VERSION_LOGV2BIT; | |
776 | break; | |
777 | case XFS_SB_VERSION_4: | |
2660e653 | 778 | if (xfs_has_logv2(mp)) |
a23fa047 DC |
779 | dbprintf( |
780 | _("version 2 log format is already in use\n")); | |
66997473 NS |
781 | else |
782 | version = mp->m_sb.sb_versionnum | | |
783 | XFS_SB_VERSION_LOGV2BIT; | |
784 | break; | |
a23fa047 DC |
785 | case XFS_SB_VERSION_5: |
786 | dbprintf( | |
787 | _("Version 2 logs always enabled for v5 superblocks.\n")); | |
788 | break; | |
66997473 | 789 | } |
a23fa047 DC |
790 | } else if (XFS_SB_VERSION_NUM(&mp->m_sb) == XFS_SB_VERSION_5) { |
791 | dbprintf( | |
792 | _("%s: Cannot change %s on v5 superblocks.\n"), | |
793 | progname, argv[1]); | |
794 | return 0; | |
70476e54 | 795 | } else if (!strcasecmp(argv[1], "attr1")) { |
a23fa047 | 796 | |
2660e653 | 797 | if (xfs_has_attr2(mp)) { |
70476e54 NS |
798 | if (!(mp->m_sb.sb_features2 &= |
799 | ~XFS_SB_VERSION2_ATTR2BIT)) | |
800 | mp->m_sb.sb_versionnum &= | |
801 | ~XFS_SB_VERSION_MOREBITSBIT; | |
802 | } | |
5e656dbb | 803 | xfs_sb_version_addattr(&mp->m_sb); |
70476e54 NS |
804 | version = mp->m_sb.sb_versionnum; |
805 | features = mp->m_sb.sb_features2; | |
806 | } else if (!strcasecmp(argv[1], "attr2")) { | |
5e656dbb BN |
807 | xfs_sb_version_addattr(&mp->m_sb); |
808 | xfs_sb_version_addattr2(&mp->m_sb); | |
22bc10ed AM |
809 | version = mp->m_sb.sb_versionnum; |
810 | features = mp->m_sb.sb_features2; | |
811 | } else if (!strcasecmp(argv[1], "projid32bit")) { | |
3bc1fdd4 | 812 | xfs_sb_version_addprojid32(&mp->m_sb); |
70476e54 NS |
813 | version = mp->m_sb.sb_versionnum; |
814 | features = mp->m_sb.sb_features2; | |
4ca431fc | 815 | } else { |
9ee7055c | 816 | dbprintf(_("%s: invalid version change command \"%s\"\n"), |
4ca431fc NS |
817 | progname, argv[1]); |
818 | return 0; | |
819 | } | |
820 | ||
821 | if (version) { | |
9ee7055c | 822 | dbprintf(_("writing all SBs\n")); |
4ca431fc | 823 | for (ag = 0; ag < mp->m_sb.sb_agcount; ag++) |
70476e54 | 824 | if (!do_version(ag, version, features)) { |
9ee7055c AM |
825 | dbprintf(_("failed to set versionnum " |
826 | "in AG %d\n"), ag); | |
4ca431fc NS |
827 | break; |
828 | } | |
829 | mp->m_sb.sb_versionnum = version; | |
70476e54 | 830 | mp->m_sb.sb_features2 = features; |
3bc1fdd4 DC |
831 | mp->m_features &= ~XFS_FEAT_ATTR2; |
832 | mp->m_features |= libxfs_sb_version_to_features(&mp->m_sb); | |
4ca431fc NS |
833 | } |
834 | } | |
d2df702b NS |
835 | |
836 | if (argc == 3) { /* VERSIONNUM + FEATURES2 */ | |
837 | char *sp; | |
838 | ||
839 | version = mp->m_sb.sb_versionnum; | |
840 | features = mp->m_sb.sb_features2; | |
841 | mp->m_sb.sb_versionnum = strtoul(argv[1], &sp, 0); | |
842 | mp->m_sb.sb_features2 = strtoul(argv[2], &sp, 0); | |
3bc1fdd4 DC |
843 | old_mfeatures = mp->m_features; |
844 | mp->m_features = libxfs_sb_version_to_features(&mp->m_sb); | |
d2df702b NS |
845 | } |
846 | ||
9ee7055c | 847 | dbprintf(_("versionnum [0x%x+0x%x] = %s\n"), mp->m_sb.sb_versionnum, |
575f24e5 | 848 | mp->m_sb.sb_features2, version_string(mp)); |
d2df702b NS |
849 | |
850 | if (argc == 3) { /* now reset... */ | |
851 | mp->m_sb.sb_versionnum = version; | |
852 | mp->m_sb.sb_features2 = features; | |
3bc1fdd4 | 853 | mp->m_features = old_mfeatures; |
d2df702b NS |
854 | return 0; |
855 | } | |
856 | ||
4ca431fc NS |
857 | return 0; |
858 | } |