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