]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - repair/xfs_repair.c
repair: fix an ABBA deadlock in inode prefetching
[thirdparty/xfsprogs-dev.git] / repair / xfs_repair.c
CommitLineData
2bd0ea18 1/*
da23017d
NS
2 * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc.
3 * All Rights Reserved.
dfc130f3 4 *
da23017d
NS
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
2bd0ea18 7 * published by the Free Software Foundation.
dfc130f3 8 *
da23017d
NS
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
dfc130f3 13 *
da23017d
NS
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
2bd0ea18
NS
17 */
18
1d7e80ee 19#include <xfs/libxlog.h>
12be365e 20#include <sys/resource.h>
2bd0ea18
NS
21#include "avl.h"
22#include "avl64.h"
23#include "globals.h"
24#include "versions.h"
25#include "agheader.h"
26#include "protos.h"
27#include "incore.h"
28#include "err_protos.h"
cb5b3ef4 29#include "prefetch.h"
3b6ac903 30#include "threads.h"
06fbdda9 31#include "progress.h"
2bd0ea18
NS
32
33#define rounddown(x, y) (((x)/(y))*(y))
34
35extern void phase1(xfs_mount_t *);
364a126c 36extern void phase2(xfs_mount_t *, int);
2bd0ea18
NS
37extern void phase3(xfs_mount_t *);
38extern void phase4(xfs_mount_t *);
39extern void phase5(xfs_mount_t *);
40extern void phase6(xfs_mount_t *);
41extern void phase7(xfs_mount_t *);
2bd0ea18
NS
42
43#define XR_MAX_SECT_SIZE (64 * 1024)
44
45/*
46 * option tables for getsubopt calls
47 */
48
49/*
4af916f8 50 * -o: user-supplied override options
2bd0ea18
NS
51 */
52
53char *o_opts[] = {
54#define ASSUME_XFS 0
55 "assume_xfs",
56#define PRE_65_BETA 1
57 "fs_is_pre_65_beta",
9f38f08d
MV
58#define IHASH_SIZE 2
59 "ihash",
60#define BHASH_SIZE 3
61 "bhash",
2556c98b 62#define AG_STRIDE 4
add3cb90 63 "ag_stride",
d4dd6ab5
CH
64#define FORCE_GEO 5
65 "force_geometry",
364a126c
DC
66#define PHASE2_THREADS 6
67 "phase2_threads",
2bd0ea18
NS
68 NULL
69};
70
4af916f8
BN
71/*
72 * -c: conversion options
73 */
74
75char *c_opts[] = {
76#define CONVERT_LAZY_COUNT 0
77 "lazycount",
78 NULL
79};
80
81
2556c98b
BN
82static int ihash_option_used;
83static int bhash_option_used;
12be365e 84static long max_mem_specified; /* in megabytes */
364a126c 85static int phase2_threads = 32;
2556c98b 86
2bd0ea18
NS
87static void
88usage(void)
89{
4af916f8
BN
90 do_warn(_(
91"Usage: %s [options] device\n"
92"\n"
93"Options:\n"
94" -f The device is a file\n"
95" -L Force log zeroing. Do this as a last resort.\n"
96" -l logdev Specifies the device where the external log resides.\n"
97" -m maxmem Maximum amount of memory to be used in megabytes.\n"
98" -n No modify mode, just checks the filesystem for damage.\n"
99" -P Disables prefetching.\n"
100" -r rtdev Specifies the device where the realtime section resides.\n"
101" -v Verbose output.\n"
102" -c subopts Change filesystem parameters - use xfs_admin.\n"
103" -o subopts Override default behaviour, refer to man page.\n"
104" -t interval Reporting interval in minutes.\n"
105" -d Repair dangerously.\n"
106" -V Reports version and exits.\n"), progname);
2bd0ea18
NS
107 exit(1);
108}
109
2bd0ea18
NS
110char *
111err_string(int err_code)
112{
507f4e33
NS
113 static char *err_message[XR_BAD_ERR_CODE];
114 static int done;
115
116 if (!done) {
117 err_message[XR_OK] = _("no error");
118 err_message[XR_BAD_MAGIC] = _("bad magic number");
119 err_message[XR_BAD_BLOCKSIZE] = _("bad blocksize field");
120 err_message[XR_BAD_BLOCKLOG] = _("bad blocksize log field");
4af916f8 121 err_message[XR_BAD_VERSION] = _("bad or unsupported version");
507f4e33
NS
122 err_message[XR_BAD_INPROGRESS] =
123 _("filesystem mkfs-in-progress bit set");
124 err_message[XR_BAD_FS_SIZE_DATA] =
125 _("inconsistent filesystem geometry information");
126 err_message[XR_BAD_INO_SIZE_DATA] =
127 _("bad inode size or inconsistent with number of inodes/block"),
128 err_message[XR_BAD_SECT_SIZE_DATA] = _("bad sector size");
129 err_message[XR_AGF_GEO_MISMATCH] =
130 _("AGF geometry info conflicts with filesystem geometry");
131 err_message[XR_AGI_GEO_MISMATCH] =
132 _("AGI geometry info conflicts with filesystem geometry");
133 err_message[XR_SB_GEO_MISMATCH] =
134 _("AG superblock geometry info conflicts with filesystem geometry");
135 err_message[XR_EOF] = _("attempted to perform I/O beyond EOF");
136 err_message[XR_BAD_RT_GEO_DATA] =
137 _("inconsistent filesystem geometry in realtime filesystem component");
138 err_message[XR_BAD_INO_MAX_PCT] =
139 _("maximum indicated percentage of inodes > 100%");
140 err_message[XR_BAD_INO_ALIGN] =
141 _("inconsistent inode alignment value");
142 err_message[XR_INSUFF_SEC_SB] =
143 _("not enough secondary superblocks with matching geometry");
144 err_message[XR_BAD_SB_UNIT] =
145 _("bad stripe unit in superblock");
146 err_message[XR_BAD_SB_WIDTH] =
147 _("bad stripe width in superblock");
148 err_message[XR_BAD_SVN] =
149 _("bad shared version number in superblock");
150 done = 1;
151 }
152
2bd0ea18 153 if (err_code < XR_OK || err_code >= XR_BAD_ERR_CODE)
507f4e33 154 do_abort(_("bad error code - %d\n"), err_code);
2bd0ea18
NS
155
156 return(err_message[err_code]);
157}
158
159static void
160noval(char opt, char *tbl[], int idx)
161{
507f4e33 162 do_warn(_("-%c %s option cannot have a value\n"), opt, tbl[idx]);
2bd0ea18
NS
163 usage();
164}
165
166static void
167respec(char opt, char *tbl[], int idx)
168{
169 do_warn("-%c ", opt);
170 if (tbl)
171 do_warn("%s ", tbl[idx]);
507f4e33 172 do_warn(_("option respecified\n"));
2bd0ea18
NS
173 usage();
174}
175
176static void
177unknown(char opt, char *s)
178{
507f4e33 179 do_warn(_("unknown option -%c %s\n"), opt, s);
2bd0ea18
NS
180 usage();
181}
182
183/*
184 * sets only the global argument flags and variables
185 */
186void
187process_args(int argc, char **argv)
188{
189 char *p;
190 int c;
191
192 log_spec = 0;
193 fs_is_dirty = 0;
194 verbose = 0;
195 no_modify = 0;
c781939c 196 dangerously = 0;
2bd0ea18 197 isa_file = 0;
d321ceac 198 zap_log = 0;
2bd0ea18 199 dumpcore = 0;
0f012a4c 200 full_ino_ex_data = 0;
2bd0ea18
NS
201 delete_attr_ok = 1;
202 force_geo = 0;
203 assume_xfs = 0;
204 clear_sunit = 0;
205 sb_inoalignmt = 0;
206 sb_unit = 0;
207 sb_width = 0;
208 fs_attributes_allowed = 1;
9b1d68ec 209 fs_attributes2_allowed = 1;
2bd0ea18
NS
210 fs_inode_nlink_allowed = 1;
211 fs_quotas_allowed = 1;
212 fs_aligned_inodes_allowed = 1;
213 fs_sb_feature_bits_allowed = 1;
214 fs_has_extflgbit_allowed = 1;
215 pre_65_beta = 0;
216 fs_shared_allowed = 1;
add3cb90 217 ag_stride = 0;
2556c98b 218 thread_count = 1;
06fbdda9 219 report_interval = PROG_RPT_DEFAULT;
2bd0ea18
NS
220
221 /*
222 * XXX have to add suboption processing here
223 * attributes, quotas, nlinks, aligned_inos, sb_fbits
224 */
4af916f8 225 while ((c = getopt(argc, argv, "c:o:fl:m:r:LnDvVdPt:")) != EOF) {
2bd0ea18
NS
226 switch (c) {
227 case 'D':
228 dumpcore = 1;
229 break;
230 case 'o':
231 p = optarg;
232 while (*p != '\0') {
233 char *val;
234
235 switch (getsubopt(&p, (constpp)o_opts, &val)) {
236 case ASSUME_XFS:
237 if (val)
238 noval('o', o_opts, ASSUME_XFS);
239 if (assume_xfs)
240 respec('o', o_opts, ASSUME_XFS);
241 assume_xfs = 1;
242 break;
243 case PRE_65_BETA:
244 if (val)
245 noval('o', o_opts, PRE_65_BETA);
246 if (pre_65_beta)
247 respec('o', o_opts,
248 PRE_65_BETA);
249 pre_65_beta = 1;
250 break;
9f38f08d 251 case IHASH_SIZE:
5e656dbb 252 libxfs_ihash_size = (int)strtol(val, NULL, 0);
2556c98b 253 ihash_option_used = 1;
9f38f08d
MV
254 break;
255 case BHASH_SIZE:
12be365e
BN
256 if (max_mem_specified)
257 do_abort(
258 _("-o bhash option cannot be used with -m option\n"));
5e656dbb 259 libxfs_bhash_size = (int)strtol(val, NULL, 0);
2556c98b 260 bhash_option_used = 1;
cb5b3ef4 261 break;
add3cb90 262 case AG_STRIDE:
5e656dbb 263 ag_stride = (int)strtol(val, NULL, 0);
3b6ac903 264 break;
d4dd6ab5
CH
265 case FORCE_GEO:
266 if (val)
267 noval('o', o_opts, FORCE_GEO);
268 if (force_geo)
269 respec('o', o_opts, FORCE_GEO);
270 force_geo = 1;
271 break;
364a126c
DC
272 case PHASE2_THREADS:
273 phase2_threads = (int)strtol(val, NULL, 0);
274 break;
2bd0ea18
NS
275 default:
276 unknown('o', val);
277 break;
278 }
279 }
280 break;
4af916f8
BN
281 case 'c':
282 p = optarg;
283 while (*p) {
284 char *val;
285
286 switch (getsubopt(&p, (constpp)c_opts, &val)) {
287 case CONVERT_LAZY_COUNT:
5e656dbb 288 lazy_count = (int)strtol(val, NULL, 0);
4af916f8
BN
289 convert_lazy_count = 1;
290 break;
291 default:
292 unknown('c', val);
293 break;
294 }
295 }
296 break;
2bd0ea18
NS
297 case 'l':
298 log_name = optarg;
299 log_spec = 1;
300 break;
42a564ab
ES
301 case 'r':
302 rt_name = optarg;
303 rt_spec = 1;
304 break;
2bd0ea18
NS
305 case 'f':
306 isa_file = 1;
307 break;
12be365e
BN
308 case 'm':
309 if (bhash_option_used)
310 do_abort(_("-m option cannot be used with "
311 "-o bhash option\n"));
5e656dbb 312 max_mem_specified = strtol(optarg, NULL, 0);
12be365e 313 break;
d321ceac
NS
314 case 'L':
315 zap_log = 1;
316 break;
2bd0ea18
NS
317 case 'n':
318 no_modify = 1;
319 break;
6089b6f0
NS
320 case 'd':
321 dangerously = 1;
322 break;
2bd0ea18 323 case 'v':
3b6ac903 324 verbose++;
2bd0ea18
NS
325 break;
326 case 'V':
507f4e33 327 printf(_("%s version %s\n"), progname, VERSION);
3d98fe63 328 exit(0);
cb5b3ef4 329 case 'P':
2556c98b 330 do_prefetch = 0;
3b6ac903 331 break;
06fbdda9 332 case 't':
5e656dbb 333 report_interval = (int)strtol(optarg, NULL, 0);
06fbdda9 334 break;
2bd0ea18
NS
335 case '?':
336 usage();
337 }
338 }
339
340 if (argc - optind != 1)
341 usage();
342
343 if ((fs_name = argv[optind]) == NULL)
344 usage();
345}
346
b1559967 347void __attribute__((noreturn))
2bd0ea18
NS
348do_error(char const *msg, ...)
349{
350 va_list args;
351
507f4e33 352 fprintf(stderr, _("\nfatal error -- "));
2bd0ea18
NS
353
354 va_start(args, msg);
079afa09
CH
355 vfprintf(stderr, msg, args);
356 if (dumpcore)
357 abort();
358 exit(1);
2bd0ea18
NS
359}
360
361/*
362 * like do_error, only the error is internal, no system
363 * error so no oserror processing
364 */
b1559967 365void __attribute__((noreturn))
2bd0ea18
NS
366do_abort(char const *msg, ...)
367{
368 va_list args;
369
370 va_start(args, msg);
079afa09
CH
371 vfprintf(stderr, msg, args);
372 if (dumpcore)
373 abort();
374 exit(1);
2bd0ea18
NS
375}
376
377void
378do_warn(char const *msg, ...)
379{
380 va_list args;
381
382 fs_is_dirty = 1;
383
384 va_start(args, msg);
079afa09 385 vfprintf(stderr, msg, args);
2bd0ea18
NS
386 va_end(args);
387}
388
389/* no formatting */
390
391void
392do_log(char const *msg, ...)
393{
394 va_list args;
395
396 va_start(args, msg);
079afa09 397 vfprintf(stderr, msg, args);
2bd0ea18
NS
398 va_end(args);
399}
400
401void
402calc_mkfs(xfs_mount_t *mp)
403{
404 xfs_agblock_t fino_bno;
405 int do_inoalign;
406
407 do_inoalign = mp->m_sinoalign;
408
409 /*
410 * pre-calculate geometry of ag 0. We know what it looks
411 * like because we know what mkfs does -- 3 btree roots,
412 * and some number of blocks to prefill the agfl.
413 */
414 bnobt_root = howmany(4 * mp->m_sb.sb_sectsize, mp->m_sb.sb_blocksize);
415 bcntbt_root = bnobt_root + 1;
416 inobt_root = bnobt_root + 2;
417 fino_bno = inobt_root + XFS_MIN_FREELIST_RAW(1, 1, mp) + 1;
418
d4dd6ab5
CH
419 /*
420 * If we only have a single allocation group the log is also allocated
421 * in the first allocation group and we need to add the number of
422 * blocks used by the log to the above calculation.
423 * All this of course doesn't apply if we have an external log.
424 */
425 if (mp->m_sb.sb_agcount == 1 && mp->m_sb.sb_logstart) {
426 /*
427 * XXX(hch): verify that sb_logstart makes sense?
428 */
429 fino_bno += mp->m_sb.sb_logblocks;
430 }
431
2bd0ea18
NS
432 /*
433 * ditto the location of the first inode chunks in the fs ('/')
434 */
5e656dbb 435 if (xfs_sb_version_hasdalign(&mp->m_sb) && do_inoalign) {
2bd0ea18
NS
436 first_prealloc_ino = XFS_OFFBNO_TO_AGINO(mp, roundup(fino_bno,
437 mp->m_sb.sb_unit), 0);
5e656dbb 438 } else if (xfs_sb_version_hasalign(&mp->m_sb) &&
2bd0ea18
NS
439 mp->m_sb.sb_inoalignmt > 1) {
440 first_prealloc_ino = XFS_OFFBNO_TO_AGINO(mp,
441 roundup(fino_bno,
442 mp->m_sb.sb_inoalignmt),
443 0);
444 } else {
445 first_prealloc_ino = XFS_OFFBNO_TO_AGINO(mp, fino_bno, 0);
446 }
447
448 ASSERT(XFS_IALLOC_BLOCKS(mp) > 0);
449
450 if (XFS_IALLOC_BLOCKS(mp) > 1)
451 last_prealloc_ino = first_prealloc_ino + XFS_INODES_PER_CHUNK;
452 else
453 last_prealloc_ino = XFS_OFFBNO_TO_AGINO(mp, fino_bno + 1, 0);
454
455 /*
456 * now the first 3 inodes in the system
457 */
458 if (mp->m_sb.sb_rootino != first_prealloc_ino) {
459 do_warn(
5d1b7f0f 460_("sb root inode value %" PRIu64 " %sinconsistent with calculated value %u\n"),
507f4e33
NS
461 mp->m_sb.sb_rootino,
462 (mp->m_sb.sb_rootino == NULLFSINO ? "(NULLFSINO) ":""),
463 first_prealloc_ino);
2bd0ea18
NS
464
465 if (!no_modify)
466 do_warn(
5d1b7f0f 467 _("resetting superblock root inode pointer to %u\n"),
2bd0ea18
NS
468 first_prealloc_ino);
469 else
470 do_warn(
5d1b7f0f 471 _("would reset superblock root inode pointer to %u\n"),
2bd0ea18
NS
472 first_prealloc_ino);
473
474 /*
475 * just set the value -- safe since the superblock
476 * doesn't get flushed out if no_modify is set
477 */
478 mp->m_sb.sb_rootino = first_prealloc_ino;
479 }
480
481 if (mp->m_sb.sb_rbmino != first_prealloc_ino + 1) {
482 do_warn(
5d1b7f0f 483_("sb realtime bitmap inode %" PRIu64 " %sinconsistent with calculated value %u\n"),
507f4e33
NS
484 mp->m_sb.sb_rbmino,
485 (mp->m_sb.sb_rbmino == NULLFSINO ? "(NULLFSINO) ":""),
486 first_prealloc_ino + 1);
2bd0ea18
NS
487
488 if (!no_modify)
489 do_warn(
5d1b7f0f 490 _("resetting superblock realtime bitmap ino pointer to %u\n"),
2bd0ea18
NS
491 first_prealloc_ino + 1);
492 else
493 do_warn(
5d1b7f0f 494 _("would reset superblock realtime bitmap ino pointer to %u\n"),
2bd0ea18
NS
495 first_prealloc_ino + 1);
496
497 /*
498 * just set the value -- safe since the superblock
499 * doesn't get flushed out if no_modify is set
500 */
501 mp->m_sb.sb_rbmino = first_prealloc_ino + 1;
502 }
503
504 if (mp->m_sb.sb_rsumino != first_prealloc_ino + 2) {
505 do_warn(
5d1b7f0f
CH
506_("sb realtime summary inode %" PRIu64 " %sinconsistent with calculated value %u\n"),
507 mp->m_sb.sb_rsumino,
508 (mp->m_sb.sb_rsumino == NULLFSINO ? "(NULLFSINO) ":""),
509 first_prealloc_ino + 2);
2bd0ea18
NS
510
511 if (!no_modify)
512 do_warn(
5d1b7f0f 513 _("resetting superblock realtime summary ino pointer to %u\n"),
2bd0ea18
NS
514 first_prealloc_ino + 2);
515 else
516 do_warn(
5d1b7f0f 517 _("would reset superblock realtime summary ino pointer to %u\n"),
2bd0ea18
NS
518 first_prealloc_ino + 2);
519
520 /*
521 * just set the value -- safe since the superblock
522 * doesn't get flushed out if no_modify is set
523 */
524 mp->m_sb.sb_rsumino = first_prealloc_ino + 2;
525 }
526
527}
528
529int
530main(int argc, char **argv)
531{
2bd0ea18
NS
532 xfs_mount_t *temp_mp;
533 xfs_mount_t *mp;
5e656dbb 534 xfs_dsb_t *dsb;
2bd0ea18
NS
535 xfs_buf_t *sbp;
536 xfs_mount_t xfs_m;
06fbdda9 537 char *msgbuf;
2bd0ea18
NS
538
539 progname = basename(argv[0]);
507f4e33
NS
540 setlocale(LC_ALL, "");
541 bindtextdomain(PACKAGE, LOCALEDIR);
542 textdomain(PACKAGE);
2bd0ea18
NS
543
544 temp_mp = &xfs_m;
545 setbuf(stdout, NULL);
546
547 process_args(argc, argv);
d321ceac 548 xfs_init(&x);
2bd0ea18 549
2556c98b
BN
550 msgbuf = malloc(DURATION_BUF_SIZE);
551
06fbdda9
MV
552 timestamp(PHASE_START, 0, NULL);
553 timestamp(PHASE_END, 0, NULL);
554
2bd0ea18
NS
555 /* do phase1 to make sure we have a superblock */
556 phase1(temp_mp);
06fbdda9 557 timestamp(PHASE_END, 1, NULL);
2bd0ea18
NS
558
559 if (no_modify && primary_sb_modified) {
507f4e33
NS
560 do_warn(_("Primary superblock would have been modified.\n"
561 "Cannot proceed further in no_modify mode.\n"
562 "Exiting now.\n"));
2bd0ea18
NS
563 exit(1);
564 }
565
566 /* prepare the mount structure */
2aa2e7b9
BN
567 sbp = libxfs_readbuf(x.ddev, XFS_SB_DADDR,
568 1 << (XFS_MAX_SECTORSIZE_LOG - BBSHIFT), 0);
2bd0ea18 569 memset(&xfs_m, 0, sizeof(xfs_mount_t));
5e656dbb 570 libxfs_sb_from_disk(&xfs_m.m_sb, XFS_BUF_TO_SBP(sbp));
2bd0ea18 571
f63fd268
DC
572 /*
573 * if the sector size of the filesystem we are trying to repair is
574 * smaller than that of the underlying filesystem (i.e. we are repairing
575 * an image), the we have to turn off direct IO because we cannot do IO
576 * smaller than the host filesystem's sector size.
577 */
578 if (isa_file) {
579 int fd = libxfs_device_to_fd(x.ddev);
580 struct xfs_fsop_geom_v1 geom = { 0 };
581
582 if (ioctl(fd, XFS_IOC_FSGEOMETRY_V1, &geom) < 0) {
583 do_warn(_("Cannot get host filesystem geometry.\n"
584 "Repair may fail if there is a sector size mismatch between\n"
585 "the image and the host filesystem.\n"));
586 geom.sectsize = BBSIZE;
587 }
588
589 if (xfs_m.m_sb.sb_sectsize < geom.sectsize) {
590 long old_flags;
591
592 old_flags = fcntl(fd, F_GETFL, 0);
593 if (fcntl(fd, F_SETFL, old_flags & ~O_DIRECT) < 0) {
594 do_warn(_(
595 "Sector size on host filesystem larger than image sector size.\n"
596 "Cannot turn off direct IO, so exiting.\n"));
597 exit(1);
598 }
599 }
600 }
5e656dbb 601 mp = libxfs_mount(&xfs_m, &xfs_m.m_sb, x.ddev, x.logdev, x.rtdev, 0);
2bd0ea18
NS
602
603 if (!mp) {
507f4e33
NS
604 fprintf(stderr,
605 _("%s: cannot repair this filesystem. Sorry.\n"),
2bd0ea18
NS
606 progname);
607 exit(1);
608 }
609 libxfs_putbuf(sbp);
2aa2e7b9 610 libxfs_purgebuf(sbp);
2bd0ea18
NS
611
612 /*
613 * set XFS-independent status vars from the mount/sb structure
614 */
615 glob_agcount = mp->m_sb.sb_agcount;
616
617 chunks_pblock = mp->m_sb.sb_inopblock / XFS_INODES_PER_CHUNK;
618 max_symlink_blocks = howmany(MAXPATHLEN - 1, mp->m_sb.sb_blocksize);
edf3f9d0
BN
619 inodes_per_cluster = MAX(mp->m_sb.sb_inopblock,
620 XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_inodelog);
2bd0ea18 621
add3cb90 622 if (ag_stride) {
2556c98b 623 thread_count = (glob_agcount + ag_stride - 1) / ag_stride;
add3cb90
BN
624 thread_init();
625 }
626
2556c98b 627 if (ag_stride && report_interval) {
06fbdda9 628 init_progress_rpt();
06fbdda9
MV
629 if (msgbuf) {
630 do_log(_(" - reporting progress in intervals of %s\n"),
631 duration(report_interval, msgbuf));
06fbdda9
MV
632 }
633 }
634
2556c98b
BN
635 /*
636 * Adjust libxfs cache sizes based on system memory,
637 * filesystem size and inode count.
638 *
639 * We'll set the cache size based on 3/4s the memory minus
640 * space used by the inode AVL tree and block usage map.
641 *
642 * Inode AVL tree space is approximately 4 bytes per inode,
643 * block usage map is currently 1 byte for 2 blocks.
644 *
645 * We assume most blocks will be inode clusters.
646 *
647 * Calculations are done in kilobyte units.
648 */
649
12be365e 650 if (!bhash_option_used || max_mem_specified) {
2556c98b 651 unsigned long mem_used;
12be365e
BN
652 unsigned long max_mem;
653 struct rlimit rlim;
2556c98b
BN
654
655 libxfs_icache_purge();
656 libxfs_bcache_purge();
657 cache_destroy(libxfs_icache);
658 cache_destroy(libxfs_bcache);
659
660 mem_used = (mp->m_sb.sb_icount >> (10 - 2)) +
12be365e
BN
661 (mp->m_sb.sb_dblocks >> (10 + 1)) +
662 50000; /* rough estimate of 50MB overhead */
663 max_mem = max_mem_specified ? max_mem_specified * 1024 :
664 libxfs_physmem() * 3 / 4;
665
666 if (getrlimit(RLIMIT_AS, &rlim) != -1 &&
667 rlim.rlim_cur != RLIM_INFINITY) {
668 rlim.rlim_cur = rlim.rlim_max;
669 setrlimit(RLIMIT_AS, &rlim);
670 /* use approximately 80% of rlimit to avoid overrun */
671 max_mem = MIN(max_mem, rlim.rlim_cur / 1280);
672 } else
673 max_mem = MIN(max_mem, (LONG_MAX >> 10) + 1);
2556c98b
BN
674
675 if (verbose > 1)
5d1b7f0f
CH
676 do_log(
677 _(" - max_mem = %lu, icount = %" PRIu64 ", imem = %" PRIu64 ", dblock = %" PRIu64 ", dmem = %" PRIu64 "\n"),
12be365e
BN
678 max_mem, mp->m_sb.sb_icount,
679 mp->m_sb.sb_icount >> (10 - 2),
680 mp->m_sb.sb_dblocks,
681 mp->m_sb.sb_dblocks >> (10 + 1));
682
683 if (max_mem <= mem_used) {
2556c98b
BN
684 /*
685 * Turn off prefetch and minimise libxfs cache if
686 * physical memory is deemed insufficient
687 */
0335a835
DC
688 if (max_mem_specified) {
689 do_abort(
690 _("Required memory for repair is greater that the maximum specified\n"
691 "with the -m option. Please increase it to at least %lu.\n"),
12be365e 692 mem_used / 1024);
0335a835
DC
693 } else {
694 do_warn(
695 _("Not enough RAM available for repair to enable prefetching.\n"
696 "This will be _slow_.\n"
697 "You need at least %luMB RAM to run with prefetching enabled.\n"),
698 mem_used * 1280 / (1024 * 1024));
699 }
2556c98b
BN
700 do_prefetch = 0;
701 libxfs_bhash_size = 64;
702 } else {
12be365e
BN
703 max_mem -= mem_used;
704 if (max_mem >= (1 << 30))
705 max_mem = 1 << 30;
706 libxfs_bhash_size = max_mem / (HASH_CACHE_RATIO *
2556c98b
BN
707 (mp->m_inode_cluster_size >> 10));
708 if (libxfs_bhash_size < 512)
709 libxfs_bhash_size = 512;
710 }
711
712 if (verbose)
713 do_log(_(" - block cache size set to %d entries\n"),
714 libxfs_bhash_size * HASH_CACHE_RATIO);
715
716 if (!ihash_option_used)
717 libxfs_ihash_size = libxfs_bhash_size;
718
719 libxfs_icache = cache_init(libxfs_ihash_size,
720 &libxfs_icache_operations);
721 libxfs_bcache = cache_init(libxfs_bhash_size,
722 &libxfs_bcache_operations);
723 }
724
2bd0ea18
NS
725 /*
726 * calculate what mkfs would do to this filesystem
727 */
728 calc_mkfs(mp);
729
730 /*
c1f7a46c 731 * initialize block alloc map
2bd0ea18 732 */
c1f7a46c
BN
733 init_bmaps(mp);
734 incore_ino_init(mp);
735 incore_ext_init(mp);
736
737 /* initialize random globals now that we know the fs geometry */
738 inodes_per_block = mp->m_sb.sb_inopblock;
2bd0ea18
NS
739
740 if (parse_sb_version(&mp->m_sb)) {
741 do_warn(
507f4e33 742 _("Found unsupported filesystem features. Exiting now.\n"));
2bd0ea18
NS
743 return(1);
744 }
745
746 /* make sure the per-ag freespace maps are ok so we can mount the fs */
364a126c 747 phase2(mp, phase2_threads);
06fbdda9 748 timestamp(PHASE_END, 2, NULL);
2bd0ea18 749
2556c98b
BN
750 if (do_prefetch)
751 init_prefetch(mp);
752
2bd0ea18 753 phase3(mp);
06fbdda9 754 timestamp(PHASE_END, 3, NULL);
2bd0ea18
NS
755
756 phase4(mp);
06fbdda9 757 timestamp(PHASE_END, 4, NULL);
2bd0ea18
NS
758
759 if (no_modify)
507f4e33 760 printf(_("No modify flag set, skipping phase 5\n"));
3b6ac903 761 else {
2bd0ea18 762 phase5(mp);
3b6ac903 763 }
06fbdda9 764 timestamp(PHASE_END, 5, NULL);
2bd0ea18 765
c1f7a46c
BN
766 /*
767 * Done with the block usage maps, toss them...
768 */
769 free_bmaps(mp);
770
2bd0ea18
NS
771 if (!bad_ino_btree) {
772 phase6(mp);
06fbdda9 773 timestamp(PHASE_END, 6, NULL);
2bd0ea18
NS
774
775 phase7(mp);
06fbdda9 776 timestamp(PHASE_END, 7, NULL);
2bd0ea18
NS
777 } else {
778 do_warn(
507f4e33 779_("Inode allocation btrees are too corrupted, skipping phases 6 and 7\n"));
2bd0ea18
NS
780 }
781
b36eef04 782 if (lost_quotas && !have_uquotino && !have_gquotino) {
2bd0ea18
NS
783 if (!no_modify) {
784 do_warn(
507f4e33 785_("Warning: no quota inodes were found. Quotas disabled.\n"));
2bd0ea18
NS
786 } else {
787 do_warn(
507f4e33 788_("Warning: no quota inodes were found. Quotas would be disabled.\n"));
2bd0ea18
NS
789 }
790 } else if (lost_quotas) {
791 if (!no_modify) {
792 do_warn(
507f4e33 793_("Warning: quota inodes were cleared. Quotas disabled.\n"));
2bd0ea18
NS
794 } else {
795 do_warn(
507f4e33 796_("Warning: quota inodes would be cleared. Quotas would be disabled.\n"));
2bd0ea18
NS
797 }
798 } else {
799 if (lost_uquotino) {
800 if (!no_modify) {
801 do_warn(
507f4e33
NS
802_("Warning: user quota information was cleared.\n"
803 "User quotas can not be enforced until limit information is recreated.\n"));
2bd0ea18
NS
804 } else {
805 do_warn(
507f4e33
NS
806_("Warning: user quota information would be cleared.\n"
807 "User quotas could not be enforced until limit information was recreated.\n"));
2bd0ea18
NS
808 }
809 }
810
b36eef04 811 if (lost_gquotino) {
2bd0ea18
NS
812 if (!no_modify) {
813 do_warn(
507f4e33
NS
814_("Warning: group quota information was cleared.\n"
815 "Group quotas can not be enforced until limit information is recreated.\n"));
2bd0ea18
NS
816 } else {
817 do_warn(
507f4e33
NS
818_("Warning: group quota information would be cleared.\n"
819 "Group quotas could not be enforced until limit information was recreated.\n"));
9b27bdbb
NS
820 }
821 }
822
823 if (lost_pquotino) {
824 if (!no_modify) {
825 do_warn(
826_("Warning: project quota information was cleared.\n"
827 "Project quotas can not be enforced until limit information is recreated.\n"));
828 } else {
829 do_warn(
830_("Warning: project quota information would be cleared.\n"
831 "Project quotas could not be enforced until limit information was recreated.\n"));
2bd0ea18
NS
832 }
833 }
834 }
835
2556c98b 836 if (ag_stride && report_interval)
06fbdda9 837 stop_progress_rpt();
9f38f08d 838
2bd0ea18
NS
839 if (no_modify) {
840 do_log(
507f4e33 841 _("No modify flag set, skipping filesystem flush and exiting.\n"));
3b6ac903 842 if (verbose)
06fbdda9 843 summary_report();
2bd0ea18
NS
844 if (fs_is_dirty)
845 return(1);
846
847 return(0);
848 }
849
850 /*
851 * Clear the quota flags if they're on.
852 */
853 sbp = libxfs_getsb(mp, 0);
854 if (!sbp)
507f4e33 855 do_error(_("couldn't get superblock\n"));
2bd0ea18 856
5e656dbb 857 dsb = XFS_BUF_TO_SBP(sbp);
2bd0ea18 858
5e656dbb
BN
859 if (be16_to_cpu(dsb->sb_qflags) & (XFS_UQUOTA_CHKD | XFS_OQUOTA_CHKD)) {
860 do_warn(_("Note - quota info will be regenerated on next "
861 "quota mount.\n"));
862 dsb->sb_qflags &= cpu_to_be16(~(XFS_UQUOTA_CHKD |
863 XFS_OQUOTA_CHKD));
2bd0ea18
NS
864 }
865
866 if (clear_sunit) {
867 do_warn(
507f4e33
NS
868_("Note - stripe unit (%d) and width (%d) fields have been reset.\n"
869 "Please set with mount -o sunit=<value>,swidth=<value>\n"),
5e656dbb
BN
870 be32_to_cpu(dsb->sb_unit), be32_to_cpu(dsb->sb_width));
871 dsb->sb_unit = 0;
872 dsb->sb_width = 0;
dfc130f3 873 }
2bd0ea18
NS
874
875 libxfs_writebuf(sbp, 0);
876
2556c98b
BN
877 /*
878 * Done, flush all cached buffers and inodes.
879 */
880 libxfs_bcache_flush();
881
2bd0ea18 882 libxfs_umount(mp);
d321ceac
NS
883 if (x.rtdev)
884 libxfs_device_close(x.rtdev);
885 if (x.logdev && x.logdev != x.ddev)
886 libxfs_device_close(x.logdev);
887 libxfs_device_close(x.ddev);
2bd0ea18 888
06fbdda9
MV
889 if (verbose)
890 summary_report();
507f4e33 891 do_log(_("done\n"));
4c0a98ae
BN
892 pftrace_done();
893
3b6ac903
MV
894 return (0);
895}