xref: /illumos-gate/usr/src/cmd/fs.d/ufs/fsck/pass5.c (revision aa9740b1)
1 /*
2  * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
3  */
4 
5 /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
6 /*	  All Rights Reserved  	*/
7 
8 /*
9  * Copyright (c) 1980, 1986, 1990 The Regents of the University of California.
10  * All rights reserved.
11  *
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.
25  */
26 
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"
37 
38 static int check_maps(uchar_t *, uchar_t *, int, int, char *, int, int);
39 
40 void
41 pass5(void)
42 {
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;
66 
67 	(void) memset((void *)buf, 0, sizeof (u.buf));
68 	newcg->cg_niblk = fs->fs_ipg;
69 
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 */
75 	}
76 
77 	/* LINTED this subtraction can't overflow and is int32-aligned */
78 	basesize = &newcg->cg_space[0] - (uchar_t *)newcg;
79 
80 	/*
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.
86 	 */
87 
88 	/*
89 	 * Note that we don't use any of the cg_*() macros until
90 	 * after cg_sanity() has approved of what we've got.
91 	 */
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);
97 
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;
103 
104 	sumsize = newcg->cg_iusedoff - newcg->cg_btotoff;
105 	mapsize = newcg->cg_nextfreeoff - newcg->cg_iusedoff;
106 
107 	init_inodesc(&idesc);
108 	idesc.id_type = ADDR;
109 	(void) memset((void *)&cstotal, 0, sizeof (struct csum));
110 	now = time(NULL);
111 
112 	/*
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.
118 	 */
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);
122 
123 	/*
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.
132 	 */
133 	update_csums = -1;
134 	update_bitmaps = 0;
135 	for (c = 0; c < fs->fs_ncg; c++) {
136 		backup_cs = cstotal;
137 
138 		/*
139 		 * cg_sanity() will catch i/o errors for us.
140 		 */
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);
150 		}
151 		/*
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.
156 		 */
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)) {
197 
198 			case USTATE:
199 				break;
200 
201 			case DSTATE:
202 			case DCLEAR:
203 			case DFOUND:
204 			case DZLINK:
205 				newcg->cg_cs.cs_ndir++;
206 				/* FALLTHROUGH */
207 
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;
216 
217 			default:
218 				if (j < UFSROOTINO)
219 					break;
220 				errexit("BAD STATE 0x%x FOR INODE I=%d",
221 				    statemap[j], (int)j);
222 			}
223 		}
224 		if (c == 0) {
225 			for (i = 0; i < UFSROOTINO; i++) {
226 				setbit(cg_inosused(newcg), i);
227 				newcg->cg_cs.cs_nifree--;
228 			}
229 		}
230 		/*
231 		 * Count up what fragments and blocks are free, and
232 		 * reflect the relevant section of blockmap[] into
233 		 * newcg's map.
234 		 */
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++;
244 			}
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);
256 			}
257 		}
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;
262 
263 		/*
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.
274 		 */
275 
276 		cs = &fs->fs_cs(fs, c);
277 		bad_csum_sb = (memcmp((void *)cs, (void *)&newcg->cg_cs,
278 		    sizeof (*cs)) != 0);
279 
280 		bad_csum_cg = (memcmp((void *)&cg->cg_cs, (void *)&newcg->cg_cs,
281 		    sizeof (struct csum)) != 0);
282 
283 		/*
284 		 * Has the user told us what to do yet?  If not, find out.
285 		 */
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);
295 			}
296 		}
297 
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);
304 		}
305 
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);
315 		}
316 
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;
322 		}
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;
339 				}
340 			}
341 		}
342 
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;
356 			}
357 		}
358 
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;
372 			}
373 		}
374 
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);
378 
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;
393 			}
394 		}
395 
396 		bad_cgblktot_cg = (memcmp((void *)&cg_blktot(cg)[0],
397 		    (void *)&cg_blktot(newcg)[0],
398 		    fs->fs_cpg * sizeof (int32_t)) != 0);
399 
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;
413 			}
414 		}
415 
416 		/*
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.
420 		 */
421 		if (cgisdirty()) {
422 			cgflush();
423 			cstotal = backup_cs;
424 			c--;
425 		}
426 	}
427 
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;
439 		}
440 	}
441 }
442 
443 /*
444  * Compare two allocation bitmaps, reporting any discrepancies.
445  *
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.
452  */
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 */
462 {
463 	long i, j, k, l, m, n, size;
464 	int astart, aend, ustart, uend;
465 	int mismatch;
466 
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;
482 				}
483 				if (aend + 1 == n) {
484 					aend = n;
485 					continue;
486 				}
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);
496 				}
497 				mismatch = 1;
498 				astart = aend = n;
499 			} else {
500 				if (ustart == -1) {
501 					ustart = uend = n;
502 					continue;
503 				}
504 				if (uend + 1 == n) {
505 					uend = n;
506 					continue;
507 				}
508 				size = uend - ustart + 1;
509 				if (size <= skip) {
510 					skip -= size;
511 					ustart = uend = n;
512 					continue;
513 				}
514 				if (skip > 0) {
515 					ustart += skip;
516 					size -= skip;
517 					skip = 0;
518 				}
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);
531 				}
532 				mismatch = 1;
533 				limit -= size;
534 				if (limit <= 0)
535 					return (mismatch);
536 				ustart = uend = n;
537 			}
538 		}
539 	}
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);
550 		}
551 		mismatch = 1;
552 	}
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;
560 		}
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);
572 		}
573 		mismatch = 1;
574 	}
575 	return (mismatch);
576 }
577