xref: /onnv-gate/usr/src/cmd/fs.d/ufs/fsck/pass5.c (revision 12838:e54202e5e259)
10Sstevel@tonic-gate /*
2*12838SAndrew.Balfour@Sun.COM  * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
30Sstevel@tonic-gate  */
40Sstevel@tonic-gate 
50Sstevel@tonic-gate /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
60Sstevel@tonic-gate /*	  All Rights Reserved  	*/
70Sstevel@tonic-gate 
80Sstevel@tonic-gate /*
90Sstevel@tonic-gate  * Copyright (c) 1980, 1986, 1990 The Regents of the University of California.
100Sstevel@tonic-gate  * All rights reserved.
110Sstevel@tonic-gate  *
120Sstevel@tonic-gate  * Redistribution and use in source and binary forms are permitted
130Sstevel@tonic-gate  * provided that: (1) source distributions retain this entire copyright
140Sstevel@tonic-gate  * notice and comment, and (2) distributions including binaries display
150Sstevel@tonic-gate  * the following acknowledgement:  ``This product includes software
160Sstevel@tonic-gate  * developed by the University of California, Berkeley and its contributors''
170Sstevel@tonic-gate  * in the documentation or other materials provided with the distribution
180Sstevel@tonic-gate  * and in all advertising materials mentioning features or use of this
190Sstevel@tonic-gate  * software. Neither the name of the University nor the names of its
200Sstevel@tonic-gate  * contributors may be used to endorse or promote products derived
210Sstevel@tonic-gate  * from this software without specific prior written permission.
220Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
230Sstevel@tonic-gate  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
240Sstevel@tonic-gate  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
27392Sswilcox #include <stdio.h>
28392Sswilcox #include <stdlib.h>
29392Sswilcox #include <unistd.h>
30392Sswilcox #include <string.h>
310Sstevel@tonic-gate #include <sys/param.h>
320Sstevel@tonic-gate #include <sys/mntent.h>
330Sstevel@tonic-gate #include <sys/fs/ufs_fs.h>
340Sstevel@tonic-gate #include <sys/vnode.h>
350Sstevel@tonic-gate #include <sys/fs/ufs_inode.h>
360Sstevel@tonic-gate #include "fsck.h"
370Sstevel@tonic-gate 
38392Sswilcox static int check_maps(uchar_t *, uchar_t *, int, int, char *, int, int);
39392Sswilcox 
40392Sswilcox void
pass5(void)41392Sswilcox pass5(void)
420Sstevel@tonic-gate {
43392Sswilcox 	caddr_t err;
44392Sswilcox 	int32_t c, blk, frags;
450Sstevel@tonic-gate 	size_t	basesize, sumsize, mapsize;
46392Sswilcox 	int excessdirs;
47392Sswilcox 	int inomapsize, blkmapsize;
486715Svsakar 	int update_csums, update_bitmaps;
496715Svsakar 	int bad_csum_sb, bad_csum_cg, bad_cgblks_cg, bad_cgblktot_cg;
500Sstevel@tonic-gate 	struct fs *fs = &sblock;
510Sstevel@tonic-gate 	struct cg *cg = &cgrp;
520Sstevel@tonic-gate 	diskaddr_t dbase, dmax;
530Sstevel@tonic-gate 	diskaddr_t d;
540Sstevel@tonic-gate 	uint64_t i, j;
550Sstevel@tonic-gate 	struct csum *cs;
56392Sswilcox 	struct csum backup_cs;
570Sstevel@tonic-gate 	time_t now;
580Sstevel@tonic-gate 	struct csum cstotal;
590Sstevel@tonic-gate 	struct inodesc idesc;
60392Sswilcox 	union {				/* keep lint happy about alignment */
61392Sswilcox 		struct cg cg;		/* the rest of buf has the bitmaps */
62392Sswilcox 		char buf[MAXBSIZE];
63392Sswilcox 	} u;
64392Sswilcox 	caddr_t buf = u.buf;
65392Sswilcox 	struct cg *newcg = &u.cg;
660Sstevel@tonic-gate 
67392Sswilcox 	(void) memset((void *)buf, 0, sizeof (u.buf));
68392Sswilcox 	newcg->cg_niblk = fs->fs_ipg;
690Sstevel@tonic-gate 
70392Sswilcox 	if (fs->fs_postblformat != FS_DYNAMICPOSTBLFMT) {
71392Sswilcox 		pfatal("UNSUPPORTED ROTATIONAL TABLE FORMAT %d\n",
726715Svsakar 		    fs->fs_postblformat);
73392Sswilcox 		errexit("Program terminated.");
74392Sswilcox 		/* NOTREACHED */
750Sstevel@tonic-gate 	}
760Sstevel@tonic-gate 
77392Sswilcox 	/* LINTED this subtraction can't overflow and is int32-aligned */
78392Sswilcox 	basesize = &newcg->cg_space[0] - (uchar_t *)newcg;
79392Sswilcox 
80392Sswilcox 	/*
81392Sswilcox 	 * We reserve the space for the old rotation summary
82392Sswilcox 	 * tables for the benefit of old kernels, but do not
83392Sswilcox 	 * maintain them in modern kernels. In time, they could
84392Sswilcox 	 * theoretically go away, if we wanted to deal with
85392Sswilcox 	 * changing the on-disk format.
86392Sswilcox 	 */
87392Sswilcox 
88392Sswilcox 	/*
89392Sswilcox 	 * Note that we don't use any of the cg_*() macros until
90392Sswilcox 	 * after cg_sanity() has approved of what we've got.
91392Sswilcox 	 */
92392Sswilcox 	newcg->cg_btotoff = basesize;
93392Sswilcox 	newcg->cg_boff = newcg->cg_btotoff + fs->fs_cpg * sizeof (daddr32_t);
94392Sswilcox 	newcg->cg_iusedoff = newcg->cg_boff +
956715Svsakar 	    fs->fs_cpg * fs->fs_nrpos * sizeof (uint16_t);
96392Sswilcox 	(void) memset(&newcg->cg_space[0], 0, newcg->cg_iusedoff - basesize);
97392Sswilcox 
98392Sswilcox 	inomapsize = howmany(fs->fs_ipg, NBBY);
99392Sswilcox 	newcg->cg_freeoff = newcg->cg_iusedoff + inomapsize;
100392Sswilcox 	blkmapsize = howmany(fs->fs_fpg, NBBY);
101392Sswilcox 	newcg->cg_nextfreeoff = newcg->cg_freeoff + blkmapsize;
102392Sswilcox 	newcg->cg_magic = CG_MAGIC;
103392Sswilcox 
104392Sswilcox 	sumsize = newcg->cg_iusedoff - newcg->cg_btotoff;
105392Sswilcox 	mapsize = newcg->cg_nextfreeoff - newcg->cg_iusedoff;
106392Sswilcox 
107392Sswilcox 	init_inodesc(&idesc);
1080Sstevel@tonic-gate 	idesc.id_type = ADDR;
109392Sswilcox 	(void) memset((void *)&cstotal, 0, sizeof (struct csum));
110392Sswilcox 	now = time(NULL);
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate 	/*
1130Sstevel@tonic-gate 	 * If the last fragments in the file system don't make up a
1140Sstevel@tonic-gate 	 * full file system block, mark the bits in the blockmap
1150Sstevel@tonic-gate 	 * that correspond to those missing fragments as "allocated",
1160Sstevel@tonic-gate 	 * so that the last block doesn't get counted as a free block
1170Sstevel@tonic-gate 	 * and those missing fragments don't get counted as free frags.
1180Sstevel@tonic-gate 	 */
1190Sstevel@tonic-gate 	j = blknum(fs, (uint64_t)fs->fs_size + fs->fs_frag - 1);
1200Sstevel@tonic-gate 	for (i = fs->fs_size; i < j; i++)
1210Sstevel@tonic-gate 		setbmap(i);
122392Sswilcox 
123392Sswilcox 	/*
124392Sswilcox 	 * The cg summaries are not always updated when using
125392Sswilcox 	 * logging.  Since we're really concerned with getting a
126392Sswilcox 	 * sane filesystem, rather than in trying to debug UFS
127392Sswilcox 	 * corner cases, logically we would just always recompute
128392Sswilcox 	 * them.  However, it is disconcerting to users to be asked
129392Sswilcox 	 * about updating the summaries when, from their point of
130392Sswilcox 	 * view, there's been no indication of a problem up to this
131392Sswilcox 	 * point.  So, only do it if we find a discrepancy.
132392Sswilcox 	 */
133392Sswilcox 	update_csums = -1;
134392Sswilcox 	update_bitmaps = 0;
1350Sstevel@tonic-gate 	for (c = 0; c < fs->fs_ncg; c++) {
136392Sswilcox 		backup_cs = cstotal;
137392Sswilcox 
138392Sswilcox 		/*
139392Sswilcox 		 * cg_sanity() will catch i/o errors for us.
140392Sswilcox 		 */
141392Sswilcox 		(void) getblk(&cgblk, (diskaddr_t)cgtod(fs, c),
142392Sswilcox 		    (size_t)fs->fs_cgsize);
1433219Sabalfour 		err = cg_sanity(cg, c);
144392Sswilcox 		if (err != NULL) {
145392Sswilcox 			pfatal("CG %d: %s\n", c, err);
146392Sswilcox 			free((void *)err);
147392Sswilcox 			if (reply("REPAIR") == 0)
148392Sswilcox 				errexit("Program terminated.");
149392Sswilcox 			fix_cg(cg, c);
150392Sswilcox 		}
151392Sswilcox 		/*
152392Sswilcox 		 * If the on-disk timestamp is in the future, then it
153392Sswilcox 		 * by definition is wrong.  Otherwise, if it's in
154392Sswilcox 		 * the past, then use that value so that we don't
155392Sswilcox 		 * declare a spurious mismatch.
156392Sswilcox 		 */
1570Sstevel@tonic-gate 		if (now > cg->cg_time)
1580Sstevel@tonic-gate 			newcg->cg_time = cg->cg_time;
1590Sstevel@tonic-gate 		else
1600Sstevel@tonic-gate 			newcg->cg_time = now;
1610Sstevel@tonic-gate 		newcg->cg_cgx = c;
162392Sswilcox 		dbase = cgbase(fs, c);
163392Sswilcox 		dmax = dbase + fs->fs_fpg;
164392Sswilcox 		if (dmax > fs->fs_size)
165392Sswilcox 			dmax = fs->fs_size;
166392Sswilcox 		newcg->cg_ndblk = dmax - dbase;
1670Sstevel@tonic-gate 		if (c == fs->fs_ncg - 1)
1682201Svk154806 			newcg->cg_ncyl = fs->fs_ncyl - (fs->fs_cpg * c);
1690Sstevel@tonic-gate 		else
1700Sstevel@tonic-gate 			newcg->cg_ncyl = fs->fs_cpg;
1710Sstevel@tonic-gate 		newcg->cg_niblk = sblock.fs_ipg;
1720Sstevel@tonic-gate 		newcg->cg_cs.cs_ndir = 0;
1730Sstevel@tonic-gate 		newcg->cg_cs.cs_nffree = 0;
1740Sstevel@tonic-gate 		newcg->cg_cs.cs_nbfree = 0;
1750Sstevel@tonic-gate 		newcg->cg_cs.cs_nifree = fs->fs_ipg;
1760Sstevel@tonic-gate 		if ((cg->cg_rotor >= 0) && (cg->cg_rotor < newcg->cg_ndblk))
1770Sstevel@tonic-gate 			newcg->cg_rotor = cg->cg_rotor;
1780Sstevel@tonic-gate 		else
1790Sstevel@tonic-gate 			newcg->cg_rotor = 0;
1800Sstevel@tonic-gate 		if ((cg->cg_frotor >= 0) && (cg->cg_frotor < newcg->cg_ndblk))
1810Sstevel@tonic-gate 			newcg->cg_frotor = cg->cg_frotor;
1820Sstevel@tonic-gate 		else
1830Sstevel@tonic-gate 			newcg->cg_frotor = 0;
1840Sstevel@tonic-gate 		if ((cg->cg_irotor >= 0) && (cg->cg_irotor < newcg->cg_niblk))
1850Sstevel@tonic-gate 			newcg->cg_irotor = cg->cg_irotor;
1860Sstevel@tonic-gate 		else
1870Sstevel@tonic-gate 			newcg->cg_irotor = 0;
188392Sswilcox 		(void) memset((void *)&newcg->cg_frsum[0], 0,
189392Sswilcox 		    sizeof (newcg->cg_frsum));
190392Sswilcox 		(void) memset((void *)cg_inosused(newcg), 0, (size_t)mapsize);
191392Sswilcox 		/* LINTED macro is int32-aligned per newcg->cg_btotoff above */
192392Sswilcox 		(void) memset((void *)&cg_blktot(newcg)[0], 0,
193392Sswilcox 		    sumsize + mapsize);
1940Sstevel@tonic-gate 		j = fs->fs_ipg * c;
1950Sstevel@tonic-gate 		for (i = 0; i < fs->fs_ipg; j++, i++) {
196392Sswilcox 			switch (statemap[j] & ~(INORPHAN | INDELAYD)) {
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate 			case USTATE:
1990Sstevel@tonic-gate 				break;
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate 			case DSTATE:
2020Sstevel@tonic-gate 			case DCLEAR:
2030Sstevel@tonic-gate 			case DFOUND:
204392Sswilcox 			case DZLINK:
2050Sstevel@tonic-gate 				newcg->cg_cs.cs_ndir++;
206392Sswilcox 				/* FALLTHROUGH */
2070Sstevel@tonic-gate 
2080Sstevel@tonic-gate 			case FSTATE:
2090Sstevel@tonic-gate 			case FCLEAR:
210392Sswilcox 			case FZLINK:
2110Sstevel@tonic-gate 			case SSTATE:
2120Sstevel@tonic-gate 			case SCLEAR:
2130Sstevel@tonic-gate 				newcg->cg_cs.cs_nifree--;
2140Sstevel@tonic-gate 				setbit(cg_inosused(newcg), i);
2150Sstevel@tonic-gate 				break;
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate 			default:
2180Sstevel@tonic-gate 				if (j < UFSROOTINO)
2190Sstevel@tonic-gate 					break;
220392Sswilcox 				errexit("BAD STATE 0x%x FOR INODE I=%d",
221392Sswilcox 				    statemap[j], (int)j);
2220Sstevel@tonic-gate 			}
2230Sstevel@tonic-gate 		}
224392Sswilcox 		if (c == 0) {
2250Sstevel@tonic-gate 			for (i = 0; i < UFSROOTINO; i++) {
2260Sstevel@tonic-gate 				setbit(cg_inosused(newcg), i);
2270Sstevel@tonic-gate 				newcg->cg_cs.cs_nifree--;
2280Sstevel@tonic-gate 			}
229392Sswilcox 		}
230392Sswilcox 		/*
231392Sswilcox 		 * Count up what fragments and blocks are free, and
232392Sswilcox 		 * reflect the relevant section of blockmap[] into
233392Sswilcox 		 * newcg's map.
234392Sswilcox 		 */
2350Sstevel@tonic-gate 		for (i = 0, d = dbase;
2360Sstevel@tonic-gate 		    d < dmax;
2370Sstevel@tonic-gate 		    d += fs->fs_frag, i += fs->fs_frag) {
2380Sstevel@tonic-gate 			frags = 0;
2390Sstevel@tonic-gate 			for (j = 0; j < fs->fs_frag; j++) {
2400Sstevel@tonic-gate 				if (testbmap(d + j))
2410Sstevel@tonic-gate 					continue;
2420Sstevel@tonic-gate 				setbit(cg_blksfree(newcg), i + j);
2430Sstevel@tonic-gate 				frags++;
2440Sstevel@tonic-gate 			}
2450Sstevel@tonic-gate 			if (frags == fs->fs_frag) {
2460Sstevel@tonic-gate 				newcg->cg_cs.cs_nbfree++;
2470Sstevel@tonic-gate 				j = cbtocylno(fs, i);
248392Sswilcox 				/* LINTED macro is int32-aligned per above */
2490Sstevel@tonic-gate 				cg_blktot(newcg)[j]++;
250392Sswilcox 				/* LINTED cg_blks(newcg) is aligned */
2510Sstevel@tonic-gate 				cg_blks(fs, newcg, j)[cbtorpos(fs, i)]++;
2520Sstevel@tonic-gate 			} else if (frags > 0) {
2530Sstevel@tonic-gate 				newcg->cg_cs.cs_nffree += frags;
2540Sstevel@tonic-gate 				blk = blkmap(fs, cg_blksfree(newcg), i);
2550Sstevel@tonic-gate 				fragacct(fs, blk, newcg->cg_frsum, 1);
2560Sstevel@tonic-gate 			}
2570Sstevel@tonic-gate 		}
2580Sstevel@tonic-gate 		cstotal.cs_nffree += newcg->cg_cs.cs_nffree;
2590Sstevel@tonic-gate 		cstotal.cs_nbfree += newcg->cg_cs.cs_nbfree;
2600Sstevel@tonic-gate 		cstotal.cs_nifree += newcg->cg_cs.cs_nifree;
2610Sstevel@tonic-gate 		cstotal.cs_ndir += newcg->cg_cs.cs_ndir;
2620Sstevel@tonic-gate 
263392Sswilcox 		/*
264392Sswilcox 		 * Note that, just like the kernel, we dynamically
265392Sswilcox 		 * allocated an array to hold the csums and stuffed
266392Sswilcox 		 * the pointer into the in-core superblock's fs_u.fs_csp
267392Sswilcox 		 * field.  This means that the fs_u field contains a
268392Sswilcox 		 * random value when the disk version is examined, but
269392Sswilcox 		 * fs_cs() gives us a valid pointer nonetheless.
2703219Sabalfour 		 * We need to compare the recalculated summaries to
2713219Sabalfour 		 * both the superblock version and the on disk version.
2723219Sabalfour 		 * If either is bad, copy the calculated version over
2733219Sabalfour 		 * the corrupt values.
274392Sswilcox 		 */
2753219Sabalfour 
2760Sstevel@tonic-gate 		cs = &fs->fs_cs(fs, c);
2773219Sabalfour 		bad_csum_sb = (memcmp((void *)cs, (void *)&newcg->cg_cs,
278392Sswilcox 		    sizeof (*cs)) != 0);
279392Sswilcox 
2803219Sabalfour 		bad_csum_cg = (memcmp((void *)&cg->cg_cs, (void *)&newcg->cg_cs,
2813219Sabalfour 		    sizeof (struct csum)) != 0);
2823219Sabalfour 
283392Sswilcox 		/*
284392Sswilcox 		 * Has the user told us what to do yet?  If not, find out.
285392Sswilcox 		 */
2863219Sabalfour 		if ((bad_csum_sb || bad_csum_cg) && (update_csums == -1)) {
287392Sswilcox 			if (preen) {
288392Sswilcox 				update_csums = 1;
2893219Sabalfour 				(void) printf("CORRECTING BAD CG SUMMARIES"
2906715Svsakar 				    " FOR CG %d\n", c);
291392Sswilcox 			} else if (update_csums == -1) {
292392Sswilcox 				update_csums = (reply(
2933219Sabalfour 				    "CORRECT BAD CG SUMMARIES FOR CG %d",
2943219Sabalfour 				    c) == 1);
295392Sswilcox 			}
296392Sswilcox 		}
297392Sswilcox 
2983219Sabalfour 		if (bad_csum_sb && (update_csums == 1)) {
299392Sswilcox 			(void) memmove((void *)cs, (void *)&newcg->cg_cs,
300392Sswilcox 			    sizeof (*cs));
3010Sstevel@tonic-gate 			sbdirty();
3023219Sabalfour 			(void) printf("CORRECTED SUPERBLOCK SUMMARIES FOR"
3036715Svsakar 			    " CG %d\n", c);
3043219Sabalfour 		}
305392Sswilcox 
3063219Sabalfour 		if (bad_csum_cg && (update_csums == 1)) {
3074086Sabalfour 			(void) memmove((void *)cg, (void *)newcg,
3084086Sabalfour 			    (size_t)basesize);
309392Sswilcox 			/* LINTED per cg_sanity() */
310392Sswilcox 			(void) memmove((void *)&cg_blktot(cg)[0],
311392Sswilcox 			    /* LINTED macro aligned as above */
312392Sswilcox 			    (void *)&cg_blktot(newcg)[0], sumsize);
313392Sswilcox 			cgdirty();
3143219Sabalfour 			(void) printf("CORRECTED SUMMARIES FOR CG %d\n", c);
3150Sstevel@tonic-gate 		}
316392Sswilcox 
317392Sswilcox 		excessdirs = cg->cg_cs.cs_ndir - newcg->cg_cs.cs_ndir;
318392Sswilcox 		if (excessdirs < 0) {
319392Sswilcox 			pfatal("LOST %d DIRECTORIES IN CG %d\n",
320392Sswilcox 			    -excessdirs, c);
321392Sswilcox 			excessdirs = 0;
3220Sstevel@tonic-gate 		}
323392Sswilcox 		if (excessdirs > 0) {
324392Sswilcox 			if (check_maps((uchar_t *)cg_inosused(newcg),
325392Sswilcox 			    (uchar_t *)cg_inosused(cg), inomapsize,
326392Sswilcox 			    cg->cg_cgx * fs->fs_ipg, "DIR", 0, excessdirs)) {
327392Sswilcox 				if (!verbose)
328392Sswilcox 					(void) printf("DIR BITMAP WRONG ");
329392Sswilcox 				if (preen || update_bitmaps ||
330392Sswilcox 				    reply("FIX") == 1) {
331392Sswilcox 					(void) memmove((void *)cg_inosused(cg),
332392Sswilcox 					    (void *)cg_inosused(newcg),
333392Sswilcox 					    inomapsize);
334392Sswilcox 					cgdirty();
335392Sswilcox 					if (preen ||
336392Sswilcox 					    (!verbose && update_bitmaps))
337392Sswilcox 						(void) printf("(CORRECTED)\n");
338392Sswilcox 					update_bitmaps = 1;
339392Sswilcox 				}
340392Sswilcox 			}
3410Sstevel@tonic-gate 		}
342392Sswilcox 
343392Sswilcox 		if (check_maps((uchar_t *)cg_inosused(newcg),
344392Sswilcox 		    (uchar_t *)cg_inosused(cg), inomapsize,
345392Sswilcox 		    cg->cg_cgx * fs->fs_ipg, "FILE", excessdirs, fs->fs_ipg)) {
346392Sswilcox 			if (!verbose)
347392Sswilcox 				(void) printf("FILE BITMAP WRONG ");
348392Sswilcox 			if (preen || update_bitmaps || reply("FIX") == 1) {
349392Sswilcox 				(void) memmove((void *)cg_inosused(cg),
350392Sswilcox 				    (void *)cg_inosused(newcg), inomapsize);
351392Sswilcox 				cgdirty();
352392Sswilcox 				if (preen ||
353392Sswilcox 				    (!verbose && update_bitmaps))
354392Sswilcox 					(void) printf("(CORRECTED)\n");
355392Sswilcox 				update_bitmaps = 1;
356392Sswilcox 			}
357392Sswilcox 		}
358392Sswilcox 
359392Sswilcox 		if (check_maps((uchar_t *)cg_blksfree(cg),
360392Sswilcox 		    (uchar_t *)cg_blksfree(newcg), blkmapsize,
361392Sswilcox 		    cg->cg_cgx * fs->fs_fpg, "FRAG", 0, fs->fs_fpg)) {
362392Sswilcox 			if (!verbose)
363392Sswilcox 				(void) printf("FRAG BITMAP WRONG ");
364392Sswilcox 			if (preen || update_bitmaps || reply("FIX") == 1) {
365392Sswilcox 				(void) memmove((void *)cg_blksfree(cg),
366392Sswilcox 				    (void *)cg_blksfree(newcg), blkmapsize);
367392Sswilcox 				cgdirty();
368392Sswilcox 				if (preen ||
369392Sswilcox 				    (!verbose && update_bitmaps))
370392Sswilcox 					(void) printf("(CORRECTED)\n");
371392Sswilcox 				update_bitmaps = 1;
372392Sswilcox 			}
3730Sstevel@tonic-gate 		}
3740Sstevel@tonic-gate 
3756715Svsakar 		bad_cgblks_cg = (memcmp((void *)&cg_blks(fs, cg, 0)[0],
3766715Svsakar 		    (void *)&cg_blks(fs, newcg, 0)[0],
377*12838SAndrew.Balfour@Sun.COM 		    fs->fs_cpg * fs->fs_nrpos * sizeof (int16_t)) != 0);
3786715Svsakar 
3796715Svsakar 		if (bad_cgblks_cg) {
3806715Svsakar 			if (!verbose)
3816715Svsakar 				(void) printf("ROTATIONAL POSITIONS "
3826715Svsakar 				    "BLOCK COUNT WRONG ");
3836715Svsakar 			if (preen || update_bitmaps || reply("FIX") == 1) {
3846715Svsakar 				(void) memmove((void *)&cg_blks(fs, cg, 0)[0],
3856715Svsakar 				    (void *)&cg_blks(fs, newcg, 0)[0],
3866715Svsakar 				    fs->fs_cpg * fs->fs_nrpos *
387*12838SAndrew.Balfour@Sun.COM 				    sizeof (int16_t));
3886715Svsakar 				cgdirty();
3896715Svsakar 				if (preen ||
3906715Svsakar 				    (!verbose && update_bitmaps))
3916715Svsakar 					(void) printf("(CORRECTED)\n");
3926715Svsakar 				update_bitmaps = 1;
3936715Svsakar 			}
3946715Svsakar 		}
3956715Svsakar 
3966715Svsakar 		bad_cgblktot_cg = (memcmp((void *)&cg_blktot(cg)[0],
3976715Svsakar 		    (void *)&cg_blktot(newcg)[0],
3986715Svsakar 		    fs->fs_cpg * sizeof (int32_t)) != 0);
3996715Svsakar 
4006715Svsakar 		if (bad_cgblktot_cg) {
4016715Svsakar 			if (!verbose)
4026715Svsakar 				(void) printf("ROTATIONAL POSITIONS "
4036715Svsakar 				    "BLOCK TOTAL WRONG ");
4046715Svsakar 			if (preen || update_bitmaps || reply("FIX") == 1) {
4056715Svsakar 				(void) memmove((void *)&cg_blktot(cg)[0],
4066715Svsakar 				    (void *)&cg_blktot(newcg)[0],
4076715Svsakar 				    fs->fs_cpg * sizeof (int32_t));
4086715Svsakar 				cgdirty();
4096715Svsakar 				if (preen ||
4106715Svsakar 				    (!verbose && update_bitmaps))
4116715Svsakar 					(void) printf("(CORRECTED)\n");
4126715Svsakar 				update_bitmaps = 1;
4136715Svsakar 			}
4146715Svsakar 		}
4156715Svsakar 
416392Sswilcox 		/*
417392Sswilcox 		 * Fixing one set of problems often shows up more in the
418392Sswilcox 		 * same cg.  Just to make sure, go back and check it
419392Sswilcox 		 * again if we found something this time through.
420392Sswilcox 		 */
421392Sswilcox 		if (cgisdirty()) {
422392Sswilcox 			cgflush();
423392Sswilcox 			cstotal = backup_cs;
424392Sswilcox 			c--;
4250Sstevel@tonic-gate 		}
4260Sstevel@tonic-gate 	}
427392Sswilcox 
4280Sstevel@tonic-gate 	if ((fflag || !(islog && islogok)) &&
429392Sswilcox 	    (memcmp((void *)&cstotal, (void *)&fs->fs_cstotal,
430392Sswilcox 	    sizeof (struct csum)) != 0)) {
431392Sswilcox 		if (dofix(&idesc, "CORRECT GLOBAL SUMMARY")) {
432392Sswilcox 			(void) memmove((void *)&fs->fs_cstotal,
433392Sswilcox 			    (void *)&cstotal, sizeof (struct csum));
434392Sswilcox 			fs->fs_ronly = 0;
435392Sswilcox 			fs->fs_fmod = 0;
436392Sswilcox 			sbdirty();
437392Sswilcox 		} else {
438392Sswilcox 			iscorrupt = 1;
439392Sswilcox 		}
4400Sstevel@tonic-gate 	}
4410Sstevel@tonic-gate }
442392Sswilcox 
443392Sswilcox /*
444392Sswilcox  * Compare two allocation bitmaps, reporting any discrepancies.
445392Sswilcox  *
446392Sswilcox  * If a mismatch is found, if the bit is set in map1, it's considered
447392Sswilcox  * to be an indication that the corresponding resource is supposed
448392Sswilcox  * to be free, but isn't.  Otherwise, it's considered marked as allocated
449392Sswilcox  * but not found to be so.  In other words, if the two maps being compared
450392Sswilcox  * use a set bit to indicate something is free, pass the on-disk map
451392Sswilcox  * first.  Otherwise, pass the calculated map first.
452392Sswilcox  */
453392Sswilcox static int
check_maps(uchar_t * map1,uchar_t * map2,int mapsize,int startvalue,char * name,int skip,int limit)454392Sswilcox check_maps(
455392Sswilcox 	uchar_t *map1,	/* map of claimed allocations */
456392Sswilcox 	uchar_t *map2,	/* map of determined allocations */
457392Sswilcox 	int mapsize,	/* size of above two maps */
458392Sswilcox 	int startvalue,	/* resource value for first element in map */
459392Sswilcox 	char *name,	/* name of resource found in maps */
460392Sswilcox 	int skip,	/* number of entries to skip before starting to free */
461392Sswilcox 	int limit)	/* limit on number of entries to free */
462392Sswilcox {
463392Sswilcox 	long i, j, k, l, m, n, size;
464392Sswilcox 	int astart, aend, ustart, uend;
465392Sswilcox 	int mismatch;
466392Sswilcox 
467392Sswilcox 	mismatch = 0;
468392Sswilcox 	astart = ustart = aend = uend = -1;
469392Sswilcox 	for (i = 0; i < mapsize; i++) {
470392Sswilcox 		j = *map1++;
471392Sswilcox 		k = *map2++;
472392Sswilcox 		if (j == k)
473392Sswilcox 			continue;
474392Sswilcox 		for (m = 0, l = 1; m < NBBY; m++, l <<= 1) {
475392Sswilcox 			if ((j & l) == (k & l))
476392Sswilcox 				continue;
477392Sswilcox 			n = startvalue + i * NBBY + m;
478392Sswilcox 			if ((j & l) != 0) {
479392Sswilcox 				if (astart == -1) {
480392Sswilcox 					astart = aend = n;
481392Sswilcox 					continue;
482392Sswilcox 				}
483392Sswilcox 				if (aend + 1 == n) {
484392Sswilcox 					aend = n;
485392Sswilcox 					continue;
486392Sswilcox 				}
487392Sswilcox 				if (verbose) {
488392Sswilcox 					if (astart == aend)
489392Sswilcox 						pwarn(
490392Sswilcox 			    "ALLOCATED %s %d WAS MARKED FREE ON DISK\n",
491392Sswilcox 						    name, astart);
492392Sswilcox 					else
493392Sswilcox 						pwarn(
494392Sswilcox 			    "ALLOCATED %sS %d-%d WERE MARKED FREE ON DISK\n",
495392Sswilcox 						    name, astart, aend);
496392Sswilcox 				}
497392Sswilcox 				mismatch = 1;
498392Sswilcox 				astart = aend = n;
499392Sswilcox 			} else {
500392Sswilcox 				if (ustart == -1) {
501392Sswilcox 					ustart = uend = n;
502392Sswilcox 					continue;
503392Sswilcox 				}
504392Sswilcox 				if (uend + 1 == n) {
505392Sswilcox 					uend = n;
506392Sswilcox 					continue;
507392Sswilcox 				}
508392Sswilcox 				size = uend - ustart + 1;
509392Sswilcox 				if (size <= skip) {
510392Sswilcox 					skip -= size;
511392Sswilcox 					ustart = uend = n;
512392Sswilcox 					continue;
513392Sswilcox 				}
514392Sswilcox 				if (skip > 0) {
515392Sswilcox 					ustart += skip;
516392Sswilcox 					size -= skip;
517392Sswilcox 					skip = 0;
518392Sswilcox 				}
519392Sswilcox 				if (size > limit)
520392Sswilcox 					size = limit;
521392Sswilcox 				if (verbose) {
522392Sswilcox 					if (size == 1)
523392Sswilcox 						pwarn(
524392Sswilcox 			    "UNALLOCATED %s %d WAS MARKED USED ON DISK\n",
525392Sswilcox 						    name, ustart);
526392Sswilcox 					else
527392Sswilcox 						pwarn(
528392Sswilcox 			    "UNALLOCATED %sS %d-%ld WERE MARKED USED ON DISK\n",
529392Sswilcox 						    name, ustart,
530392Sswilcox 						    ustart + size - 1);
531392Sswilcox 				}
532392Sswilcox 				mismatch = 1;
533392Sswilcox 				limit -= size;
534392Sswilcox 				if (limit <= 0)
535392Sswilcox 					return (mismatch);
536392Sswilcox 				ustart = uend = n;
537392Sswilcox 			}
538392Sswilcox 		}
539392Sswilcox 	}
540392Sswilcox 	if (astart != -1) {
541392Sswilcox 		if (verbose) {
542392Sswilcox 			if (astart == aend)
543392Sswilcox 				pwarn(
544392Sswilcox 			    "ALLOCATED %s %d WAS MARKED FREE ON DISK\n",
545392Sswilcox 				    name, astart);
546392Sswilcox 			else
547392Sswilcox 				pwarn(
548392Sswilcox 			    "ALLOCATED %sS %d-%d WERE MARKED FREE ON DISK\n",
549392Sswilcox 				    name, astart, aend);
550392Sswilcox 		}
551392Sswilcox 		mismatch = 1;
552392Sswilcox 	}
553392Sswilcox 	if (ustart != -1) {
554392Sswilcox 		size = uend - ustart + 1;
555392Sswilcox 		if (size <= skip)
556392Sswilcox 			return (mismatch);
557392Sswilcox 		if (skip > 0) {
558392Sswilcox 			ustart += skip;
559392Sswilcox 			size -= skip;
560392Sswilcox 		}
561392Sswilcox 		if (size > limit)
562392Sswilcox 			size = limit;
563392Sswilcox 		if (verbose) {
564392Sswilcox 			if (size == 1)
565392Sswilcox 				pwarn(
566392Sswilcox 			    "UNALLOCATED %s %d WAS MARKED USED ON DISK\n",
567392Sswilcox 				    name, ustart);
568392Sswilcox 			else
569392Sswilcox 				pwarn(
570392Sswilcox 		    "UNALLOCATED %sS %d-%ld WERE MARKED USED ON DISK\n",
571392Sswilcox 				    name, ustart, ustart + size - 1);
572392Sswilcox 		}
573392Sswilcox 		mismatch = 1;
574392Sswilcox 	}
575392Sswilcox 	return (mismatch);
576392Sswilcox }
577