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 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 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