8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / fs.d / ufs / fsck / pass5.c
blob95a9ddd850b309f0f23adba48bca80055552d974
1 /*
2 * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
3 */
5 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
6 /* All Rights Reserved */
8 /*
9 * Copyright (c) 1980, 1986, 1990 The Regents of the University of California.
10 * All rights reserved.
12 * Redistribution and use in source and binary forms are permitted
13 * provided that: (1) source distributions retain this entire copyright
14 * notice and comment, and (2) distributions including binaries display
15 * the following acknowledgement: ``This product includes software
16 * developed by the University of California, Berkeley and its contributors''
17 * in the documentation or other materials provided with the distribution
18 * and in all advertising materials mentioning features or use of this
19 * software. Neither the name of the University nor the names of its
20 * contributors may be used to endorse or promote products derived
21 * from this software without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
24 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <unistd.h>
30 #include <string.h>
31 #include <sys/param.h>
32 #include <sys/mntent.h>
33 #include <sys/fs/ufs_fs.h>
34 #include <sys/vnode.h>
35 #include <sys/fs/ufs_inode.h>
36 #include "fsck.h"
38 static int check_maps(uchar_t *, uchar_t *, int, int, char *, int, int);
40 void
41 pass5(void)
43 caddr_t err;
44 int32_t c, blk, frags;
45 size_t basesize, sumsize, mapsize;
46 int excessdirs;
47 int inomapsize, blkmapsize;
48 int update_csums, update_bitmaps;
49 int bad_csum_sb, bad_csum_cg, bad_cgblks_cg, bad_cgblktot_cg;
50 struct fs *fs = &sblock;
51 struct cg *cg = &cgrp;
52 diskaddr_t dbase, dmax;
53 diskaddr_t d;
54 uint64_t i, j;
55 struct csum *cs;
56 struct csum backup_cs;
57 time_t now;
58 struct csum cstotal;
59 struct inodesc idesc;
60 union { /* keep lint happy about alignment */
61 struct cg cg; /* the rest of buf has the bitmaps */
62 char buf[MAXBSIZE];
63 } u;
64 caddr_t buf = u.buf;
65 struct cg *newcg = &u.cg;
67 (void) memset((void *)buf, 0, sizeof (u.buf));
68 newcg->cg_niblk = fs->fs_ipg;
70 if (fs->fs_postblformat != FS_DYNAMICPOSTBLFMT) {
71 pfatal("UNSUPPORTED ROTATIONAL TABLE FORMAT %d\n",
72 fs->fs_postblformat);
73 errexit("Program terminated.");
74 /* NOTREACHED */
77 /* LINTED this subtraction can't overflow and is int32-aligned */
78 basesize = &newcg->cg_space[0] - (uchar_t *)newcg;
81 * We reserve the space for the old rotation summary
82 * tables for the benefit of old kernels, but do not
83 * maintain them in modern kernels. In time, they could
84 * theoretically go away, if we wanted to deal with
85 * changing the on-disk format.
89 * Note that we don't use any of the cg_*() macros until
90 * after cg_sanity() has approved of what we've got.
92 newcg->cg_btotoff = basesize;
93 newcg->cg_boff = newcg->cg_btotoff + fs->fs_cpg * sizeof (daddr32_t);
94 newcg->cg_iusedoff = newcg->cg_boff +
95 fs->fs_cpg * fs->fs_nrpos * sizeof (uint16_t);
96 (void) memset(&newcg->cg_space[0], 0, newcg->cg_iusedoff - basesize);
98 inomapsize = howmany(fs->fs_ipg, NBBY);
99 newcg->cg_freeoff = newcg->cg_iusedoff + inomapsize;
100 blkmapsize = howmany(fs->fs_fpg, NBBY);
101 newcg->cg_nextfreeoff = newcg->cg_freeoff + blkmapsize;
102 newcg->cg_magic = CG_MAGIC;
104 sumsize = newcg->cg_iusedoff - newcg->cg_btotoff;
105 mapsize = newcg->cg_nextfreeoff - newcg->cg_iusedoff;
107 init_inodesc(&idesc);
108 idesc.id_type = ADDR;
109 (void) memset((void *)&cstotal, 0, sizeof (struct csum));
110 now = time(NULL);
113 * If the last fragments in the file system don't make up a
114 * full file system block, mark the bits in the blockmap
115 * that correspond to those missing fragments as "allocated",
116 * so that the last block doesn't get counted as a free block
117 * and those missing fragments don't get counted as free frags.
119 j = blknum(fs, (uint64_t)fs->fs_size + fs->fs_frag - 1);
120 for (i = fs->fs_size; i < j; i++)
121 setbmap(i);
124 * The cg summaries are not always updated when using
125 * logging. Since we're really concerned with getting a
126 * sane filesystem, rather than in trying to debug UFS
127 * corner cases, logically we would just always recompute
128 * them. However, it is disconcerting to users to be asked
129 * about updating the summaries when, from their point of
130 * view, there's been no indication of a problem up to this
131 * point. So, only do it if we find a discrepancy.
133 update_csums = -1;
134 update_bitmaps = 0;
135 for (c = 0; c < fs->fs_ncg; c++) {
136 backup_cs = cstotal;
139 * cg_sanity() will catch i/o errors for us.
141 (void) getblk(&cgblk, (diskaddr_t)cgtod(fs, c),
142 (size_t)fs->fs_cgsize);
143 err = cg_sanity(cg, c);
144 if (err != NULL) {
145 pfatal("CG %d: %s\n", c, err);
146 free((void *)err);
147 if (reply("REPAIR") == 0)
148 errexit("Program terminated.");
149 fix_cg(cg, c);
152 * If the on-disk timestamp is in the future, then it
153 * by definition is wrong. Otherwise, if it's in
154 * the past, then use that value so that we don't
155 * declare a spurious mismatch.
157 if (now > cg->cg_time)
158 newcg->cg_time = cg->cg_time;
159 else
160 newcg->cg_time = now;
161 newcg->cg_cgx = c;
162 dbase = cgbase(fs, c);
163 dmax = dbase + fs->fs_fpg;
164 if (dmax > fs->fs_size)
165 dmax = fs->fs_size;
166 newcg->cg_ndblk = dmax - dbase;
167 if (c == fs->fs_ncg - 1)
168 newcg->cg_ncyl = fs->fs_ncyl - (fs->fs_cpg * c);
169 else
170 newcg->cg_ncyl = fs->fs_cpg;
171 newcg->cg_niblk = sblock.fs_ipg;
172 newcg->cg_cs.cs_ndir = 0;
173 newcg->cg_cs.cs_nffree = 0;
174 newcg->cg_cs.cs_nbfree = 0;
175 newcg->cg_cs.cs_nifree = fs->fs_ipg;
176 if ((cg->cg_rotor >= 0) && (cg->cg_rotor < newcg->cg_ndblk))
177 newcg->cg_rotor = cg->cg_rotor;
178 else
179 newcg->cg_rotor = 0;
180 if ((cg->cg_frotor >= 0) && (cg->cg_frotor < newcg->cg_ndblk))
181 newcg->cg_frotor = cg->cg_frotor;
182 else
183 newcg->cg_frotor = 0;
184 if ((cg->cg_irotor >= 0) && (cg->cg_irotor < newcg->cg_niblk))
185 newcg->cg_irotor = cg->cg_irotor;
186 else
187 newcg->cg_irotor = 0;
188 (void) memset((void *)&newcg->cg_frsum[0], 0,
189 sizeof (newcg->cg_frsum));
190 (void) memset((void *)cg_inosused(newcg), 0, (size_t)mapsize);
191 /* LINTED macro is int32-aligned per newcg->cg_btotoff above */
192 (void) memset((void *)&cg_blktot(newcg)[0], 0,
193 sumsize + mapsize);
194 j = fs->fs_ipg * c;
195 for (i = 0; i < fs->fs_ipg; j++, i++) {
196 switch (statemap[j] & ~(INORPHAN | INDELAYD)) {
198 case USTATE:
199 break;
201 case DSTATE:
202 case DCLEAR:
203 case DFOUND:
204 case DZLINK:
205 newcg->cg_cs.cs_ndir++;
206 /* FALLTHROUGH */
208 case FSTATE:
209 case FCLEAR:
210 case FZLINK:
211 case SSTATE:
212 case SCLEAR:
213 newcg->cg_cs.cs_nifree--;
214 setbit(cg_inosused(newcg), i);
215 break;
217 default:
218 if (j < UFSROOTINO)
219 break;
220 errexit("BAD STATE 0x%x FOR INODE I=%d",
221 statemap[j], (int)j);
224 if (c == 0) {
225 for (i = 0; i < UFSROOTINO; i++) {
226 setbit(cg_inosused(newcg), i);
227 newcg->cg_cs.cs_nifree--;
231 * Count up what fragments and blocks are free, and
232 * reflect the relevant section of blockmap[] into
233 * newcg's map.
235 for (i = 0, d = dbase;
236 d < dmax;
237 d += fs->fs_frag, i += fs->fs_frag) {
238 frags = 0;
239 for (j = 0; j < fs->fs_frag; j++) {
240 if (testbmap(d + j))
241 continue;
242 setbit(cg_blksfree(newcg), i + j);
243 frags++;
245 if (frags == fs->fs_frag) {
246 newcg->cg_cs.cs_nbfree++;
247 j = cbtocylno(fs, i);
248 /* LINTED macro is int32-aligned per above */
249 cg_blktot(newcg)[j]++;
250 /* LINTED cg_blks(newcg) is aligned */
251 cg_blks(fs, newcg, j)[cbtorpos(fs, i)]++;
252 } else if (frags > 0) {
253 newcg->cg_cs.cs_nffree += frags;
254 blk = blkmap(fs, cg_blksfree(newcg), i);
255 fragacct(fs, blk, newcg->cg_frsum, 1);
258 cstotal.cs_nffree += newcg->cg_cs.cs_nffree;
259 cstotal.cs_nbfree += newcg->cg_cs.cs_nbfree;
260 cstotal.cs_nifree += newcg->cg_cs.cs_nifree;
261 cstotal.cs_ndir += newcg->cg_cs.cs_ndir;
264 * Note that, just like the kernel, we dynamically
265 * allocated an array to hold the csums and stuffed
266 * the pointer into the in-core superblock's fs_u.fs_csp
267 * field. This means that the fs_u field contains a
268 * random value when the disk version is examined, but
269 * fs_cs() gives us a valid pointer nonetheless.
270 * We need to compare the recalculated summaries to
271 * both the superblock version and the on disk version.
272 * If either is bad, copy the calculated version over
273 * the corrupt values.
276 cs = &fs->fs_cs(fs, c);
277 bad_csum_sb = (memcmp((void *)cs, (void *)&newcg->cg_cs,
278 sizeof (*cs)) != 0);
280 bad_csum_cg = (memcmp((void *)&cg->cg_cs, (void *)&newcg->cg_cs,
281 sizeof (struct csum)) != 0);
284 * Has the user told us what to do yet? If not, find out.
286 if ((bad_csum_sb || bad_csum_cg) && (update_csums == -1)) {
287 if (preen) {
288 update_csums = 1;
289 (void) printf("CORRECTING BAD CG SUMMARIES"
290 " FOR CG %d\n", c);
291 } else if (update_csums == -1) {
292 update_csums = (reply(
293 "CORRECT BAD CG SUMMARIES FOR CG %d",
294 c) == 1);
298 if (bad_csum_sb && (update_csums == 1)) {
299 (void) memmove((void *)cs, (void *)&newcg->cg_cs,
300 sizeof (*cs));
301 sbdirty();
302 (void) printf("CORRECTED SUPERBLOCK SUMMARIES FOR"
303 " CG %d\n", c);
306 if (bad_csum_cg && (update_csums == 1)) {
307 (void) memmove((void *)cg, (void *)newcg,
308 (size_t)basesize);
309 /* LINTED per cg_sanity() */
310 (void) memmove((void *)&cg_blktot(cg)[0],
311 /* LINTED macro aligned as above */
312 (void *)&cg_blktot(newcg)[0], sumsize);
313 cgdirty();
314 (void) printf("CORRECTED SUMMARIES FOR CG %d\n", c);
317 excessdirs = cg->cg_cs.cs_ndir - newcg->cg_cs.cs_ndir;
318 if (excessdirs < 0) {
319 pfatal("LOST %d DIRECTORIES IN CG %d\n",
320 -excessdirs, c);
321 excessdirs = 0;
323 if (excessdirs > 0) {
324 if (check_maps((uchar_t *)cg_inosused(newcg),
325 (uchar_t *)cg_inosused(cg), inomapsize,
326 cg->cg_cgx * fs->fs_ipg, "DIR", 0, excessdirs)) {
327 if (!verbose)
328 (void) printf("DIR BITMAP WRONG ");
329 if (preen || update_bitmaps ||
330 reply("FIX") == 1) {
331 (void) memmove((void *)cg_inosused(cg),
332 (void *)cg_inosused(newcg),
333 inomapsize);
334 cgdirty();
335 if (preen ||
336 (!verbose && update_bitmaps))
337 (void) printf("(CORRECTED)\n");
338 update_bitmaps = 1;
343 if (check_maps((uchar_t *)cg_inosused(newcg),
344 (uchar_t *)cg_inosused(cg), inomapsize,
345 cg->cg_cgx * fs->fs_ipg, "FILE", excessdirs, fs->fs_ipg)) {
346 if (!verbose)
347 (void) printf("FILE BITMAP WRONG ");
348 if (preen || update_bitmaps || reply("FIX") == 1) {
349 (void) memmove((void *)cg_inosused(cg),
350 (void *)cg_inosused(newcg), inomapsize);
351 cgdirty();
352 if (preen ||
353 (!verbose && update_bitmaps))
354 (void) printf("(CORRECTED)\n");
355 update_bitmaps = 1;
359 if (check_maps((uchar_t *)cg_blksfree(cg),
360 (uchar_t *)cg_blksfree(newcg), blkmapsize,
361 cg->cg_cgx * fs->fs_fpg, "FRAG", 0, fs->fs_fpg)) {
362 if (!verbose)
363 (void) printf("FRAG BITMAP WRONG ");
364 if (preen || update_bitmaps || reply("FIX") == 1) {
365 (void) memmove((void *)cg_blksfree(cg),
366 (void *)cg_blksfree(newcg), blkmapsize);
367 cgdirty();
368 if (preen ||
369 (!verbose && update_bitmaps))
370 (void) printf("(CORRECTED)\n");
371 update_bitmaps = 1;
375 bad_cgblks_cg = (memcmp((void *)&cg_blks(fs, cg, 0)[0],
376 (void *)&cg_blks(fs, newcg, 0)[0],
377 fs->fs_cpg * fs->fs_nrpos * sizeof (int16_t)) != 0);
379 if (bad_cgblks_cg) {
380 if (!verbose)
381 (void) printf("ROTATIONAL POSITIONS "
382 "BLOCK COUNT WRONG ");
383 if (preen || update_bitmaps || reply("FIX") == 1) {
384 (void) memmove((void *)&cg_blks(fs, cg, 0)[0],
385 (void *)&cg_blks(fs, newcg, 0)[0],
386 fs->fs_cpg * fs->fs_nrpos *
387 sizeof (int16_t));
388 cgdirty();
389 if (preen ||
390 (!verbose && update_bitmaps))
391 (void) printf("(CORRECTED)\n");
392 update_bitmaps = 1;
396 bad_cgblktot_cg = (memcmp((void *)&cg_blktot(cg)[0],
397 (void *)&cg_blktot(newcg)[0],
398 fs->fs_cpg * sizeof (int32_t)) != 0);
400 if (bad_cgblktot_cg) {
401 if (!verbose)
402 (void) printf("ROTATIONAL POSITIONS "
403 "BLOCK TOTAL WRONG ");
404 if (preen || update_bitmaps || reply("FIX") == 1) {
405 (void) memmove((void *)&cg_blktot(cg)[0],
406 (void *)&cg_blktot(newcg)[0],
407 fs->fs_cpg * sizeof (int32_t));
408 cgdirty();
409 if (preen ||
410 (!verbose && update_bitmaps))
411 (void) printf("(CORRECTED)\n");
412 update_bitmaps = 1;
417 * Fixing one set of problems often shows up more in the
418 * same cg. Just to make sure, go back and check it
419 * again if we found something this time through.
421 if (cgisdirty()) {
422 cgflush();
423 cstotal = backup_cs;
424 c--;
428 if ((fflag || !(islog && islogok)) &&
429 (memcmp((void *)&cstotal, (void *)&fs->fs_cstotal,
430 sizeof (struct csum)) != 0)) {
431 if (dofix(&idesc, "CORRECT GLOBAL SUMMARY")) {
432 (void) memmove((void *)&fs->fs_cstotal,
433 (void *)&cstotal, sizeof (struct csum));
434 fs->fs_ronly = 0;
435 fs->fs_fmod = 0;
436 sbdirty();
437 } else {
438 iscorrupt = 1;
444 * Compare two allocation bitmaps, reporting any discrepancies.
446 * If a mismatch is found, if the bit is set in map1, it's considered
447 * to be an indication that the corresponding resource is supposed
448 * to be free, but isn't. Otherwise, it's considered marked as allocated
449 * but not found to be so. In other words, if the two maps being compared
450 * use a set bit to indicate something is free, pass the on-disk map
451 * first. Otherwise, pass the calculated map first.
453 static int
454 check_maps(
455 uchar_t *map1, /* map of claimed allocations */
456 uchar_t *map2, /* map of determined allocations */
457 int mapsize, /* size of above two maps */
458 int startvalue, /* resource value for first element in map */
459 char *name, /* name of resource found in maps */
460 int skip, /* number of entries to skip before starting to free */
461 int limit) /* limit on number of entries to free */
463 long i, j, k, l, m, n, size;
464 int astart, aend, ustart, uend;
465 int mismatch;
467 mismatch = 0;
468 astart = ustart = aend = uend = -1;
469 for (i = 0; i < mapsize; i++) {
470 j = *map1++;
471 k = *map2++;
472 if (j == k)
473 continue;
474 for (m = 0, l = 1; m < NBBY; m++, l <<= 1) {
475 if ((j & l) == (k & l))
476 continue;
477 n = startvalue + i * NBBY + m;
478 if ((j & l) != 0) {
479 if (astart == -1) {
480 astart = aend = n;
481 continue;
483 if (aend + 1 == n) {
484 aend = n;
485 continue;
487 if (verbose) {
488 if (astart == aend)
489 pwarn(
490 "ALLOCATED %s %d WAS MARKED FREE ON DISK\n",
491 name, astart);
492 else
493 pwarn(
494 "ALLOCATED %sS %d-%d WERE MARKED FREE ON DISK\n",
495 name, astart, aend);
497 mismatch = 1;
498 astart = aend = n;
499 } else {
500 if (ustart == -1) {
501 ustart = uend = n;
502 continue;
504 if (uend + 1 == n) {
505 uend = n;
506 continue;
508 size = uend - ustart + 1;
509 if (size <= skip) {
510 skip -= size;
511 ustart = uend = n;
512 continue;
514 if (skip > 0) {
515 ustart += skip;
516 size -= skip;
517 skip = 0;
519 if (size > limit)
520 size = limit;
521 if (verbose) {
522 if (size == 1)
523 pwarn(
524 "UNALLOCATED %s %d WAS MARKED USED ON DISK\n",
525 name, ustart);
526 else
527 pwarn(
528 "UNALLOCATED %sS %d-%ld WERE MARKED USED ON DISK\n",
529 name, ustart,
530 ustart + size - 1);
532 mismatch = 1;
533 limit -= size;
534 if (limit <= 0)
535 return (mismatch);
536 ustart = uend = n;
540 if (astart != -1) {
541 if (verbose) {
542 if (astart == aend)
543 pwarn(
544 "ALLOCATED %s %d WAS MARKED FREE ON DISK\n",
545 name, astart);
546 else
547 pwarn(
548 "ALLOCATED %sS %d-%d WERE MARKED FREE ON DISK\n",
549 name, astart, aend);
551 mismatch = 1;
553 if (ustart != -1) {
554 size = uend - ustart + 1;
555 if (size <= skip)
556 return (mismatch);
557 if (skip > 0) {
558 ustart += skip;
559 size -= skip;
561 if (size > limit)
562 size = limit;
563 if (verbose) {
564 if (size == 1)
565 pwarn(
566 "UNALLOCATED %s %d WAS MARKED USED ON DISK\n",
567 name, ustart);
568 else
569 pwarn(
570 "UNALLOCATED %sS %d-%ld WERE MARKED USED ON DISK\n",
571 name, ustart, ustart + size - 1);
573 mismatch = 1;
575 return (mismatch);