]>
Commit | Line | Data |
---|---|---|
2bd0ea18 | 1 | /* |
cc08d43e | 2 | * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. |
2bd0ea18 NS |
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 | ||
d321ceac | 33 | #include <libxlog.h> |
2bd0ea18 NS |
34 | #include "avl.h" |
35 | #include "avl64.h" | |
36 | #include "globals.h" | |
37 | #include "versions.h" | |
38 | #include "agheader.h" | |
39 | #include "protos.h" | |
40 | #include "incore.h" | |
41 | #include "err_protos.h" | |
42 | ||
43 | #define rounddown(x, y) (((x)/(y))*(y)) | |
44 | ||
45 | extern void phase1(xfs_mount_t *); | |
d321ceac | 46 | extern void phase2(xfs_mount_t *); |
2bd0ea18 NS |
47 | extern void phase3(xfs_mount_t *); |
48 | extern void phase4(xfs_mount_t *); | |
49 | extern void phase5(xfs_mount_t *); | |
50 | extern void phase6(xfs_mount_t *); | |
51 | extern void phase7(xfs_mount_t *); | |
52 | extern void incore_init(xfs_mount_t *); | |
53 | ||
54 | #define XR_MAX_SECT_SIZE (64 * 1024) | |
55 | ||
56 | /* | |
57 | * option tables for getsubopt calls | |
58 | */ | |
59 | ||
60 | /* | |
61 | * -o (user-supplied override options) | |
62 | */ | |
63 | ||
64 | char *o_opts[] = { | |
65 | #define ASSUME_XFS 0 | |
66 | "assume_xfs", | |
67 | #define PRE_65_BETA 1 | |
68 | "fs_is_pre_65_beta", | |
69 | NULL | |
70 | }; | |
71 | ||
72 | static void | |
73 | usage(void) | |
74 | { | |
42a564ab | 75 | do_warn("Usage: %s [-nLvV] [-o subopt[=value]] [-l logdev] [-r rtdev] devname\n", |
2bd0ea18 NS |
76 | progname); |
77 | exit(1); | |
78 | } | |
79 | ||
80 | static char *err_message[] = { | |
81 | "no error", | |
82 | "bad magic number", | |
83 | "bad blocksize field", | |
84 | "bad blocksize log field", | |
85 | "bad version number", | |
86 | "filesystem mkfs-in-progress bit set", | |
87 | "inconsistent filesystem geometry information", | |
88 | "bad inode size or inconsistent with number of inodes/block", | |
89 | "bad sector size", | |
90 | "AGF geometry info conflicts with filesystem geometry", | |
91 | "AGI geometry info conflicts with filesystem geometry", | |
92 | "AG superblock geometry info conflicts with filesystem geometry", | |
93 | "attempted to perform I/O beyond EOF", | |
94 | "inconsistent filesystem geometry in realtime filesystem component", | |
95 | "maximum indicated percentage of inodes > 100%", | |
96 | "inconsistent inode alignment value", | |
97 | "not enough secondary superblocks with matching geometry", | |
98 | "bad stripe unit in superblock", | |
99 | "bad stripe width in superblock", | |
100 | "bad shared version number in superblock" | |
101 | }; | |
102 | ||
103 | char * | |
104 | err_string(int err_code) | |
105 | { | |
106 | if (err_code < XR_OK || err_code >= XR_BAD_ERR_CODE) | |
107 | do_abort("bad error code - %d\n", err_code); | |
108 | ||
109 | return(err_message[err_code]); | |
110 | } | |
111 | ||
112 | static void | |
113 | noval(char opt, char *tbl[], int idx) | |
114 | { | |
115 | do_warn("-%c %s option cannot have a value\n", opt, tbl[idx]); | |
116 | usage(); | |
117 | } | |
118 | ||
119 | static void | |
120 | respec(char opt, char *tbl[], int idx) | |
121 | { | |
122 | do_warn("-%c ", opt); | |
123 | if (tbl) | |
124 | do_warn("%s ", tbl[idx]); | |
125 | do_warn("option respecified\n"); | |
126 | usage(); | |
127 | } | |
128 | ||
129 | static void | |
130 | unknown(char opt, char *s) | |
131 | { | |
132 | do_warn("unknown option -%c %s\n", opt, s); | |
133 | usage(); | |
134 | } | |
135 | ||
136 | /* | |
137 | * sets only the global argument flags and variables | |
138 | */ | |
139 | void | |
140 | process_args(int argc, char **argv) | |
141 | { | |
142 | char *p; | |
143 | int c; | |
144 | ||
145 | log_spec = 0; | |
146 | fs_is_dirty = 0; | |
147 | verbose = 0; | |
148 | no_modify = 0; | |
149 | isa_file = 0; | |
d321ceac | 150 | zap_log = 0; |
2bd0ea18 NS |
151 | dumpcore = 0; |
152 | full_backptrs = 0; | |
153 | delete_attr_ok = 1; | |
154 | force_geo = 0; | |
155 | assume_xfs = 0; | |
156 | clear_sunit = 0; | |
157 | sb_inoalignmt = 0; | |
158 | sb_unit = 0; | |
159 | sb_width = 0; | |
160 | fs_attributes_allowed = 1; | |
161 | fs_inode_nlink_allowed = 1; | |
162 | fs_quotas_allowed = 1; | |
163 | fs_aligned_inodes_allowed = 1; | |
164 | fs_sb_feature_bits_allowed = 1; | |
165 | fs_has_extflgbit_allowed = 1; | |
166 | pre_65_beta = 0; | |
167 | fs_shared_allowed = 1; | |
168 | ||
169 | /* | |
170 | * XXX have to add suboption processing here | |
171 | * attributes, quotas, nlinks, aligned_inos, sb_fbits | |
172 | */ | |
42a564ab | 173 | while ((c = getopt(argc, argv, "o:fl:r:LnDvV")) != EOF) { |
2bd0ea18 NS |
174 | switch (c) { |
175 | case 'D': | |
176 | dumpcore = 1; | |
177 | break; | |
178 | case 'o': | |
179 | p = optarg; | |
180 | while (*p != '\0') { | |
181 | char *val; | |
182 | ||
183 | switch (getsubopt(&p, (constpp)o_opts, &val)) { | |
184 | case ASSUME_XFS: | |
185 | if (val) | |
186 | noval('o', o_opts, ASSUME_XFS); | |
187 | if (assume_xfs) | |
188 | respec('o', o_opts, ASSUME_XFS); | |
189 | assume_xfs = 1; | |
190 | break; | |
191 | case PRE_65_BETA: | |
192 | if (val) | |
193 | noval('o', o_opts, PRE_65_BETA); | |
194 | if (pre_65_beta) | |
195 | respec('o', o_opts, | |
196 | PRE_65_BETA); | |
197 | pre_65_beta = 1; | |
198 | break; | |
199 | default: | |
200 | unknown('o', val); | |
201 | break; | |
202 | } | |
203 | } | |
204 | break; | |
205 | case 'l': | |
206 | log_name = optarg; | |
207 | log_spec = 1; | |
208 | break; | |
42a564ab ES |
209 | case 'r': |
210 | rt_name = optarg; | |
211 | rt_spec = 1; | |
212 | break; | |
2bd0ea18 NS |
213 | case 'f': |
214 | isa_file = 1; | |
215 | break; | |
d321ceac NS |
216 | case 'L': |
217 | zap_log = 1; | |
218 | break; | |
2bd0ea18 NS |
219 | case 'n': |
220 | no_modify = 1; | |
221 | break; | |
222 | case 'v': | |
223 | verbose = 1; | |
224 | break; | |
225 | case 'V': | |
226 | printf("%s version %s\n", progname, VERSION); | |
3d98fe63 | 227 | exit(0); |
2bd0ea18 NS |
228 | case '?': |
229 | usage(); | |
230 | } | |
231 | } | |
232 | ||
233 | if (argc - optind != 1) | |
234 | usage(); | |
235 | ||
236 | if ((fs_name = argv[optind]) == NULL) | |
237 | usage(); | |
238 | } | |
239 | ||
240 | void | |
241 | do_msg(int do_abort, char const *msg, va_list args) | |
242 | { | |
243 | vfprintf(stderr, msg, args); | |
244 | ||
245 | if (do_abort) { | |
246 | if (dumpcore) | |
247 | abort(); | |
248 | exit(1); | |
249 | } | |
250 | } | |
251 | ||
252 | void | |
253 | do_error(char const *msg, ...) | |
254 | { | |
255 | va_list args; | |
256 | ||
257 | fprintf(stderr, "\nfatal error -- "); | |
258 | ||
259 | va_start(args, msg); | |
260 | do_msg(1, msg, args); | |
261 | } | |
262 | ||
263 | /* | |
264 | * like do_error, only the error is internal, no system | |
265 | * error so no oserror processing | |
266 | */ | |
267 | void | |
268 | do_abort(char const *msg, ...) | |
269 | { | |
270 | va_list args; | |
271 | ||
272 | va_start(args, msg); | |
273 | do_msg(1, msg, args); | |
274 | } | |
275 | ||
276 | void | |
277 | do_warn(char const *msg, ...) | |
278 | { | |
279 | va_list args; | |
280 | ||
281 | fs_is_dirty = 1; | |
282 | ||
283 | va_start(args, msg); | |
284 | do_msg(0, msg, args); | |
285 | va_end(args); | |
286 | } | |
287 | ||
288 | /* no formatting */ | |
289 | ||
290 | void | |
291 | do_log(char const *msg, ...) | |
292 | { | |
293 | va_list args; | |
294 | ||
295 | va_start(args, msg); | |
296 | do_msg(0, msg, args); | |
297 | va_end(args); | |
298 | } | |
299 | ||
300 | void | |
301 | calc_mkfs(xfs_mount_t *mp) | |
302 | { | |
303 | xfs_agblock_t fino_bno; | |
304 | int do_inoalign; | |
305 | ||
306 | do_inoalign = mp->m_sinoalign; | |
307 | ||
308 | /* | |
309 | * pre-calculate geometry of ag 0. We know what it looks | |
310 | * like because we know what mkfs does -- 3 btree roots, | |
311 | * and some number of blocks to prefill the agfl. | |
312 | */ | |
313 | bnobt_root = howmany(4 * mp->m_sb.sb_sectsize, mp->m_sb.sb_blocksize); | |
314 | bcntbt_root = bnobt_root + 1; | |
315 | inobt_root = bnobt_root + 2; | |
316 | fino_bno = inobt_root + XFS_MIN_FREELIST_RAW(1, 1, mp) + 1; | |
317 | ||
318 | /* | |
319 | * ditto the location of the first inode chunks in the fs ('/') | |
320 | */ | |
321 | if (XFS_SB_VERSION_HASDALIGN(&mp->m_sb) && do_inoalign) { | |
322 | first_prealloc_ino = XFS_OFFBNO_TO_AGINO(mp, roundup(fino_bno, | |
323 | mp->m_sb.sb_unit), 0); | |
324 | } else if (XFS_SB_VERSION_HASALIGN(&mp->m_sb) && | |
325 | mp->m_sb.sb_inoalignmt > 1) { | |
326 | first_prealloc_ino = XFS_OFFBNO_TO_AGINO(mp, | |
327 | roundup(fino_bno, | |
328 | mp->m_sb.sb_inoalignmt), | |
329 | 0); | |
330 | } else { | |
331 | first_prealloc_ino = XFS_OFFBNO_TO_AGINO(mp, fino_bno, 0); | |
332 | } | |
333 | ||
334 | ASSERT(XFS_IALLOC_BLOCKS(mp) > 0); | |
335 | ||
336 | if (XFS_IALLOC_BLOCKS(mp) > 1) | |
337 | last_prealloc_ino = first_prealloc_ino + XFS_INODES_PER_CHUNK; | |
338 | else | |
339 | last_prealloc_ino = XFS_OFFBNO_TO_AGINO(mp, fino_bno + 1, 0); | |
340 | ||
341 | /* | |
342 | * now the first 3 inodes in the system | |
343 | */ | |
344 | if (mp->m_sb.sb_rootino != first_prealloc_ino) { | |
345 | do_warn( | |
346 | "sb root inode value %llu inconsistent with calculated value %llu\n", | |
347 | mp->m_sb.sb_rootino, first_prealloc_ino); | |
348 | ||
349 | if (!no_modify) | |
350 | do_warn( | |
351 | "resetting superblock root inode pointer to %llu\n", | |
352 | first_prealloc_ino); | |
353 | else | |
354 | do_warn( | |
355 | "would reset superblock root inode pointer to %llu\n", | |
356 | first_prealloc_ino); | |
357 | ||
358 | /* | |
359 | * just set the value -- safe since the superblock | |
360 | * doesn't get flushed out if no_modify is set | |
361 | */ | |
362 | mp->m_sb.sb_rootino = first_prealloc_ino; | |
363 | } | |
364 | ||
365 | if (mp->m_sb.sb_rbmino != first_prealloc_ino + 1) { | |
366 | do_warn( | |
367 | "sb realtime bitmap inode %llu inconsistent with calculated value %llu\n", | |
368 | mp->m_sb.sb_rbmino, first_prealloc_ino + 1); | |
369 | ||
370 | if (!no_modify) | |
371 | do_warn( | |
372 | "resetting superblock realtime bitmap ino pointer to %llu\n", | |
373 | first_prealloc_ino + 1); | |
374 | else | |
375 | do_warn( | |
376 | "would reset superblock realtime bitmap ino pointer to %llu\n", | |
377 | first_prealloc_ino + 1); | |
378 | ||
379 | /* | |
380 | * just set the value -- safe since the superblock | |
381 | * doesn't get flushed out if no_modify is set | |
382 | */ | |
383 | mp->m_sb.sb_rbmino = first_prealloc_ino + 1; | |
384 | } | |
385 | ||
386 | if (mp->m_sb.sb_rsumino != first_prealloc_ino + 2) { | |
387 | do_warn( | |
388 | "sb realtime summary inode %llu inconsistent with calculated value %llu\n", | |
389 | mp->m_sb.sb_rsumino, first_prealloc_ino + 2); | |
390 | ||
391 | if (!no_modify) | |
392 | do_warn( | |
393 | "resetting superblock realtime summary ino pointer to %llu\n", | |
394 | first_prealloc_ino + 2); | |
395 | else | |
396 | do_warn( | |
397 | "would reset superblock realtime summary ino pointer to %llu\n", | |
398 | first_prealloc_ino + 2); | |
399 | ||
400 | /* | |
401 | * just set the value -- safe since the superblock | |
402 | * doesn't get flushed out if no_modify is set | |
403 | */ | |
404 | mp->m_sb.sb_rsumino = first_prealloc_ino + 2; | |
405 | } | |
406 | ||
407 | } | |
408 | ||
409 | int | |
410 | main(int argc, char **argv) | |
411 | { | |
2bd0ea18 NS |
412 | xfs_mount_t *temp_mp; |
413 | xfs_mount_t *mp; | |
414 | xfs_sb_t *sb; | |
415 | xfs_buf_t *sbp; | |
416 | xfs_mount_t xfs_m; | |
417 | ||
418 | progname = basename(argv[0]); | |
419 | ||
420 | temp_mp = &xfs_m; | |
421 | setbuf(stdout, NULL); | |
422 | ||
423 | process_args(argc, argv); | |
d321ceac | 424 | xfs_init(&x); |
2bd0ea18 NS |
425 | |
426 | /* do phase1 to make sure we have a superblock */ | |
427 | phase1(temp_mp); | |
428 | ||
429 | if (no_modify && primary_sb_modified) { | |
430 | do_warn("primary superblock would have been modified.\n"); | |
431 | do_warn("cannot proceed further in no_modify mode.\n"); | |
432 | do_warn("exiting now.\n"); | |
433 | exit(1); | |
434 | } | |
435 | ||
436 | /* prepare the mount structure */ | |
d321ceac | 437 | sbp = libxfs_readbuf(x.ddev, XFS_SB_DADDR, 1, 0); |
2bd0ea18 NS |
438 | memset(&xfs_m, 0, sizeof(xfs_mount_t)); |
439 | sb = &xfs_m.m_sb; | |
440 | libxfs_xlate_sb(XFS_BUF_PTR(sbp), sb, 1, ARCH_CONVERT, XFS_SB_ALL_BITS); | |
441 | ||
d321ceac | 442 | mp = libxfs_mount(&xfs_m, sb, x.ddev, x.logdev, x.rtdev, 0); |
2bd0ea18 NS |
443 | |
444 | if (!mp) { | |
445 | fprintf(stderr, "%s: cannot repair this filesystem. Sorry.\n", | |
446 | progname); | |
447 | exit(1); | |
448 | } | |
449 | libxfs_putbuf(sbp); | |
450 | ||
451 | /* | |
452 | * set XFS-independent status vars from the mount/sb structure | |
453 | */ | |
454 | glob_agcount = mp->m_sb.sb_agcount; | |
455 | ||
456 | chunks_pblock = mp->m_sb.sb_inopblock / XFS_INODES_PER_CHUNK; | |
457 | max_symlink_blocks = howmany(MAXPATHLEN - 1, mp->m_sb.sb_blocksize); | |
458 | inodes_per_cluster = XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_inodelog; | |
459 | ||
460 | /* | |
461 | * calculate what mkfs would do to this filesystem | |
462 | */ | |
463 | calc_mkfs(mp); | |
464 | ||
465 | /* | |
466 | * check sb filesystem stats and initialize in-core data structures | |
467 | */ | |
468 | incore_init(mp); | |
469 | ||
470 | if (parse_sb_version(&mp->m_sb)) { | |
471 | do_warn( | |
472 | "Found unsupported filesystem features. Exiting now.\n"); | |
473 | return(1); | |
474 | } | |
475 | ||
476 | /* make sure the per-ag freespace maps are ok so we can mount the fs */ | |
477 | ||
d321ceac | 478 | phase2(mp); |
2bd0ea18 NS |
479 | |
480 | phase3(mp); | |
481 | ||
482 | phase4(mp); | |
483 | ||
484 | if (no_modify) | |
485 | printf("No modify flag set, skipping phase 5\n"); | |
486 | else | |
487 | phase5(mp); | |
488 | ||
489 | if (!bad_ino_btree) { | |
490 | phase6(mp); | |
491 | ||
492 | phase7(mp); | |
493 | } else { | |
494 | do_warn( | |
495 | "Inode allocation btrees are too corrupted, skipping phases 6 and 7\n"); | |
496 | } | |
497 | ||
b36eef04 | 498 | if (lost_quotas && !have_uquotino && !have_gquotino) { |
2bd0ea18 NS |
499 | if (!no_modify) { |
500 | do_warn( | |
501 | "Warning: no quota inodes were found. Quotas disabled.\n"); | |
502 | } else { | |
503 | do_warn( | |
504 | "Warning: no quota inodes were found. Quotas would be disabled.\n"); | |
505 | } | |
506 | } else if (lost_quotas) { | |
507 | if (!no_modify) { | |
508 | do_warn( | |
509 | "Warning: quota inodes were cleared. Quotas disabled.\n"); | |
510 | } else { | |
511 | do_warn( | |
512 | "Warning: quota inodes would be cleared. Quotas would be disabled.\n"); | |
513 | } | |
514 | } else { | |
515 | if (lost_uquotino) { | |
516 | if (!no_modify) { | |
517 | do_warn( | |
518 | "Warning: user quota information was cleared.\n"); | |
519 | do_warn( | |
520 | "User quotas can not be enforced until limit information is recreated.\n"); | |
521 | } else { | |
522 | do_warn( | |
523 | "Warning: user quota information would be cleared.\n"); | |
524 | do_warn( | |
525 | "User quotas could not be enforced until limit information was recreated.\n"); | |
526 | } | |
527 | } | |
528 | ||
b36eef04 | 529 | if (lost_gquotino) { |
2bd0ea18 NS |
530 | if (!no_modify) { |
531 | do_warn( | |
b36eef04 | 532 | "Warning: group quota information was cleared.\n"); |
2bd0ea18 | 533 | do_warn( |
b36eef04 | 534 | "Group quotas can not be enforced until limit information is recreated.\n"); |
2bd0ea18 NS |
535 | } else { |
536 | do_warn( | |
b36eef04 | 537 | "Warning: group quota information would be cleared.\n"); |
2bd0ea18 | 538 | do_warn( |
b36eef04 | 539 | "Group quotas could not be enforced until limit information was recreated.\n"); |
2bd0ea18 NS |
540 | } |
541 | } | |
542 | } | |
543 | ||
544 | if (no_modify) { | |
545 | do_log( | |
546 | "No modify flag set, skipping filesystem flush and exiting.\n"); | |
547 | if (fs_is_dirty) | |
548 | return(1); | |
549 | ||
550 | return(0); | |
551 | } | |
552 | ||
553 | /* | |
554 | * Clear the quota flags if they're on. | |
555 | */ | |
556 | sbp = libxfs_getsb(mp, 0); | |
557 | if (!sbp) | |
558 | do_error("couldn't get superblock\n"); | |
559 | ||
560 | sb = XFS_BUF_TO_SBP(sbp); | |
561 | ||
b36eef04 | 562 | if (sb->sb_qflags & (XFS_UQUOTA_CHKD|XFS_GQUOTA_CHKD)) { |
2bd0ea18 NS |
563 | do_warn( |
564 | "Note - quota info will be regenerated on next quota mount.\n"); | |
b36eef04 | 565 | sb->sb_qflags &= ~(XFS_UQUOTA_CHKD|XFS_GQUOTA_CHKD); |
2bd0ea18 NS |
566 | } |
567 | ||
568 | if (clear_sunit) { | |
569 | do_warn( | |
570 | "Note - stripe unit (%d) and width (%d) fields have been reset.\n" | |
571 | "Please set with mount -o sunit=<value>,swidth=<value>\n", | |
572 | sb->sb_unit, sb->sb_width); | |
573 | sb->sb_unit = 0; | |
574 | sb->sb_width = 0; | |
575 | } | |
576 | ||
577 | libxfs_writebuf(sbp, 0); | |
578 | ||
579 | libxfs_umount(mp); | |
d321ceac NS |
580 | if (x.rtdev) |
581 | libxfs_device_close(x.rtdev); | |
582 | if (x.logdev && x.logdev != x.ddev) | |
583 | libxfs_device_close(x.logdev); | |
584 | libxfs_device_close(x.ddev); | |
2bd0ea18 NS |
585 | |
586 | do_log("done\n"); | |
587 | ||
588 | return(0); | |
589 | } |