]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - repair/xfs_repair.c
Update copyright dates
[thirdparty/xfsprogs-dev.git] / repair / xfs_repair.c
CommitLineData
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
45extern void phase1(xfs_mount_t *);
d321ceac 46extern void phase2(xfs_mount_t *);
2bd0ea18
NS
47extern void phase3(xfs_mount_t *);
48extern void phase4(xfs_mount_t *);
49extern void phase5(xfs_mount_t *);
50extern void phase6(xfs_mount_t *);
51extern void phase7(xfs_mount_t *);
52extern 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
64char *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
72static void
73usage(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
80static 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
103char *
104err_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
112static void
113noval(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
119static void
120respec(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
129static void
130unknown(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 */
139void
140process_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
240void
241do_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
252void
253do_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 */
267void
268do_abort(char const *msg, ...)
269{
270 va_list args;
271
272 va_start(args, msg);
273 do_msg(1, msg, args);
274}
275
276void
277do_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
290void
291do_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
300void
301calc_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
409int
410main(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}