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