xref: /illumos-gate/usr/src/cmd/fs.d/ufs/fsck/pass5.c (revision 355d6bb5)
17c478bd9Sstevel@tonic-gate /*
2*355d6bb5Sswilcox  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
37c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate  */
57c478bd9Sstevel@tonic-gate 
67c478bd9Sstevel@tonic-gate /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
77c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
87c478bd9Sstevel@tonic-gate 
97c478bd9Sstevel@tonic-gate /*
107c478bd9Sstevel@tonic-gate  * Copyright (c) 1980, 1986, 1990 The Regents of the University of California.
117c478bd9Sstevel@tonic-gate  * All rights reserved.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * Redistribution and use in source and binary forms are permitted
147c478bd9Sstevel@tonic-gate  * provided that: (1) source distributions retain this entire copyright
157c478bd9Sstevel@tonic-gate  * notice and comment, and (2) distributions including binaries display
167c478bd9Sstevel@tonic-gate  * the following acknowledgement:  ``This product includes software
177c478bd9Sstevel@tonic-gate  * developed by the University of California, Berkeley and its contributors''
187c478bd9Sstevel@tonic-gate  * in the documentation or other materials provided with the distribution
197c478bd9Sstevel@tonic-gate  * and in all advertising materials mentioning features or use of this
207c478bd9Sstevel@tonic-gate  * software. Neither the name of the University nor the names of its
217c478bd9Sstevel@tonic-gate  * contributors may be used to endorse or promote products derived
227c478bd9Sstevel@tonic-gate  * from this software without specific prior written permission.
237c478bd9Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
247c478bd9Sstevel@tonic-gate  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
257c478bd9Sstevel@tonic-gate  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
267c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
297c478bd9Sstevel@tonic-gate 
30*355d6bb5Sswilcox #include <stdio.h>
31*355d6bb5Sswilcox #include <stdlib.h>
32*355d6bb5Sswilcox #include <unistd.h>
33*355d6bb5Sswilcox #include <string.h>
347c478bd9Sstevel@tonic-gate #include <sys/param.h>
357c478bd9Sstevel@tonic-gate #include <sys/mntent.h>
367c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_fs.h>
377c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
387c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_inode.h>
397c478bd9Sstevel@tonic-gate #include "fsck.h"
407c478bd9Sstevel@tonic-gate 
41*355d6bb5Sswilcox static int check_maps(uchar_t *, uchar_t *, int, int, char *, int, int);
42*355d6bb5Sswilcox 
43*355d6bb5Sswilcox void
44*355d6bb5Sswilcox pass5(void)
457c478bd9Sstevel@tonic-gate {
46*355d6bb5Sswilcox 	caddr_t err;
47*355d6bb5Sswilcox 	int32_t c, blk, frags;
48*355d6bb5Sswilcox 	int cg_fatal;
497c478bd9Sstevel@tonic-gate 	size_t	basesize, sumsize, mapsize;
50*355d6bb5Sswilcox 	int excessdirs;
51*355d6bb5Sswilcox 	int inomapsize, blkmapsize;
52*355d6bb5Sswilcox 	int update_csums, bad_csum, update_bitmaps;
537c478bd9Sstevel@tonic-gate 	struct fs *fs = &sblock;
547c478bd9Sstevel@tonic-gate 	struct cg *cg = &cgrp;
557c478bd9Sstevel@tonic-gate 	diskaddr_t dbase, dmax;
567c478bd9Sstevel@tonic-gate 	diskaddr_t d;
577c478bd9Sstevel@tonic-gate 	uint64_t i, j;
587c478bd9Sstevel@tonic-gate 	struct csum *cs;
59*355d6bb5Sswilcox 	struct csum backup_cs;
607c478bd9Sstevel@tonic-gate 	time_t now;
617c478bd9Sstevel@tonic-gate 	struct csum cstotal;
627c478bd9Sstevel@tonic-gate 	struct inodesc idesc;
63*355d6bb5Sswilcox 	union {				/* keep lint happy about alignment */
64*355d6bb5Sswilcox 		struct cg cg;		/* the rest of buf has the bitmaps */
65*355d6bb5Sswilcox 		char buf[MAXBSIZE];
66*355d6bb5Sswilcox 	} u;
67*355d6bb5Sswilcox 	caddr_t buf = u.buf;
68*355d6bb5Sswilcox 	struct cg *newcg = &u.cg;
697c478bd9Sstevel@tonic-gate 
70*355d6bb5Sswilcox 	(void) memset((void *)buf, 0, sizeof (u.buf));
717c478bd9Sstevel@tonic-gate 	newcg->cg_niblk = fs->fs_ipg;
72*355d6bb5Sswilcox 
73*355d6bb5Sswilcox 	if (fs->fs_postblformat != FS_DYNAMICPOSTBLFMT) {
74*355d6bb5Sswilcox 		pfatal("UNSUPPORTED ROTATIONAL TABLE FORMAT %d\n",
757c478bd9Sstevel@tonic-gate 			fs->fs_postblformat);
76*355d6bb5Sswilcox 		errexit("Program terminated.");
77*355d6bb5Sswilcox 		/* NOTREACHED */
787c478bd9Sstevel@tonic-gate 	}
797c478bd9Sstevel@tonic-gate 
80*355d6bb5Sswilcox 	/* LINTED this subtraction can't overflow and is int32-aligned */
81*355d6bb5Sswilcox 	basesize = &newcg->cg_space[0] - (uchar_t *)newcg;
82*355d6bb5Sswilcox 
83*355d6bb5Sswilcox 	/*
84*355d6bb5Sswilcox 	 * We reserve the space for the old rotation summary
85*355d6bb5Sswilcox 	 * tables for the benefit of old kernels, but do not
86*355d6bb5Sswilcox 	 * maintain them in modern kernels. In time, they could
87*355d6bb5Sswilcox 	 * theoretically go away, if we wanted to deal with
88*355d6bb5Sswilcox 	 * changing the on-disk format.
89*355d6bb5Sswilcox 	 */
90*355d6bb5Sswilcox 
91*355d6bb5Sswilcox 	/*
92*355d6bb5Sswilcox 	 * Note that we don't use any of the cg_*() macros until
93*355d6bb5Sswilcox 	 * after cg_sanity() has approved of what we've got.
94*355d6bb5Sswilcox 	 */
95*355d6bb5Sswilcox 	newcg->cg_btotoff = basesize;
96*355d6bb5Sswilcox 	newcg->cg_boff = newcg->cg_btotoff + fs->fs_cpg * sizeof (daddr32_t);
97*355d6bb5Sswilcox 	newcg->cg_iusedoff = newcg->cg_boff +
98*355d6bb5Sswilcox 		fs->fs_cpg * fs->fs_nrpos * sizeof (uint16_t);
99*355d6bb5Sswilcox 	(void) memset(&newcg->cg_space[0], 0, newcg->cg_iusedoff - basesize);
100*355d6bb5Sswilcox 
101*355d6bb5Sswilcox 	inomapsize = howmany(fs->fs_ipg, NBBY);
102*355d6bb5Sswilcox 	newcg->cg_freeoff = newcg->cg_iusedoff + inomapsize;
103*355d6bb5Sswilcox 	blkmapsize = howmany(fs->fs_fpg, NBBY);
104*355d6bb5Sswilcox 	newcg->cg_nextfreeoff = newcg->cg_freeoff + blkmapsize;
105*355d6bb5Sswilcox 	newcg->cg_magic = CG_MAGIC;
106*355d6bb5Sswilcox 
107*355d6bb5Sswilcox 	sumsize = newcg->cg_iusedoff - newcg->cg_btotoff;
108*355d6bb5Sswilcox 	mapsize = newcg->cg_nextfreeoff - newcg->cg_iusedoff;
109*355d6bb5Sswilcox 
110*355d6bb5Sswilcox 	init_inodesc(&idesc);
1117c478bd9Sstevel@tonic-gate 	idesc.id_type = ADDR;
112*355d6bb5Sswilcox 	(void) memset((void *)&cstotal, 0, sizeof (struct csum));
113*355d6bb5Sswilcox 	now = time(NULL);
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate 	/*
1167c478bd9Sstevel@tonic-gate 	 * If the last fragments in the file system don't make up a
1177c478bd9Sstevel@tonic-gate 	 * full file system block, mark the bits in the blockmap
1187c478bd9Sstevel@tonic-gate 	 * that correspond to those missing fragments as "allocated",
1197c478bd9Sstevel@tonic-gate 	 * so that the last block doesn't get counted as a free block
1207c478bd9Sstevel@tonic-gate 	 * and those missing fragments don't get counted as free frags.
1217c478bd9Sstevel@tonic-gate 	 */
1227c478bd9Sstevel@tonic-gate 	j = blknum(fs, (uint64_t)fs->fs_size + fs->fs_frag - 1);
1237c478bd9Sstevel@tonic-gate 	for (i = fs->fs_size; i < j; i++)
1247c478bd9Sstevel@tonic-gate 		setbmap(i);
125*355d6bb5Sswilcox 
126*355d6bb5Sswilcox 	/*
127*355d6bb5Sswilcox 	 * The cg summaries are not always updated when using
128*355d6bb5Sswilcox 	 * logging.  Since we're really concerned with getting a
129*355d6bb5Sswilcox 	 * sane filesystem, rather than in trying to debug UFS
130*355d6bb5Sswilcox 	 * corner cases, logically we would just always recompute
131*355d6bb5Sswilcox 	 * them.  However, it is disconcerting to users to be asked
132*355d6bb5Sswilcox 	 * about updating the summaries when, from their point of
133*355d6bb5Sswilcox 	 * view, there's been no indication of a problem up to this
134*355d6bb5Sswilcox 	 * point.  So, only do it if we find a discrepancy.
135*355d6bb5Sswilcox 	 */
136*355d6bb5Sswilcox 	update_csums = -1;
137*355d6bb5Sswilcox 	update_bitmaps = 0;
1387c478bd9Sstevel@tonic-gate 	for (c = 0; c < fs->fs_ncg; c++) {
139*355d6bb5Sswilcox 		backup_cs = cstotal;
140*355d6bb5Sswilcox 
141*355d6bb5Sswilcox 		/*
142*355d6bb5Sswilcox 		 * cg_sanity() will catch i/o errors for us.
143*355d6bb5Sswilcox 		 */
144*355d6bb5Sswilcox 		(void) getblk(&cgblk, (diskaddr_t)cgtod(fs, c),
145*355d6bb5Sswilcox 		    (size_t)fs->fs_cgsize);
146*355d6bb5Sswilcox 		err = cg_sanity(cg, c, &cg_fatal);
147*355d6bb5Sswilcox 		if (err != NULL) {
148*355d6bb5Sswilcox 			pfatal("CG %d: %s\n", c, err);
149*355d6bb5Sswilcox 			free((void *)err);
150*355d6bb5Sswilcox 			if (cg_fatal)
151*355d6bb5Sswilcox 				errexit(
152*355d6bb5Sswilcox 	    "Irreparable cylinder group header problem.  Program terminated.");
153*355d6bb5Sswilcox 			if (reply("REPAIR") == 0)
154*355d6bb5Sswilcox 				errexit("Program terminated.");
155*355d6bb5Sswilcox 			fix_cg(cg, c);
156*355d6bb5Sswilcox 		}
157*355d6bb5Sswilcox 		/*
158*355d6bb5Sswilcox 		 * If the on-disk timestamp is in the future, then it
159*355d6bb5Sswilcox 		 * by definition is wrong.  Otherwise, if it's in
160*355d6bb5Sswilcox 		 * the past, then use that value so that we don't
161*355d6bb5Sswilcox 		 * declare a spurious mismatch.
162*355d6bb5Sswilcox 		 */
1637c478bd9Sstevel@tonic-gate 		if (now > cg->cg_time)
1647c478bd9Sstevel@tonic-gate 			newcg->cg_time = cg->cg_time;
1657c478bd9Sstevel@tonic-gate 		else
1667c478bd9Sstevel@tonic-gate 			newcg->cg_time = now;
1677c478bd9Sstevel@tonic-gate 		newcg->cg_cgx = c;
168*355d6bb5Sswilcox 		dbase = cgbase(fs, c);
169*355d6bb5Sswilcox 		dmax = dbase + fs->fs_fpg;
170*355d6bb5Sswilcox 		if (dmax > fs->fs_size)
171*355d6bb5Sswilcox 			dmax = fs->fs_size;
172*355d6bb5Sswilcox 		newcg->cg_ndblk = dmax - dbase;
1737c478bd9Sstevel@tonic-gate 		if (c == fs->fs_ncg - 1)
1747c478bd9Sstevel@tonic-gate 			newcg->cg_ncyl = fs->fs_ncyl % fs->fs_cpg;
1757c478bd9Sstevel@tonic-gate 		else
1767c478bd9Sstevel@tonic-gate 			newcg->cg_ncyl = fs->fs_cpg;
1777c478bd9Sstevel@tonic-gate 		newcg->cg_niblk = sblock.fs_ipg;
1787c478bd9Sstevel@tonic-gate 		newcg->cg_cs.cs_ndir = 0;
1797c478bd9Sstevel@tonic-gate 		newcg->cg_cs.cs_nffree = 0;
1807c478bd9Sstevel@tonic-gate 		newcg->cg_cs.cs_nbfree = 0;
1817c478bd9Sstevel@tonic-gate 		newcg->cg_cs.cs_nifree = fs->fs_ipg;
1827c478bd9Sstevel@tonic-gate 		if ((cg->cg_rotor >= 0) && (cg->cg_rotor < newcg->cg_ndblk))
1837c478bd9Sstevel@tonic-gate 			newcg->cg_rotor = cg->cg_rotor;
1847c478bd9Sstevel@tonic-gate 		else
1857c478bd9Sstevel@tonic-gate 			newcg->cg_rotor = 0;
1867c478bd9Sstevel@tonic-gate 		if ((cg->cg_frotor >= 0) && (cg->cg_frotor < newcg->cg_ndblk))
1877c478bd9Sstevel@tonic-gate 			newcg->cg_frotor = cg->cg_frotor;
1887c478bd9Sstevel@tonic-gate 		else
1897c478bd9Sstevel@tonic-gate 			newcg->cg_frotor = 0;
1907c478bd9Sstevel@tonic-gate 		if ((cg->cg_irotor >= 0) && (cg->cg_irotor < newcg->cg_niblk))
1917c478bd9Sstevel@tonic-gate 			newcg->cg_irotor = cg->cg_irotor;
1927c478bd9Sstevel@tonic-gate 		else
1937c478bd9Sstevel@tonic-gate 			newcg->cg_irotor = 0;
194*355d6bb5Sswilcox 		(void) memset((void *)&newcg->cg_frsum[0], 0,
195*355d6bb5Sswilcox 		    sizeof (newcg->cg_frsum));
196*355d6bb5Sswilcox 		(void) memset((void *)cg_inosused(newcg), 0, (size_t)mapsize);
197*355d6bb5Sswilcox 		/* LINTED macro is int32-aligned per newcg->cg_btotoff above */
198*355d6bb5Sswilcox 		(void) memset((void *)&cg_blktot(newcg)[0], 0,
199*355d6bb5Sswilcox 		    sumsize + mapsize);
2007c478bd9Sstevel@tonic-gate 		j = fs->fs_ipg * c;
2017c478bd9Sstevel@tonic-gate 		for (i = 0; i < fs->fs_ipg; j++, i++) {
202*355d6bb5Sswilcox 			switch (statemap[j] & ~(INORPHAN | INDELAYD)) {
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate 			case USTATE:
2057c478bd9Sstevel@tonic-gate 				break;
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate 			case DSTATE:
2087c478bd9Sstevel@tonic-gate 			case DCLEAR:
2097c478bd9Sstevel@tonic-gate 			case DFOUND:
210*355d6bb5Sswilcox 			case DZLINK:
2117c478bd9Sstevel@tonic-gate 				newcg->cg_cs.cs_ndir++;
212*355d6bb5Sswilcox 				/* FALLTHROUGH */
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate 			case FSTATE:
2157c478bd9Sstevel@tonic-gate 			case FCLEAR:
216*355d6bb5Sswilcox 			case FZLINK:
2177c478bd9Sstevel@tonic-gate 			case SSTATE:
2187c478bd9Sstevel@tonic-gate 			case SCLEAR:
2197c478bd9Sstevel@tonic-gate 				newcg->cg_cs.cs_nifree--;
2207c478bd9Sstevel@tonic-gate 				setbit(cg_inosused(newcg), i);
2217c478bd9Sstevel@tonic-gate 				break;
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate 			default:
2247c478bd9Sstevel@tonic-gate 				if (j < UFSROOTINO)
2257c478bd9Sstevel@tonic-gate 					break;
226*355d6bb5Sswilcox 				errexit("BAD STATE 0x%x FOR INODE I=%d",
227*355d6bb5Sswilcox 				    statemap[j], (int)j);
2287c478bd9Sstevel@tonic-gate 			}
2297c478bd9Sstevel@tonic-gate 		}
230*355d6bb5Sswilcox 		if (c == 0) {
2317c478bd9Sstevel@tonic-gate 			for (i = 0; i < UFSROOTINO; i++) {
2327c478bd9Sstevel@tonic-gate 				setbit(cg_inosused(newcg), i);
2337c478bd9Sstevel@tonic-gate 				newcg->cg_cs.cs_nifree--;
2347c478bd9Sstevel@tonic-gate 			}
235*355d6bb5Sswilcox 		}
236*355d6bb5Sswilcox 		/*
237*355d6bb5Sswilcox 		 * Count up what fragments and blocks are free, and
238*355d6bb5Sswilcox 		 * reflect the relevant section of blockmap[] into
239*355d6bb5Sswilcox 		 * newcg's map.
240*355d6bb5Sswilcox 		 */
2417c478bd9Sstevel@tonic-gate 		for (i = 0, d = dbase;
2427c478bd9Sstevel@tonic-gate 		    d < dmax;
2437c478bd9Sstevel@tonic-gate 		    d += fs->fs_frag, i += fs->fs_frag) {
2447c478bd9Sstevel@tonic-gate 			frags = 0;
2457c478bd9Sstevel@tonic-gate 			for (j = 0; j < fs->fs_frag; j++) {
2467c478bd9Sstevel@tonic-gate 				if (testbmap(d + j))
2477c478bd9Sstevel@tonic-gate 					continue;
2487c478bd9Sstevel@tonic-gate 				setbit(cg_blksfree(newcg), i + j);
2497c478bd9Sstevel@tonic-gate 				frags++;
2507c478bd9Sstevel@tonic-gate 			}
2517c478bd9Sstevel@tonic-gate 			if (frags == fs->fs_frag) {
2527c478bd9Sstevel@tonic-gate 				newcg->cg_cs.cs_nbfree++;
2537c478bd9Sstevel@tonic-gate 				j = cbtocylno(fs, i);
254*355d6bb5Sswilcox 				/* LINTED macro is int32-aligned per above */
2557c478bd9Sstevel@tonic-gate 				cg_blktot(newcg)[j]++;
256*355d6bb5Sswilcox 				/* LINTED cg_blks(newcg) is aligned */
2577c478bd9Sstevel@tonic-gate 				cg_blks(fs, newcg, j)[cbtorpos(fs, i)]++;
2587c478bd9Sstevel@tonic-gate 			} else if (frags > 0) {
2597c478bd9Sstevel@tonic-gate 				newcg->cg_cs.cs_nffree += frags;
2607c478bd9Sstevel@tonic-gate 				blk = blkmap(fs, cg_blksfree(newcg), i);
2617c478bd9Sstevel@tonic-gate 				fragacct(fs, blk, newcg->cg_frsum, 1);
2627c478bd9Sstevel@tonic-gate 			}
2637c478bd9Sstevel@tonic-gate 		}
2647c478bd9Sstevel@tonic-gate 		cstotal.cs_nffree += newcg->cg_cs.cs_nffree;
2657c478bd9Sstevel@tonic-gate 		cstotal.cs_nbfree += newcg->cg_cs.cs_nbfree;
2667c478bd9Sstevel@tonic-gate 		cstotal.cs_nifree += newcg->cg_cs.cs_nifree;
2677c478bd9Sstevel@tonic-gate 		cstotal.cs_ndir += newcg->cg_cs.cs_ndir;
2687c478bd9Sstevel@tonic-gate 
269*355d6bb5Sswilcox 		/*
270*355d6bb5Sswilcox 		 * Note that, just like the kernel, we dynamically
271*355d6bb5Sswilcox 		 * allocated an array to hold the csums and stuffed
272*355d6bb5Sswilcox 		 * the pointer into the in-core superblock's fs_u.fs_csp
273*355d6bb5Sswilcox 		 * field.  This means that the fs_u field contains a
274*355d6bb5Sswilcox 		 * random value when the disk version is examined, but
275*355d6bb5Sswilcox 		 * fs_cs() gives us a valid pointer nonetheless.
276*355d6bb5Sswilcox 		 */
2777c478bd9Sstevel@tonic-gate 		cs = &fs->fs_cs(fs, c);
278*355d6bb5Sswilcox 		bad_csum = (memcmp((void *)cs, (void *)&newcg->cg_cs,
279*355d6bb5Sswilcox 		    sizeof (*cs)) != 0);
280*355d6bb5Sswilcox 
281*355d6bb5Sswilcox 		/*
282*355d6bb5Sswilcox 		 * Has the user told us what to do yet?  If not, find out.
283*355d6bb5Sswilcox 		 */
284*355d6bb5Sswilcox 		if (bad_csum && (update_csums == -1)) {
285*355d6bb5Sswilcox 			if (preen) {
286*355d6bb5Sswilcox 				update_csums = 1;
287*355d6bb5Sswilcox 				(void) printf("CORRECTING BAD CG SUMMARIES\n");
288*355d6bb5Sswilcox 			} else if (update_csums == -1) {
289*355d6bb5Sswilcox 				update_csums = (reply(
290*355d6bb5Sswilcox 				    "CORRECT BAD CG SUMMARIES") == 1);
291*355d6bb5Sswilcox 			}
2927c478bd9Sstevel@tonic-gate 		}
293*355d6bb5Sswilcox 
294*355d6bb5Sswilcox 		if (bad_csum && (update_csums == 1)) {
295*355d6bb5Sswilcox 			(void) memmove((void *)cs, (void *)&newcg->cg_cs,
296*355d6bb5Sswilcox 			    sizeof (*cs));
297*355d6bb5Sswilcox 			sbdirty();
298*355d6bb5Sswilcox 
299*355d6bb5Sswilcox 			(void) memmove((void *)cg, (void *)newcg,
300*355d6bb5Sswilcox 			    (size_t)basesize);
301*355d6bb5Sswilcox 			/* LINTED per cg_sanity() */
302*355d6bb5Sswilcox 			(void) memmove((void *)&cg_blktot(cg)[0],
303*355d6bb5Sswilcox 			    /* LINTED macro aligned as above */
304*355d6bb5Sswilcox 			    (void *)&cg_blktot(newcg)[0], sumsize);
3057c478bd9Sstevel@tonic-gate 			cgdirty();
306*355d6bb5Sswilcox 			(void) printf("CORRECTED SUMMARY FOR CG %d\n", c);
3077c478bd9Sstevel@tonic-gate 		}
308*355d6bb5Sswilcox 
309*355d6bb5Sswilcox 		excessdirs = cg->cg_cs.cs_ndir - newcg->cg_cs.cs_ndir;
310*355d6bb5Sswilcox 		if (excessdirs < 0) {
311*355d6bb5Sswilcox 			pfatal("LOST %d DIRECTORIES IN CG %d\n",
312*355d6bb5Sswilcox 			    -excessdirs, c);
313*355d6bb5Sswilcox 			excessdirs = 0;
3147c478bd9Sstevel@tonic-gate 		}
315*355d6bb5Sswilcox 		if (excessdirs > 0) {
316*355d6bb5Sswilcox 			if (check_maps((uchar_t *)cg_inosused(newcg),
317*355d6bb5Sswilcox 			    (uchar_t *)cg_inosused(cg), inomapsize,
318*355d6bb5Sswilcox 			    cg->cg_cgx * fs->fs_ipg, "DIR", 0, excessdirs)) {
319*355d6bb5Sswilcox 				if (!verbose)
320*355d6bb5Sswilcox 					(void) printf("DIR BITMAP WRONG ");
321*355d6bb5Sswilcox 				if (preen || update_bitmaps ||
322*355d6bb5Sswilcox 				    reply("FIX") == 1) {
323*355d6bb5Sswilcox 					(void) memmove((void *)cg_inosused(cg),
324*355d6bb5Sswilcox 					    (void *)cg_inosused(newcg),
325*355d6bb5Sswilcox 					    inomapsize);
326*355d6bb5Sswilcox 					cgdirty();
327*355d6bb5Sswilcox 					if (preen ||
328*355d6bb5Sswilcox 					    (!verbose && update_bitmaps))
329*355d6bb5Sswilcox 						(void) printf("(CORRECTED)\n");
330*355d6bb5Sswilcox 					update_bitmaps = 1;
331*355d6bb5Sswilcox 				}
332*355d6bb5Sswilcox 			}
3337c478bd9Sstevel@tonic-gate 		}
3347c478bd9Sstevel@tonic-gate 
335*355d6bb5Sswilcox 		if (check_maps((uchar_t *)cg_inosused(newcg),
336*355d6bb5Sswilcox 		    (uchar_t *)cg_inosused(cg), inomapsize,
337*355d6bb5Sswilcox 		    cg->cg_cgx * fs->fs_ipg, "FILE", excessdirs, fs->fs_ipg)) {
338*355d6bb5Sswilcox 			if (!verbose)
339*355d6bb5Sswilcox 				(void) printf("FILE BITMAP WRONG ");
340*355d6bb5Sswilcox 			if (preen || update_bitmaps || reply("FIX") == 1) {
341*355d6bb5Sswilcox 				(void) memmove((void *)cg_inosused(cg),
342*355d6bb5Sswilcox 				    (void *)cg_inosused(newcg), inomapsize);
343*355d6bb5Sswilcox 				cgdirty();
344*355d6bb5Sswilcox 				if (preen ||
345*355d6bb5Sswilcox 				    (!verbose && update_bitmaps))
346*355d6bb5Sswilcox 					(void) printf("(CORRECTED)\n");
347*355d6bb5Sswilcox 				update_bitmaps = 1;
348*355d6bb5Sswilcox 			}
3497c478bd9Sstevel@tonic-gate 		}
3507c478bd9Sstevel@tonic-gate 
351*355d6bb5Sswilcox 		if (check_maps((uchar_t *)cg_blksfree(cg),
352*355d6bb5Sswilcox 		    (uchar_t *)cg_blksfree(newcg), blkmapsize,
353*355d6bb5Sswilcox 		    cg->cg_cgx * fs->fs_fpg, "FRAG", 0, fs->fs_fpg)) {
354*355d6bb5Sswilcox 			if (!verbose)
355*355d6bb5Sswilcox 				(void) printf("FRAG BITMAP WRONG ");
356*355d6bb5Sswilcox 			if (preen || update_bitmaps || reply("FIX") == 1) {
357*355d6bb5Sswilcox 				(void) memmove((void *)cg_blksfree(cg),
358*355d6bb5Sswilcox 				    (void *)cg_blksfree(newcg), blkmapsize);
359*355d6bb5Sswilcox 				cgdirty();
360*355d6bb5Sswilcox 				if (preen ||
361*355d6bb5Sswilcox 				    (!verbose && update_bitmaps))
362*355d6bb5Sswilcox 					(void) printf("(CORRECTED)\n");
363*355d6bb5Sswilcox 				update_bitmaps = 1;
364*355d6bb5Sswilcox 			}
365*355d6bb5Sswilcox 		}
366*355d6bb5Sswilcox 
367*355d6bb5Sswilcox 		/*
368*355d6bb5Sswilcox 		 * Fixing one set of problems often shows up more in the
369*355d6bb5Sswilcox 		 * same cg.  Just to make sure, go back and check it
370*355d6bb5Sswilcox 		 * again if we found something this time through.
371*355d6bb5Sswilcox 		 */
372*355d6bb5Sswilcox 		if (cgisdirty()) {
373*355d6bb5Sswilcox 			cgflush();
374*355d6bb5Sswilcox 			cstotal = backup_cs;
375*355d6bb5Sswilcox 			c--;
376*355d6bb5Sswilcox 		}
3777c478bd9Sstevel@tonic-gate 	}
378*355d6bb5Sswilcox 
3797c478bd9Sstevel@tonic-gate 	if ((fflag || !(islog && islogok)) &&
380*355d6bb5Sswilcox 	    (memcmp((void *)&cstotal, (void *)&fs->fs_cstotal,
381*355d6bb5Sswilcox 	    sizeof (struct csum)) != 0)) {
382*355d6bb5Sswilcox 		if (dofix(&idesc, "CORRECT GLOBAL SUMMARY")) {
383*355d6bb5Sswilcox 			(void) memmove((void *)&fs->fs_cstotal,
384*355d6bb5Sswilcox 			    (void *)&cstotal, sizeof (struct csum));
385*355d6bb5Sswilcox 			fs->fs_ronly = 0;
386*355d6bb5Sswilcox 			fs->fs_fmod = 0;
387*355d6bb5Sswilcox 			sbdirty();
388*355d6bb5Sswilcox 		} else {
389*355d6bb5Sswilcox 			iscorrupt = 1;
390*355d6bb5Sswilcox 		}
391*355d6bb5Sswilcox 	}
392*355d6bb5Sswilcox }
393*355d6bb5Sswilcox 
394*355d6bb5Sswilcox /*
395*355d6bb5Sswilcox  * Compare two allocation bitmaps, reporting any discrepancies.
396*355d6bb5Sswilcox  *
397*355d6bb5Sswilcox  * If a mismatch is found, if the bit is set in map1, it's considered
398*355d6bb5Sswilcox  * to be an indication that the corresponding resource is supposed
399*355d6bb5Sswilcox  * to be free, but isn't.  Otherwise, it's considered marked as allocated
400*355d6bb5Sswilcox  * but not found to be so.  In other words, if the two maps being compared
401*355d6bb5Sswilcox  * use a set bit to indicate something is free, pass the on-disk map
402*355d6bb5Sswilcox  * first.  Otherwise, pass the calculated map first.
403*355d6bb5Sswilcox  */
404*355d6bb5Sswilcox static int
405*355d6bb5Sswilcox check_maps(
406*355d6bb5Sswilcox 	uchar_t *map1,	/* map of claimed allocations */
407*355d6bb5Sswilcox 	uchar_t *map2,	/* map of determined allocations */
408*355d6bb5Sswilcox 	int mapsize,	/* size of above two maps */
409*355d6bb5Sswilcox 	int startvalue,	/* resource value for first element in map */
410*355d6bb5Sswilcox 	char *name,	/* name of resource found in maps */
411*355d6bb5Sswilcox 	int skip,	/* number of entries to skip before starting to free */
412*355d6bb5Sswilcox 	int limit)	/* limit on number of entries to free */
413*355d6bb5Sswilcox {
414*355d6bb5Sswilcox 	long i, j, k, l, m, n, size;
415*355d6bb5Sswilcox 	int astart, aend, ustart, uend;
416*355d6bb5Sswilcox 	int mismatch;
417*355d6bb5Sswilcox 
418*355d6bb5Sswilcox 	mismatch = 0;
419*355d6bb5Sswilcox 	astart = ustart = aend = uend = -1;
420*355d6bb5Sswilcox 	for (i = 0; i < mapsize; i++) {
421*355d6bb5Sswilcox 		j = *map1++;
422*355d6bb5Sswilcox 		k = *map2++;
423*355d6bb5Sswilcox 		if (j == k)
424*355d6bb5Sswilcox 			continue;
425*355d6bb5Sswilcox 		for (m = 0, l = 1; m < NBBY; m++, l <<= 1) {
426*355d6bb5Sswilcox 			if ((j & l) == (k & l))
427*355d6bb5Sswilcox 				continue;
428*355d6bb5Sswilcox 			n = startvalue + i * NBBY + m;
429*355d6bb5Sswilcox 			if ((j & l) != 0) {
430*355d6bb5Sswilcox 				if (astart == -1) {
431*355d6bb5Sswilcox 					astart = aend = n;
432*355d6bb5Sswilcox 					continue;
433*355d6bb5Sswilcox 				}
434*355d6bb5Sswilcox 				if (aend + 1 == n) {
435*355d6bb5Sswilcox 					aend = n;
436*355d6bb5Sswilcox 					continue;
437*355d6bb5Sswilcox 				}
438*355d6bb5Sswilcox 				if (verbose) {
439*355d6bb5Sswilcox 					if (astart == aend)
440*355d6bb5Sswilcox 						pwarn(
441*355d6bb5Sswilcox 			    "ALLOCATED %s %d WAS MARKED FREE ON DISK\n",
442*355d6bb5Sswilcox 						    name, astart);
443*355d6bb5Sswilcox 					else
444*355d6bb5Sswilcox 						pwarn(
445*355d6bb5Sswilcox 			    "ALLOCATED %sS %d-%d WERE MARKED FREE ON DISK\n",
446*355d6bb5Sswilcox 						    name, astart, aend);
447*355d6bb5Sswilcox 				}
448*355d6bb5Sswilcox 				mismatch = 1;
449*355d6bb5Sswilcox 				astart = aend = n;
450*355d6bb5Sswilcox 			} else {
451*355d6bb5Sswilcox 				if (ustart == -1) {
452*355d6bb5Sswilcox 					ustart = uend = n;
453*355d6bb5Sswilcox 					continue;
454*355d6bb5Sswilcox 				}
455*355d6bb5Sswilcox 				if (uend + 1 == n) {
456*355d6bb5Sswilcox 					uend = n;
457*355d6bb5Sswilcox 					continue;
458*355d6bb5Sswilcox 				}
459*355d6bb5Sswilcox 				size = uend - ustart + 1;
460*355d6bb5Sswilcox 				if (size <= skip) {
461*355d6bb5Sswilcox 					skip -= size;
462*355d6bb5Sswilcox 					ustart = uend = n;
463*355d6bb5Sswilcox 					continue;
464*355d6bb5Sswilcox 				}
465*355d6bb5Sswilcox 				if (skip > 0) {
466*355d6bb5Sswilcox 					ustart += skip;
467*355d6bb5Sswilcox 					size -= skip;
468*355d6bb5Sswilcox 					skip = 0;
469*355d6bb5Sswilcox 				}
470*355d6bb5Sswilcox 				if (size > limit)
471*355d6bb5Sswilcox 					size = limit;
472*355d6bb5Sswilcox 				if (verbose) {
473*355d6bb5Sswilcox 					if (size == 1)
474*355d6bb5Sswilcox 						pwarn(
475*355d6bb5Sswilcox 			    "UNALLOCATED %s %d WAS MARKED USED ON DISK\n",
476*355d6bb5Sswilcox 						    name, ustart);
477*355d6bb5Sswilcox 					else
478*355d6bb5Sswilcox 						pwarn(
479*355d6bb5Sswilcox 			    "UNALLOCATED %sS %d-%ld WERE MARKED USED ON DISK\n",
480*355d6bb5Sswilcox 						    name, ustart,
481*355d6bb5Sswilcox 						    ustart + size - 1);
482*355d6bb5Sswilcox 				}
483*355d6bb5Sswilcox 				mismatch = 1;
484*355d6bb5Sswilcox 				limit -= size;
485*355d6bb5Sswilcox 				if (limit <= 0)
486*355d6bb5Sswilcox 					return (mismatch);
487*355d6bb5Sswilcox 				ustart = uend = n;
488*355d6bb5Sswilcox 			}
489*355d6bb5Sswilcox 		}
490*355d6bb5Sswilcox 	}
491*355d6bb5Sswilcox 	if (astart != -1) {
492*355d6bb5Sswilcox 		if (verbose) {
493*355d6bb5Sswilcox 			if (astart == aend)
494*355d6bb5Sswilcox 				pwarn(
495*355d6bb5Sswilcox 			    "ALLOCATED %s %d WAS MARKED FREE ON DISK\n",
496*355d6bb5Sswilcox 				    name, astart);
497*355d6bb5Sswilcox 			else
498*355d6bb5Sswilcox 				pwarn(
499*355d6bb5Sswilcox 			    "ALLOCATED %sS %d-%d WERE MARKED FREE ON DISK\n",
500*355d6bb5Sswilcox 				    name, astart, aend);
501*355d6bb5Sswilcox 		}
502*355d6bb5Sswilcox 		mismatch = 1;
503*355d6bb5Sswilcox 	}
504*355d6bb5Sswilcox 	if (ustart != -1) {
505*355d6bb5Sswilcox 		size = uend - ustart + 1;
506*355d6bb5Sswilcox 		if (size <= skip)
507*355d6bb5Sswilcox 			return (mismatch);
508*355d6bb5Sswilcox 		if (skip > 0) {
509*355d6bb5Sswilcox 			ustart += skip;
510*355d6bb5Sswilcox 			size -= skip;
511*355d6bb5Sswilcox 		}
512*355d6bb5Sswilcox 		if (size > limit)
513*355d6bb5Sswilcox 			size = limit;
514*355d6bb5Sswilcox 		if (verbose) {
515*355d6bb5Sswilcox 			if (size == 1)
516*355d6bb5Sswilcox 				pwarn(
517*355d6bb5Sswilcox 			    "UNALLOCATED %s %d WAS MARKED USED ON DISK\n",
518*355d6bb5Sswilcox 				    name, ustart);
519*355d6bb5Sswilcox 			else
520*355d6bb5Sswilcox 				pwarn(
521*355d6bb5Sswilcox 		    "UNALLOCATED %sS %d-%ld WERE MARKED USED ON DISK\n",
522*355d6bb5Sswilcox 				    name, ustart, ustart + size - 1);
523*355d6bb5Sswilcox 		}
524*355d6bb5Sswilcox 		mismatch = 1;
5257c478bd9Sstevel@tonic-gate 	}
526*355d6bb5Sswilcox 	return (mismatch);
5277c478bd9Sstevel@tonic-gate }
528