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