17c478bd9Sstevel@tonic-gate /*
2*aa9740b1SAndrew Balfour * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
37c478bd9Sstevel@tonic-gate */
47c478bd9Sstevel@tonic-gate
57c478bd9Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
67c478bd9Sstevel@tonic-gate /* All Rights Reserved */
77c478bd9Sstevel@tonic-gate
87c478bd9Sstevel@tonic-gate /*
97c478bd9Sstevel@tonic-gate * Copyright (c) 1980, 1986, 1990 The Regents of the University of California.
107c478bd9Sstevel@tonic-gate * All rights reserved.
117c478bd9Sstevel@tonic-gate *
127c478bd9Sstevel@tonic-gate * Redistribution and use in source and binary forms are permitted
137c478bd9Sstevel@tonic-gate * provided that: (1) source distributions retain this entire copyright
147c478bd9Sstevel@tonic-gate * notice and comment, and (2) distributions including binaries display
157c478bd9Sstevel@tonic-gate * the following acknowledgement: ``This product includes software
167c478bd9Sstevel@tonic-gate * developed by the University of California, Berkeley and its contributors''
177c478bd9Sstevel@tonic-gate * in the documentation or other materials provided with the distribution
187c478bd9Sstevel@tonic-gate * and in all advertising materials mentioning features or use of this
197c478bd9Sstevel@tonic-gate * software. Neither the name of the University nor the names of its
207c478bd9Sstevel@tonic-gate * contributors may be used to endorse or promote products derived
217c478bd9Sstevel@tonic-gate * from this software without specific prior written permission.
227c478bd9Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
237c478bd9Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
247c478bd9Sstevel@tonic-gate * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
257c478bd9Sstevel@tonic-gate */
267c478bd9Sstevel@tonic-gate
27355d6bb5Sswilcox #include <stdio.h>
28355d6bb5Sswilcox #include <stdlib.h>
29355d6bb5Sswilcox #include <unistd.h>
30355d6bb5Sswilcox #include <string.h>
317c478bd9Sstevel@tonic-gate #include <sys/param.h>
327c478bd9Sstevel@tonic-gate #include <sys/mntent.h>
337c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_fs.h>
347c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
357c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_inode.h>
367c478bd9Sstevel@tonic-gate #include "fsck.h"
377c478bd9Sstevel@tonic-gate
38355d6bb5Sswilcox static int check_maps(uchar_t *, uchar_t *, int, int, char *, int, int);
39355d6bb5Sswilcox
40355d6bb5Sswilcox void
pass5(void)41355d6bb5Sswilcox pass5(void)
427c478bd9Sstevel@tonic-gate {
43355d6bb5Sswilcox caddr_t err;
44355d6bb5Sswilcox int32_t c, blk, frags;
457c478bd9Sstevel@tonic-gate size_t basesize, sumsize, mapsize;
46355d6bb5Sswilcox int excessdirs;
47355d6bb5Sswilcox int inomapsize, blkmapsize;
4857846e82Svsakar int update_csums, update_bitmaps;
4957846e82Svsakar int bad_csum_sb, bad_csum_cg, bad_cgblks_cg, bad_cgblktot_cg;
507c478bd9Sstevel@tonic-gate struct fs *fs = &sblock;
517c478bd9Sstevel@tonic-gate struct cg *cg = &cgrp;
527c478bd9Sstevel@tonic-gate diskaddr_t dbase, dmax;
537c478bd9Sstevel@tonic-gate diskaddr_t d;
547c478bd9Sstevel@tonic-gate uint64_t i, j;
557c478bd9Sstevel@tonic-gate struct csum *cs;
56355d6bb5Sswilcox struct csum backup_cs;
577c478bd9Sstevel@tonic-gate time_t now;
587c478bd9Sstevel@tonic-gate struct csum cstotal;
597c478bd9Sstevel@tonic-gate struct inodesc idesc;
60355d6bb5Sswilcox union { /* keep lint happy about alignment */
61355d6bb5Sswilcox struct cg cg; /* the rest of buf has the bitmaps */
627c478bd9Sstevel@tonic-gate char buf[MAXBSIZE];
63355d6bb5Sswilcox } u;
64355d6bb5Sswilcox caddr_t buf = u.buf;
65355d6bb5Sswilcox struct cg *newcg = &u.cg;
667c478bd9Sstevel@tonic-gate
67355d6bb5Sswilcox (void) memset((void *)buf, 0, sizeof (u.buf));
687c478bd9Sstevel@tonic-gate newcg->cg_niblk = fs->fs_ipg;
697c478bd9Sstevel@tonic-gate
70355d6bb5Sswilcox if (fs->fs_postblformat != FS_DYNAMICPOSTBLFMT) {
71355d6bb5Sswilcox pfatal("UNSUPPORTED ROTATIONAL TABLE FORMAT %d\n",
72355d6bb5Sswilcox fs->fs_postblformat);
73355d6bb5Sswilcox errexit("Program terminated.");
74355d6bb5Sswilcox /* NOTREACHED */
757c478bd9Sstevel@tonic-gate }
767c478bd9Sstevel@tonic-gate
77355d6bb5Sswilcox /* LINTED this subtraction can't overflow and is int32-aligned */
78355d6bb5Sswilcox basesize = &newcg->cg_space[0] - (uchar_t *)newcg;
79355d6bb5Sswilcox
80355d6bb5Sswilcox /*
81355d6bb5Sswilcox * We reserve the space for the old rotation summary
82355d6bb5Sswilcox * tables for the benefit of old kernels, but do not
83355d6bb5Sswilcox * maintain them in modern kernels. In time, they could
84355d6bb5Sswilcox * theoretically go away, if we wanted to deal with
85355d6bb5Sswilcox * changing the on-disk format.
86355d6bb5Sswilcox */
87355d6bb5Sswilcox
88355d6bb5Sswilcox /*
89355d6bb5Sswilcox * Note that we don't use any of the cg_*() macros until
90355d6bb5Sswilcox * after cg_sanity() has approved of what we've got.
91355d6bb5Sswilcox */
92355d6bb5Sswilcox newcg->cg_btotoff = basesize;
93355d6bb5Sswilcox newcg->cg_boff = newcg->cg_btotoff + fs->fs_cpg * sizeof (daddr32_t);
947c478bd9Sstevel@tonic-gate newcg->cg_iusedoff = newcg->cg_boff +
95355d6bb5Sswilcox fs->fs_cpg * fs->fs_nrpos * sizeof (uint16_t);
96355d6bb5Sswilcox (void) memset(&newcg->cg_space[0], 0, newcg->cg_iusedoff - basesize);
97355d6bb5Sswilcox
98355d6bb5Sswilcox inomapsize = howmany(fs->fs_ipg, NBBY);
99355d6bb5Sswilcox newcg->cg_freeoff = newcg->cg_iusedoff + inomapsize;
100355d6bb5Sswilcox blkmapsize = howmany(fs->fs_fpg, NBBY);
101355d6bb5Sswilcox newcg->cg_nextfreeoff = newcg->cg_freeoff + blkmapsize;
1027c478bd9Sstevel@tonic-gate newcg->cg_magic = CG_MAGIC;
103355d6bb5Sswilcox
1047c478bd9Sstevel@tonic-gate sumsize = newcg->cg_iusedoff - newcg->cg_btotoff;
1057c478bd9Sstevel@tonic-gate mapsize = newcg->cg_nextfreeoff - newcg->cg_iusedoff;
1067c478bd9Sstevel@tonic-gate
107355d6bb5Sswilcox init_inodesc(&idesc);
1087c478bd9Sstevel@tonic-gate idesc.id_type = ADDR;
109355d6bb5Sswilcox (void) memset((void *)&cstotal, 0, sizeof (struct csum));
110355d6bb5Sswilcox now = time(NULL);
1117c478bd9Sstevel@tonic-gate
1127c478bd9Sstevel@tonic-gate /*
1137c478bd9Sstevel@tonic-gate * If the last fragments in the file system don't make up a
1147c478bd9Sstevel@tonic-gate * full file system block, mark the bits in the blockmap
1157c478bd9Sstevel@tonic-gate * that correspond to those missing fragments as "allocated",
1167c478bd9Sstevel@tonic-gate * so that the last block doesn't get counted as a free block
1177c478bd9Sstevel@tonic-gate * and those missing fragments don't get counted as free frags.
1187c478bd9Sstevel@tonic-gate */
1197c478bd9Sstevel@tonic-gate j = blknum(fs, (uint64_t)fs->fs_size + fs->fs_frag - 1);
1207c478bd9Sstevel@tonic-gate for (i = fs->fs_size; i < j; i++)
1217c478bd9Sstevel@tonic-gate setbmap(i);
122355d6bb5Sswilcox
123355d6bb5Sswilcox /*
124355d6bb5Sswilcox * The cg summaries are not always updated when using
125355d6bb5Sswilcox * logging. Since we're really concerned with getting a
126355d6bb5Sswilcox * sane filesystem, rather than in trying to debug UFS
127355d6bb5Sswilcox * corner cases, logically we would just always recompute
128355d6bb5Sswilcox * them. However, it is disconcerting to users to be asked
129355d6bb5Sswilcox * about updating the summaries when, from their point of
130355d6bb5Sswilcox * view, there's been no indication of a problem up to this
131355d6bb5Sswilcox * point. So, only do it if we find a discrepancy.
132355d6bb5Sswilcox */
133355d6bb5Sswilcox update_csums = -1;
134355d6bb5Sswilcox update_bitmaps = 0;
1357c478bd9Sstevel@tonic-gate for (c = 0; c < fs->fs_ncg; c++) {
136355d6bb5Sswilcox backup_cs = cstotal;
137355d6bb5Sswilcox
138355d6bb5Sswilcox /*
139355d6bb5Sswilcox * cg_sanity() will catch i/o errors for us.
140355d6bb5Sswilcox */
141355d6bb5Sswilcox (void) getblk(&cgblk, (diskaddr_t)cgtod(fs, c),
142355d6bb5Sswilcox (size_t)fs->fs_cgsize);
14377a343abSabalfour err = cg_sanity(cg, c);
144355d6bb5Sswilcox if (err != NULL) {
145355d6bb5Sswilcox pfatal("CG %d: %s\n", c, err);
146355d6bb5Sswilcox free((void *)err);
147355d6bb5Sswilcox if (reply("REPAIR") == 0)
148355d6bb5Sswilcox errexit("Program terminated.");
149355d6bb5Sswilcox fix_cg(cg, c);
150355d6bb5Sswilcox }
151355d6bb5Sswilcox /*
152355d6bb5Sswilcox * If the on-disk timestamp is in the future, then it
153355d6bb5Sswilcox * by definition is wrong. Otherwise, if it's in
154355d6bb5Sswilcox * the past, then use that value so that we don't
155355d6bb5Sswilcox * declare a spurious mismatch.
156355d6bb5Sswilcox */
1577c478bd9Sstevel@tonic-gate if (now > cg->cg_time)
1587c478bd9Sstevel@tonic-gate newcg->cg_time = cg->cg_time;
1597c478bd9Sstevel@tonic-gate else
1607c478bd9Sstevel@tonic-gate newcg->cg_time = now;
1617c478bd9Sstevel@tonic-gate newcg->cg_cgx = c;
162355d6bb5Sswilcox dbase = cgbase(fs, c);
163355d6bb5Sswilcox dmax = dbase + fs->fs_fpg;
164355d6bb5Sswilcox if (dmax > fs->fs_size)
165355d6bb5Sswilcox dmax = fs->fs_size;
166355d6bb5Sswilcox newcg->cg_ndblk = dmax - dbase;
1677c478bd9Sstevel@tonic-gate if (c == fs->fs_ncg - 1)
168ef31a55cSvk154806 newcg->cg_ncyl = fs->fs_ncyl - (fs->fs_cpg * c);
1697c478bd9Sstevel@tonic-gate else
1707c478bd9Sstevel@tonic-gate newcg->cg_ncyl = fs->fs_cpg;
1717c478bd9Sstevel@tonic-gate newcg->cg_niblk = sblock.fs_ipg;
1727c478bd9Sstevel@tonic-gate newcg->cg_cs.cs_ndir = 0;
1737c478bd9Sstevel@tonic-gate newcg->cg_cs.cs_nffree = 0;
1747c478bd9Sstevel@tonic-gate newcg->cg_cs.cs_nbfree = 0;
1757c478bd9Sstevel@tonic-gate newcg->cg_cs.cs_nifree = fs->fs_ipg;
1767c478bd9Sstevel@tonic-gate if ((cg->cg_rotor >= 0) && (cg->cg_rotor < newcg->cg_ndblk))
1777c478bd9Sstevel@tonic-gate newcg->cg_rotor = cg->cg_rotor;
1787c478bd9Sstevel@tonic-gate else
1797c478bd9Sstevel@tonic-gate newcg->cg_rotor = 0;
1807c478bd9Sstevel@tonic-gate if ((cg->cg_frotor >= 0) && (cg->cg_frotor < newcg->cg_ndblk))
1817c478bd9Sstevel@tonic-gate newcg->cg_frotor = cg->cg_frotor;
1827c478bd9Sstevel@tonic-gate else
1837c478bd9Sstevel@tonic-gate newcg->cg_frotor = 0;
1847c478bd9Sstevel@tonic-gate if ((cg->cg_irotor >= 0) && (cg->cg_irotor < newcg->cg_niblk))
1857c478bd9Sstevel@tonic-gate newcg->cg_irotor = cg->cg_irotor;
1867c478bd9Sstevel@tonic-gate else
1877c478bd9Sstevel@tonic-gate newcg->cg_irotor = 0;
188355d6bb5Sswilcox (void) memset((void *)&newcg->cg_frsum[0], 0,
189355d6bb5Sswilcox sizeof (newcg->cg_frsum));
190355d6bb5Sswilcox (void) memset((void *)cg_inosused(newcg), 0, (size_t)mapsize);
191355d6bb5Sswilcox /* LINTED macro is int32-aligned per newcg->cg_btotoff above */
192355d6bb5Sswilcox (void) memset((void *)&cg_blktot(newcg)[0], 0,
193355d6bb5Sswilcox sumsize + mapsize);
1947c478bd9Sstevel@tonic-gate j = fs->fs_ipg * c;
1957c478bd9Sstevel@tonic-gate for (i = 0; i < fs->fs_ipg; j++, i++) {
196355d6bb5Sswilcox switch (statemap[j] & ~(INORPHAN | INDELAYD)) {
1977c478bd9Sstevel@tonic-gate
1987c478bd9Sstevel@tonic-gate case USTATE:
1997c478bd9Sstevel@tonic-gate break;
2007c478bd9Sstevel@tonic-gate
2017c478bd9Sstevel@tonic-gate case DSTATE:
2027c478bd9Sstevel@tonic-gate case DCLEAR:
2037c478bd9Sstevel@tonic-gate case DFOUND:
204355d6bb5Sswilcox case DZLINK:
2057c478bd9Sstevel@tonic-gate newcg->cg_cs.cs_ndir++;
206355d6bb5Sswilcox /* FALLTHROUGH */
2077c478bd9Sstevel@tonic-gate
2087c478bd9Sstevel@tonic-gate case FSTATE:
2097c478bd9Sstevel@tonic-gate case FCLEAR:
210355d6bb5Sswilcox case FZLINK:
2117c478bd9Sstevel@tonic-gate case SSTATE:
2127c478bd9Sstevel@tonic-gate case SCLEAR:
2137c478bd9Sstevel@tonic-gate newcg->cg_cs.cs_nifree--;
2147c478bd9Sstevel@tonic-gate setbit(cg_inosused(newcg), i);
2157c478bd9Sstevel@tonic-gate break;
2167c478bd9Sstevel@tonic-gate
2177c478bd9Sstevel@tonic-gate default:
2187c478bd9Sstevel@tonic-gate if (j < UFSROOTINO)
2197c478bd9Sstevel@tonic-gate break;
220355d6bb5Sswilcox errexit("BAD STATE 0x%x FOR INODE I=%d",
221355d6bb5Sswilcox statemap[j], (int)j);
2227c478bd9Sstevel@tonic-gate }
2237c478bd9Sstevel@tonic-gate }
224355d6bb5Sswilcox if (c == 0) {
2257c478bd9Sstevel@tonic-gate for (i = 0; i < UFSROOTINO; i++) {
2267c478bd9Sstevel@tonic-gate setbit(cg_inosused(newcg), i);
2277c478bd9Sstevel@tonic-gate newcg->cg_cs.cs_nifree--;
2287c478bd9Sstevel@tonic-gate }
229355d6bb5Sswilcox }
230355d6bb5Sswilcox /*
231355d6bb5Sswilcox * Count up what fragments and blocks are free, and
232355d6bb5Sswilcox * reflect the relevant section of blockmap[] into
233355d6bb5Sswilcox * newcg's map.
234355d6bb5Sswilcox */
2357c478bd9Sstevel@tonic-gate for (i = 0, d = dbase;
2367c478bd9Sstevel@tonic-gate d < dmax;
2377c478bd9Sstevel@tonic-gate d += fs->fs_frag, i += fs->fs_frag) {
2387c478bd9Sstevel@tonic-gate frags = 0;
2397c478bd9Sstevel@tonic-gate for (j = 0; j < fs->fs_frag; j++) {
2407c478bd9Sstevel@tonic-gate if (testbmap(d + j))
2417c478bd9Sstevel@tonic-gate continue;
2427c478bd9Sstevel@tonic-gate setbit(cg_blksfree(newcg), i + j);
2437c478bd9Sstevel@tonic-gate frags++;
2447c478bd9Sstevel@tonic-gate }
2457c478bd9Sstevel@tonic-gate if (frags == fs->fs_frag) {
2467c478bd9Sstevel@tonic-gate newcg->cg_cs.cs_nbfree++;
2477c478bd9Sstevel@tonic-gate j = cbtocylno(fs, i);
248355d6bb5Sswilcox /* LINTED macro is int32-aligned per above */
2497c478bd9Sstevel@tonic-gate cg_blktot(newcg)[j]++;
250355d6bb5Sswilcox /* LINTED cg_blks(newcg) is aligned */
2517c478bd9Sstevel@tonic-gate cg_blks(fs, newcg, j)[cbtorpos(fs, i)]++;
2527c478bd9Sstevel@tonic-gate } else if (frags > 0) {
2537c478bd9Sstevel@tonic-gate newcg->cg_cs.cs_nffree += frags;
2547c478bd9Sstevel@tonic-gate blk = blkmap(fs, cg_blksfree(newcg), i);
2557c478bd9Sstevel@tonic-gate fragacct(fs, blk, newcg->cg_frsum, 1);
2567c478bd9Sstevel@tonic-gate }
2577c478bd9Sstevel@tonic-gate }
2587c478bd9Sstevel@tonic-gate cstotal.cs_nffree += newcg->cg_cs.cs_nffree;
2597c478bd9Sstevel@tonic-gate cstotal.cs_nbfree += newcg->cg_cs.cs_nbfree;
2607c478bd9Sstevel@tonic-gate cstotal.cs_nifree += newcg->cg_cs.cs_nifree;
2617c478bd9Sstevel@tonic-gate cstotal.cs_ndir += newcg->cg_cs.cs_ndir;
2627c478bd9Sstevel@tonic-gate
2637c478bd9Sstevel@tonic-gate /*
264355d6bb5Sswilcox * Note that, just like the kernel, we dynamically
265355d6bb5Sswilcox * allocated an array to hold the csums and stuffed
266355d6bb5Sswilcox * the pointer into the in-core superblock's fs_u.fs_csp
267355d6bb5Sswilcox * field. This means that the fs_u field contains a
268355d6bb5Sswilcox * random value when the disk version is examined, but
269355d6bb5Sswilcox * fs_cs() gives us a valid pointer nonetheless.
27077a343abSabalfour * We need to compare the recalculated summaries to
27177a343abSabalfour * both the superblock version and the on disk version.
27277a343abSabalfour * If either is bad, copy the calculated version over
27377a343abSabalfour * the corrupt values.
2747c478bd9Sstevel@tonic-gate */
27577a343abSabalfour
276355d6bb5Sswilcox cs = &fs->fs_cs(fs, c);
27777a343abSabalfour bad_csum_sb = (memcmp((void *)cs, (void *)&newcg->cg_cs,
278355d6bb5Sswilcox sizeof (*cs)) != 0);
279355d6bb5Sswilcox
28077a343abSabalfour bad_csum_cg = (memcmp((void *)&cg->cg_cs, (void *)&newcg->cg_cs,
28177a343abSabalfour sizeof (struct csum)) != 0);
28277a343abSabalfour
283355d6bb5Sswilcox /*
284355d6bb5Sswilcox * Has the user told us what to do yet? If not, find out.
285355d6bb5Sswilcox */
28677a343abSabalfour if ((bad_csum_sb || bad_csum_cg) && (update_csums == -1)) {
287355d6bb5Sswilcox if (preen) {
288355d6bb5Sswilcox update_csums = 1;
28977a343abSabalfour (void) printf("CORRECTING BAD CG SUMMARIES"
29077a343abSabalfour " FOR CG %d\n", c);
291355d6bb5Sswilcox } else if (update_csums == -1) {
292355d6bb5Sswilcox update_csums = (reply(
29377a343abSabalfour "CORRECT BAD CG SUMMARIES FOR CG %d",
29477a343abSabalfour c) == 1);
295355d6bb5Sswilcox }
2967c478bd9Sstevel@tonic-gate }
2977c478bd9Sstevel@tonic-gate
29877a343abSabalfour if (bad_csum_sb && (update_csums == 1)) {
299355d6bb5Sswilcox (void) memmove((void *)cs, (void *)&newcg->cg_cs,
300355d6bb5Sswilcox sizeof (*cs));
301355d6bb5Sswilcox sbdirty();
30277a343abSabalfour (void) printf("CORRECTED SUPERBLOCK SUMMARIES FOR"
30377a343abSabalfour " CG %d\n", c);
30477a343abSabalfour }
305355d6bb5Sswilcox
30677a343abSabalfour if (bad_csum_cg && (update_csums == 1)) {
30770e93bccSabalfour (void) memmove((void *)cg, (void *)newcg,
30870e93bccSabalfour (size_t)basesize);
309355d6bb5Sswilcox /* LINTED per cg_sanity() */
310355d6bb5Sswilcox (void) memmove((void *)&cg_blktot(cg)[0],
311355d6bb5Sswilcox /* LINTED macro aligned as above */
312355d6bb5Sswilcox (void *)&cg_blktot(newcg)[0], sumsize);
313355d6bb5Sswilcox cgdirty();
31477a343abSabalfour (void) printf("CORRECTED SUMMARIES FOR CG %d\n", c);
3157c478bd9Sstevel@tonic-gate }
316355d6bb5Sswilcox
317355d6bb5Sswilcox excessdirs = cg->cg_cs.cs_ndir - newcg->cg_cs.cs_ndir;
318355d6bb5Sswilcox if (excessdirs < 0) {
319355d6bb5Sswilcox pfatal("LOST %d DIRECTORIES IN CG %d\n",
320355d6bb5Sswilcox -excessdirs, c);
321355d6bb5Sswilcox excessdirs = 0;
3227c478bd9Sstevel@tonic-gate }
323355d6bb5Sswilcox if (excessdirs > 0) {
324355d6bb5Sswilcox if (check_maps((uchar_t *)cg_inosused(newcg),
325355d6bb5Sswilcox (uchar_t *)cg_inosused(cg), inomapsize,
326355d6bb5Sswilcox cg->cg_cgx * fs->fs_ipg, "DIR", 0, excessdirs)) {
327355d6bb5Sswilcox if (!verbose)
328355d6bb5Sswilcox (void) printf("DIR BITMAP WRONG ");
329355d6bb5Sswilcox if (preen || update_bitmaps ||
330355d6bb5Sswilcox reply("FIX") == 1) {
331355d6bb5Sswilcox (void) memmove((void *)cg_inosused(cg),
332355d6bb5Sswilcox (void *)cg_inosused(newcg),
333355d6bb5Sswilcox inomapsize);
334355d6bb5Sswilcox cgdirty();
335355d6bb5Sswilcox if (preen ||
336355d6bb5Sswilcox (!verbose && update_bitmaps))
337355d6bb5Sswilcox (void) printf("(CORRECTED)\n");
338355d6bb5Sswilcox update_bitmaps = 1;
339355d6bb5Sswilcox }
340355d6bb5Sswilcox }
341355d6bb5Sswilcox }
342355d6bb5Sswilcox
343355d6bb5Sswilcox if (check_maps((uchar_t *)cg_inosused(newcg),
344355d6bb5Sswilcox (uchar_t *)cg_inosused(cg), inomapsize,
345355d6bb5Sswilcox cg->cg_cgx * fs->fs_ipg, "FILE", excessdirs, fs->fs_ipg)) {
346355d6bb5Sswilcox if (!verbose)
347355d6bb5Sswilcox (void) printf("FILE BITMAP WRONG ");
348355d6bb5Sswilcox if (preen || update_bitmaps || reply("FIX") == 1) {
349355d6bb5Sswilcox (void) memmove((void *)cg_inosused(cg),
350355d6bb5Sswilcox (void *)cg_inosused(newcg), inomapsize);
351355d6bb5Sswilcox cgdirty();
352355d6bb5Sswilcox if (preen ||
353355d6bb5Sswilcox (!verbose && update_bitmaps))
354355d6bb5Sswilcox (void) printf("(CORRECTED)\n");
355355d6bb5Sswilcox update_bitmaps = 1;
356355d6bb5Sswilcox }
357355d6bb5Sswilcox }
358355d6bb5Sswilcox
359355d6bb5Sswilcox if (check_maps((uchar_t *)cg_blksfree(cg),
360355d6bb5Sswilcox (uchar_t *)cg_blksfree(newcg), blkmapsize,
361355d6bb5Sswilcox cg->cg_cgx * fs->fs_fpg, "FRAG", 0, fs->fs_fpg)) {
362355d6bb5Sswilcox if (!verbose)
363355d6bb5Sswilcox (void) printf("FRAG BITMAP WRONG ");
364355d6bb5Sswilcox if (preen || update_bitmaps || reply("FIX") == 1) {
365355d6bb5Sswilcox (void) memmove((void *)cg_blksfree(cg),
366355d6bb5Sswilcox (void *)cg_blksfree(newcg), blkmapsize);
367355d6bb5Sswilcox cgdirty();
368355d6bb5Sswilcox if (preen ||
369355d6bb5Sswilcox (!verbose && update_bitmaps))
370355d6bb5Sswilcox (void) printf("(CORRECTED)\n");
371355d6bb5Sswilcox update_bitmaps = 1;
372355d6bb5Sswilcox }
373355d6bb5Sswilcox }
374355d6bb5Sswilcox
37557846e82Svsakar bad_cgblks_cg = (memcmp((void *)&cg_blks(fs, cg, 0)[0],
37657846e82Svsakar (void *)&cg_blks(fs, newcg, 0)[0],
377*aa9740b1SAndrew Balfour fs->fs_cpg * fs->fs_nrpos * sizeof (int16_t)) != 0);
37857846e82Svsakar
37957846e82Svsakar if (bad_cgblks_cg) {
38057846e82Svsakar if (!verbose)
38157846e82Svsakar (void) printf("ROTATIONAL POSITIONS "
38257846e82Svsakar "BLOCK COUNT WRONG ");
38357846e82Svsakar if (preen || update_bitmaps || reply("FIX") == 1) {
38457846e82Svsakar (void) memmove((void *)&cg_blks(fs, cg, 0)[0],
38557846e82Svsakar (void *)&cg_blks(fs, newcg, 0)[0],
38657846e82Svsakar fs->fs_cpg * fs->fs_nrpos *
387*aa9740b1SAndrew Balfour sizeof (int16_t));
38857846e82Svsakar cgdirty();
38957846e82Svsakar if (preen ||
39057846e82Svsakar (!verbose && update_bitmaps))
39157846e82Svsakar (void) printf("(CORRECTED)\n");
39257846e82Svsakar update_bitmaps = 1;
39357846e82Svsakar }
39457846e82Svsakar }
39557846e82Svsakar
39657846e82Svsakar bad_cgblktot_cg = (memcmp((void *)&cg_blktot(cg)[0],
39757846e82Svsakar (void *)&cg_blktot(newcg)[0],
39857846e82Svsakar fs->fs_cpg * sizeof (int32_t)) != 0);
39957846e82Svsakar
40057846e82Svsakar if (bad_cgblktot_cg) {
40157846e82Svsakar if (!verbose)
40257846e82Svsakar (void) printf("ROTATIONAL POSITIONS "
40357846e82Svsakar "BLOCK TOTAL WRONG ");
40457846e82Svsakar if (preen || update_bitmaps || reply("FIX") == 1) {
40557846e82Svsakar (void) memmove((void *)&cg_blktot(cg)[0],
40657846e82Svsakar (void *)&cg_blktot(newcg)[0],
40757846e82Svsakar fs->fs_cpg * sizeof (int32_t));
40857846e82Svsakar cgdirty();
40957846e82Svsakar if (preen ||
41057846e82Svsakar (!verbose && update_bitmaps))
41157846e82Svsakar (void) printf("(CORRECTED)\n");
41257846e82Svsakar update_bitmaps = 1;
41357846e82Svsakar }
41457846e82Svsakar }
41557846e82Svsakar
416355d6bb5Sswilcox /*
417355d6bb5Sswilcox * Fixing one set of problems often shows up more in the
418355d6bb5Sswilcox * same cg. Just to make sure, go back and check it
419355d6bb5Sswilcox * again if we found something this time through.
420355d6bb5Sswilcox */
421355d6bb5Sswilcox if (cgisdirty()) {
422355d6bb5Sswilcox cgflush();
423355d6bb5Sswilcox cstotal = backup_cs;
424355d6bb5Sswilcox c--;
425355d6bb5Sswilcox }
426355d6bb5Sswilcox }
427355d6bb5Sswilcox
4287c478bd9Sstevel@tonic-gate if ((fflag || !(islog && islogok)) &&
429355d6bb5Sswilcox (memcmp((void *)&cstotal, (void *)&fs->fs_cstotal,
430355d6bb5Sswilcox sizeof (struct csum)) != 0)) {
431355d6bb5Sswilcox if (dofix(&idesc, "CORRECT GLOBAL SUMMARY")) {
432355d6bb5Sswilcox (void) memmove((void *)&fs->fs_cstotal,
433355d6bb5Sswilcox (void *)&cstotal, sizeof (struct csum));
4347c478bd9Sstevel@tonic-gate fs->fs_ronly = 0;
4357c478bd9Sstevel@tonic-gate fs->fs_fmod = 0;
4367c478bd9Sstevel@tonic-gate sbdirty();
437355d6bb5Sswilcox } else {
438355d6bb5Sswilcox iscorrupt = 1;
4397c478bd9Sstevel@tonic-gate }
4407c478bd9Sstevel@tonic-gate }
441355d6bb5Sswilcox }
442355d6bb5Sswilcox
443355d6bb5Sswilcox /*
444355d6bb5Sswilcox * Compare two allocation bitmaps, reporting any discrepancies.
445355d6bb5Sswilcox *
446355d6bb5Sswilcox * If a mismatch is found, if the bit is set in map1, it's considered
447355d6bb5Sswilcox * to be an indication that the corresponding resource is supposed
448355d6bb5Sswilcox * to be free, but isn't. Otherwise, it's considered marked as allocated
449355d6bb5Sswilcox * but not found to be so. In other words, if the two maps being compared
450355d6bb5Sswilcox * use a set bit to indicate something is free, pass the on-disk map
451355d6bb5Sswilcox * first. Otherwise, pass the calculated map first.
452355d6bb5Sswilcox */
453355d6bb5Sswilcox static int
check_maps(uchar_t * map1,uchar_t * map2,int mapsize,int startvalue,char * name,int skip,int limit)454355d6bb5Sswilcox check_maps(
455355d6bb5Sswilcox uchar_t *map1, /* map of claimed allocations */
456355d6bb5Sswilcox uchar_t *map2, /* map of determined allocations */
457355d6bb5Sswilcox int mapsize, /* size of above two maps */
458355d6bb5Sswilcox int startvalue, /* resource value for first element in map */
459355d6bb5Sswilcox char *name, /* name of resource found in maps */
460355d6bb5Sswilcox int skip, /* number of entries to skip before starting to free */
461355d6bb5Sswilcox int limit) /* limit on number of entries to free */
462355d6bb5Sswilcox {
463355d6bb5Sswilcox long i, j, k, l, m, n, size;
464355d6bb5Sswilcox int astart, aend, ustart, uend;
465355d6bb5Sswilcox int mismatch;
466355d6bb5Sswilcox
467355d6bb5Sswilcox mismatch = 0;
468355d6bb5Sswilcox astart = ustart = aend = uend = -1;
469355d6bb5Sswilcox for (i = 0; i < mapsize; i++) {
470355d6bb5Sswilcox j = *map1++;
471355d6bb5Sswilcox k = *map2++;
472355d6bb5Sswilcox if (j == k)
473355d6bb5Sswilcox continue;
474355d6bb5Sswilcox for (m = 0, l = 1; m < NBBY; m++, l <<= 1) {
475355d6bb5Sswilcox if ((j & l) == (k & l))
476355d6bb5Sswilcox continue;
477355d6bb5Sswilcox n = startvalue + i * NBBY + m;
478355d6bb5Sswilcox if ((j & l) != 0) {
479355d6bb5Sswilcox if (astart == -1) {
480355d6bb5Sswilcox astart = aend = n;
481355d6bb5Sswilcox continue;
482355d6bb5Sswilcox }
483355d6bb5Sswilcox if (aend + 1 == n) {
484355d6bb5Sswilcox aend = n;
485355d6bb5Sswilcox continue;
486355d6bb5Sswilcox }
487355d6bb5Sswilcox if (verbose) {
488355d6bb5Sswilcox if (astart == aend)
489355d6bb5Sswilcox pwarn(
490355d6bb5Sswilcox "ALLOCATED %s %d WAS MARKED FREE ON DISK\n",
491355d6bb5Sswilcox name, astart);
492355d6bb5Sswilcox else
493355d6bb5Sswilcox pwarn(
494355d6bb5Sswilcox "ALLOCATED %sS %d-%d WERE MARKED FREE ON DISK\n",
495355d6bb5Sswilcox name, astart, aend);
496355d6bb5Sswilcox }
497355d6bb5Sswilcox mismatch = 1;
498355d6bb5Sswilcox astart = aend = n;
499355d6bb5Sswilcox } else {
500355d6bb5Sswilcox if (ustart == -1) {
501355d6bb5Sswilcox ustart = uend = n;
502355d6bb5Sswilcox continue;
503355d6bb5Sswilcox }
504355d6bb5Sswilcox if (uend + 1 == n) {
505355d6bb5Sswilcox uend = n;
506355d6bb5Sswilcox continue;
507355d6bb5Sswilcox }
508355d6bb5Sswilcox size = uend - ustart + 1;
509355d6bb5Sswilcox if (size <= skip) {
510355d6bb5Sswilcox skip -= size;
511355d6bb5Sswilcox ustart = uend = n;
512355d6bb5Sswilcox continue;
513355d6bb5Sswilcox }
514355d6bb5Sswilcox if (skip > 0) {
515355d6bb5Sswilcox ustart += skip;
516355d6bb5Sswilcox size -= skip;
517355d6bb5Sswilcox skip = 0;
518355d6bb5Sswilcox }
519355d6bb5Sswilcox if (size > limit)
520355d6bb5Sswilcox size = limit;
521355d6bb5Sswilcox if (verbose) {
522355d6bb5Sswilcox if (size == 1)
523355d6bb5Sswilcox pwarn(
524355d6bb5Sswilcox "UNALLOCATED %s %d WAS MARKED USED ON DISK\n",
525355d6bb5Sswilcox name, ustart);
526355d6bb5Sswilcox else
527355d6bb5Sswilcox pwarn(
528355d6bb5Sswilcox "UNALLOCATED %sS %d-%ld WERE MARKED USED ON DISK\n",
529355d6bb5Sswilcox name, ustart,
530355d6bb5Sswilcox ustart + size - 1);
531355d6bb5Sswilcox }
532355d6bb5Sswilcox mismatch = 1;
533355d6bb5Sswilcox limit -= size;
534355d6bb5Sswilcox if (limit <= 0)
535355d6bb5Sswilcox return (mismatch);
536355d6bb5Sswilcox ustart = uend = n;
537355d6bb5Sswilcox }
538355d6bb5Sswilcox }
539355d6bb5Sswilcox }
540355d6bb5Sswilcox if (astart != -1) {
541355d6bb5Sswilcox if (verbose) {
542355d6bb5Sswilcox if (astart == aend)
543355d6bb5Sswilcox pwarn(
544355d6bb5Sswilcox "ALLOCATED %s %d WAS MARKED FREE ON DISK\n",
545355d6bb5Sswilcox name, astart);
546355d6bb5Sswilcox else
547355d6bb5Sswilcox pwarn(
548355d6bb5Sswilcox "ALLOCATED %sS %d-%d WERE MARKED FREE ON DISK\n",
549355d6bb5Sswilcox name, astart, aend);
550355d6bb5Sswilcox }
551355d6bb5Sswilcox mismatch = 1;
552355d6bb5Sswilcox }
553355d6bb5Sswilcox if (ustart != -1) {
554355d6bb5Sswilcox size = uend - ustart + 1;
555355d6bb5Sswilcox if (size <= skip)
556355d6bb5Sswilcox return (mismatch);
557355d6bb5Sswilcox if (skip > 0) {
558355d6bb5Sswilcox ustart += skip;
559355d6bb5Sswilcox size -= skip;
560355d6bb5Sswilcox }
561355d6bb5Sswilcox if (size > limit)
562355d6bb5Sswilcox size = limit;
563355d6bb5Sswilcox if (verbose) {
564355d6bb5Sswilcox if (size == 1)
565355d6bb5Sswilcox pwarn(
566355d6bb5Sswilcox "UNALLOCATED %s %d WAS MARKED USED ON DISK\n",
567355d6bb5Sswilcox name, ustart);
568355d6bb5Sswilcox else
569355d6bb5Sswilcox pwarn(
570355d6bb5Sswilcox "UNALLOCATED %sS %d-%ld WERE MARKED USED ON DISK\n",
571355d6bb5Sswilcox name, ustart, ustart + size - 1);
572355d6bb5Sswilcox }
573355d6bb5Sswilcox mismatch = 1;
574355d6bb5Sswilcox }
575355d6bb5Sswilcox return (mismatch);
576355d6bb5Sswilcox }
577