]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - repair/xfs_repair.c
Undoes mod: xfs-cmds:slinx:120772a
[thirdparty/xfsprogs-dev.git] / repair / xfs_repair.c
1 /*
2 * Copyright (c) 2000 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("Usage: %s [-nLvV] [-o subopt[=value]] [-l logdev] [-r rtdev] devname\n",
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;
150 zap_log = 0;
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 */
173 while ((c = getopt(argc, argv, "o:fl:r:LnDvV")) != EOF) {
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;
209 case 'r':
210 rt_name = optarg;
211 rt_spec = 1;
212 break;
213 case 'f':
214 isa_file = 1;
215 break;
216 case 'L':
217 zap_log = 1;
218 break;
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);
227 exit(0);
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 {
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);
424 xfs_init(&x);
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 */
437 sbp = libxfs_readbuf(x.ddev, XFS_SB_DADDR, 1, 0);
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
442 mp = libxfs_mount(&xfs_m, sb, x.ddev, x.logdev, x.rtdev, 0);
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
478 phase2(mp);
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
498 if (lost_quotas && !have_uquotino && !have_gquotino) {
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
529 if (lost_gquotino) {
530 if (!no_modify) {
531 do_warn(
532 "Warning: group quota information was cleared.\n");
533 do_warn(
534 "Group quotas can not be enforced until limit information is recreated.\n");
535 } else {
536 do_warn(
537 "Warning: group quota information would be cleared.\n");
538 do_warn(
539 "Group quotas could not be enforced until limit information was recreated.\n");
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
562 if (sb->sb_qflags & (XFS_UQUOTA_CHKD|XFS_GQUOTA_CHKD)) {
563 do_warn(
564 "Note - quota info will be regenerated on next quota mount.\n");
565 sb->sb_qflags &= ~(XFS_UQUOTA_CHKD|XFS_GQUOTA_CHKD);
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);
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);
585
586 do_log("done\n");
587
588 return(0);
589 }