10Sstevel@tonic-gate /* 2*2249Sns158690 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 30Sstevel@tonic-gate * Use is subject to license terms. 40Sstevel@tonic-gate */ 50Sstevel@tonic-gate 60Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 70Sstevel@tonic-gate /* All Rights Reserved */ 80Sstevel@tonic-gate 90Sstevel@tonic-gate /* 100Sstevel@tonic-gate * Copyright (c) 1980 Regents of the University of California. 110Sstevel@tonic-gate * All rights reserved. The Berkeley software License Agreement 120Sstevel@tonic-gate * specifies the terms and conditions for redistribution. 130Sstevel@tonic-gate */ 140Sstevel@tonic-gate 150Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 160Sstevel@tonic-gate 170Sstevel@tonic-gate #include "dump.h" 180Sstevel@tonic-gate #include <sys/file.h> 190Sstevel@tonic-gate #include <sys/mman.h> 200Sstevel@tonic-gate 210Sstevel@tonic-gate #ifdef __STDC__ 220Sstevel@tonic-gate static void lf_dmpindir(daddr32_t, int, u_offset_t *); 230Sstevel@tonic-gate static void indir(daddr32_t, int, u_offset_t *); 240Sstevel@tonic-gate static void lf_blksout(daddr32_t *, u_offset_t); 250Sstevel@tonic-gate static void lf_dumpinode(struct dinode *); 260Sstevel@tonic-gate static void dsrch(daddr32_t, ulong_t, u_offset_t); 270Sstevel@tonic-gate void lf_dump(struct dinode *); 280Sstevel@tonic-gate #else 290Sstevel@tonic-gate static void lf_dmpindir(); 300Sstevel@tonic-gate static void indir(); 310Sstevel@tonic-gate static void lf_blksout(); 320Sstevel@tonic-gate static void dsrch(); 330Sstevel@tonic-gate void lf_dump(); 340Sstevel@tonic-gate #endif 350Sstevel@tonic-gate 360Sstevel@tonic-gate static char msgbuf[256]; 370Sstevel@tonic-gate 380Sstevel@tonic-gate void 390Sstevel@tonic-gate pass(fn, map) 400Sstevel@tonic-gate void (*fn)(struct dinode *); 410Sstevel@tonic-gate uchar_t *map; 420Sstevel@tonic-gate { 430Sstevel@tonic-gate int bits; 440Sstevel@tonic-gate ino_t maxino; 450Sstevel@tonic-gate 460Sstevel@tonic-gate maxino = (unsigned)(sblock->fs_ipg * sblock->fs_ncg - 1); 470Sstevel@tonic-gate /* 480Sstevel@tonic-gate * Handle pass restarts. We don't check for UFSROOTINO just in 490Sstevel@tonic-gate * case we need to restart on the root inode. 500Sstevel@tonic-gate */ 510Sstevel@tonic-gate if (ino != 0) { 520Sstevel@tonic-gate bits = ~0; 530Sstevel@tonic-gate if (map != NULL) { 540Sstevel@tonic-gate /* LINTED: lint seems to think map is signed */ 550Sstevel@tonic-gate map += (ino / NBBY); 560Sstevel@tonic-gate bits = *map++; 570Sstevel@tonic-gate } 580Sstevel@tonic-gate bits >>= (ino % NBBY); 590Sstevel@tonic-gate resetino(ino); 600Sstevel@tonic-gate goto restart; 610Sstevel@tonic-gate } 620Sstevel@tonic-gate while (ino < maxino) { 630Sstevel@tonic-gate if ((ino % NBBY) == 0) { 640Sstevel@tonic-gate bits = ~0; 650Sstevel@tonic-gate if (map != NULL) 660Sstevel@tonic-gate bits = *map++; 670Sstevel@tonic-gate } 680Sstevel@tonic-gate restart: 690Sstevel@tonic-gate ino++; 700Sstevel@tonic-gate /* 710Sstevel@tonic-gate * Ignore any inode less than UFSROOTINO and inodes that 720Sstevel@tonic-gate * we have already done on a previous pass. 730Sstevel@tonic-gate */ 740Sstevel@tonic-gate if ((ino >= UFSROOTINO) && (bits & 1)) { 750Sstevel@tonic-gate /* 760Sstevel@tonic-gate * The following test is merely an optimization 770Sstevel@tonic-gate * for common case where "add" will just return. 780Sstevel@tonic-gate */ 790Sstevel@tonic-gate if (!(fn == add && BIT(ino, nodmap))) 800Sstevel@tonic-gate (*fn)(getino(ino)); 810Sstevel@tonic-gate } 820Sstevel@tonic-gate bits >>= 1; 830Sstevel@tonic-gate } 840Sstevel@tonic-gate } 850Sstevel@tonic-gate 860Sstevel@tonic-gate void 870Sstevel@tonic-gate mark(ip) 880Sstevel@tonic-gate struct dinode *ip; 890Sstevel@tonic-gate { 900Sstevel@tonic-gate int f; 910Sstevel@tonic-gate 920Sstevel@tonic-gate f = ip->di_mode & IFMT; 930Sstevel@tonic-gate if (f == 0 || ip->di_nlink <= 0) { 940Sstevel@tonic-gate /* LINTED: 32-bit to 8-bit assignment ok */ 950Sstevel@tonic-gate BIC(ino, clrmap); 960Sstevel@tonic-gate return; 970Sstevel@tonic-gate } 980Sstevel@tonic-gate /* LINTED: 32-bit to 8-bit assignment ok */ 990Sstevel@tonic-gate BIS(ino, clrmap); 1000Sstevel@tonic-gate if (f == IFDIR || f == IFATTRDIR) { 1010Sstevel@tonic-gate /* LINTED: 32-bit to 8-bit assignment ok */ 1020Sstevel@tonic-gate BIS(ino, dirmap); 1030Sstevel@tonic-gate } 1040Sstevel@tonic-gate if (ip->di_ctime >= spcl.c_ddate) { 1050Sstevel@tonic-gate if (f == IFSHAD) 1060Sstevel@tonic-gate return; 1070Sstevel@tonic-gate /* LINTED: 32-bit to 8-bit assignment ok */ 1080Sstevel@tonic-gate BIS(ino, nodmap); 1090Sstevel@tonic-gate /* attribute changes impact the root */ 1100Sstevel@tonic-gate if (f == IFATTRDIR) 1110Sstevel@tonic-gate BIS(UFSROOTINO, nodmap); 1120Sstevel@tonic-gate if (f != IFREG && f != IFDIR && f != IFATTRDIR && f != IFLNK) { 1130Sstevel@tonic-gate o_esize += 1; 1140Sstevel@tonic-gate return; 1150Sstevel@tonic-gate } 1160Sstevel@tonic-gate est(ip); 1170Sstevel@tonic-gate } 1180Sstevel@tonic-gate } 1190Sstevel@tonic-gate 1200Sstevel@tonic-gate void 1210Sstevel@tonic-gate active_mark(ip) 1220Sstevel@tonic-gate struct dinode *ip; 1230Sstevel@tonic-gate { 1240Sstevel@tonic-gate int f; 1250Sstevel@tonic-gate 1260Sstevel@tonic-gate f = ip->di_mode & IFMT; 1270Sstevel@tonic-gate if (f == 0 || ip->di_nlink <= 0) { 1280Sstevel@tonic-gate /* LINTED: 32-bit to 8-bit assignment ok */ 1290Sstevel@tonic-gate BIC(ino, clrmap); 1300Sstevel@tonic-gate return; 1310Sstevel@tonic-gate } 1320Sstevel@tonic-gate /* LINTED: 32-bit to 8-bit assignment ok */ 1330Sstevel@tonic-gate BIS(ino, clrmap); 1340Sstevel@tonic-gate if (f == IFDIR || f == IFATTRDIR) { 1350Sstevel@tonic-gate /* LINTED: 32-bit to 8-bit assignment ok */ 1360Sstevel@tonic-gate BIS(ino, dirmap); 1370Sstevel@tonic-gate } 1380Sstevel@tonic-gate if (BIT(ino, activemap)) { 1390Sstevel@tonic-gate /* LINTED: 32-bit to 8-bit assignment ok */ 1400Sstevel@tonic-gate BIS(ino, nodmap); 1410Sstevel@tonic-gate /* attribute changes impact the root */ 1420Sstevel@tonic-gate if (f == IFATTRDIR) 1430Sstevel@tonic-gate BIS(UFSROOTINO, nodmap); 1440Sstevel@tonic-gate if (f != IFREG && f != IFDIR && f != IFATTRDIR && f != IFLNK) { 1450Sstevel@tonic-gate o_esize += 1; 1460Sstevel@tonic-gate return; 1470Sstevel@tonic-gate } 1480Sstevel@tonic-gate est(ip); 1490Sstevel@tonic-gate } 1500Sstevel@tonic-gate } 1510Sstevel@tonic-gate 1520Sstevel@tonic-gate static struct shcount { 1530Sstevel@tonic-gate struct shcount *higher, *lower; 1540Sstevel@tonic-gate ino_t ino; 1550Sstevel@tonic-gate unsigned long count; 1560Sstevel@tonic-gate } shcounts = { 1570Sstevel@tonic-gate NULL, NULL, 1580Sstevel@tonic-gate 0, 1590Sstevel@tonic-gate 0 1600Sstevel@tonic-gate }; 1610Sstevel@tonic-gate static struct shcount *shc = NULL; 1620Sstevel@tonic-gate 1630Sstevel@tonic-gate void 1640Sstevel@tonic-gate markshad(ip) 1650Sstevel@tonic-gate struct dinode *ip; 1660Sstevel@tonic-gate { 1670Sstevel@tonic-gate ino_t shadow; 1680Sstevel@tonic-gate 1690Sstevel@tonic-gate if (ip->di_shadow == 0) 1700Sstevel@tonic-gate return; 1710Sstevel@tonic-gate if (shc == NULL) 1720Sstevel@tonic-gate shc = &shcounts; 1730Sstevel@tonic-gate 1740Sstevel@tonic-gate shadow = (ino_t)(unsigned)(ip->di_shadow); 1750Sstevel@tonic-gate while ((shadow > shc->ino) && (shc->higher)) 1760Sstevel@tonic-gate shc = shc->higher; 1770Sstevel@tonic-gate while ((shadow < shc->ino) && (shc->lower)) 1780Sstevel@tonic-gate shc = shc->lower; 1790Sstevel@tonic-gate if (shadow != shc->ino) { 1800Sstevel@tonic-gate struct shcount *new; 1810Sstevel@tonic-gate 1820Sstevel@tonic-gate new = (struct shcount *)xcalloc(1, sizeof (*new)); 1830Sstevel@tonic-gate new->higher = shc->higher; 1840Sstevel@tonic-gate if (shc->higher != NULL) 1850Sstevel@tonic-gate shc->higher->lower = new; 1860Sstevel@tonic-gate shc->higher = new; 1870Sstevel@tonic-gate new->lower = shc; 1880Sstevel@tonic-gate shc = new; 1890Sstevel@tonic-gate shc->ino = shadow; 1900Sstevel@tonic-gate } 1910Sstevel@tonic-gate 1920Sstevel@tonic-gate /* LINTED: 32-bit to 8-bit assignment ok */ 1930Sstevel@tonic-gate BIS(shadow, shamap); 1940Sstevel@tonic-gate shc->count++; 1950Sstevel@tonic-gate } 1960Sstevel@tonic-gate 1970Sstevel@tonic-gate void 1980Sstevel@tonic-gate estshad(ip) 1990Sstevel@tonic-gate struct dinode *ip; 2000Sstevel@tonic-gate { 2010Sstevel@tonic-gate u_offset_t esizeprime; 2020Sstevel@tonic-gate u_offset_t tmpesize; 2030Sstevel@tonic-gate 2040Sstevel@tonic-gate if (ip->di_size <= sizeof (union u_shadow)) 2050Sstevel@tonic-gate return; 2060Sstevel@tonic-gate 2070Sstevel@tonic-gate while ((ino > shc->ino) && (shc->higher)) 2080Sstevel@tonic-gate shc = shc->higher; 2090Sstevel@tonic-gate while ((ino < shc->ino) && (shc->lower)) 2100Sstevel@tonic-gate shc = shc->lower; 2110Sstevel@tonic-gate if (ino != shc->ino) 2120Sstevel@tonic-gate return; /* xxx panic? complain? */ 2130Sstevel@tonic-gate 2140Sstevel@tonic-gate tmpesize = (o_esize + f_esize); 2150Sstevel@tonic-gate esizeprime = tmpesize; 2160Sstevel@tonic-gate est(ip); 2170Sstevel@tonic-gate esizeprime = tmpesize - esizeprime; 2180Sstevel@tonic-gate esizeprime *= shc->count - 1; 2190Sstevel@tonic-gate f_esize += esizeprime; 2200Sstevel@tonic-gate } 2210Sstevel@tonic-gate 2220Sstevel@tonic-gate void 2230Sstevel@tonic-gate freeshad() 2240Sstevel@tonic-gate { 2250Sstevel@tonic-gate if (shc == NULL) 2260Sstevel@tonic-gate return; 2270Sstevel@tonic-gate 2280Sstevel@tonic-gate while (shc->higher) 2290Sstevel@tonic-gate shc = shc->higher; 2300Sstevel@tonic-gate while (shc->lower) { 2310Sstevel@tonic-gate shc = shc->lower; 2320Sstevel@tonic-gate if (shc->higher) /* else panic? */ 2330Sstevel@tonic-gate (void) free(shc->higher); 2340Sstevel@tonic-gate } 2350Sstevel@tonic-gate /* 2360Sstevel@tonic-gate * This should be unnecessary, but do it just to be safe. 2370Sstevel@tonic-gate * Note that shc might be malloc'd or static, so can't free(). 2380Sstevel@tonic-gate */ 2390Sstevel@tonic-gate bzero(shc, sizeof (*shc)); 2400Sstevel@tonic-gate } 2410Sstevel@tonic-gate 2420Sstevel@tonic-gate void 2430Sstevel@tonic-gate add(ip) 2440Sstevel@tonic-gate struct dinode *ip; 2450Sstevel@tonic-gate { 2460Sstevel@tonic-gate int i; 2470Sstevel@tonic-gate u_offset_t filesize; 2480Sstevel@tonic-gate 2490Sstevel@tonic-gate if (BIT(ino, nodmap)) 2500Sstevel@tonic-gate return; 2510Sstevel@tonic-gate if ((ip->di_mode & IFMT) != IFDIR && 2520Sstevel@tonic-gate (ip->di_mode & IFMT) != IFATTRDIR) { 2530Sstevel@tonic-gate (void) snprintf(msgbuf, sizeof (msgbuf), gettext( 2540Sstevel@tonic-gate "Warning - directory at inode `%lu' vanished!\n"), ino); 2550Sstevel@tonic-gate msg(msgbuf); 2560Sstevel@tonic-gate /* LINTED: 32-bit to 8-bit assignment ok */ 2570Sstevel@tonic-gate BIC(ino, dirmap); 2580Sstevel@tonic-gate return; 2590Sstevel@tonic-gate } 2600Sstevel@tonic-gate nsubdir = 0; 2610Sstevel@tonic-gate dadded = 0; 2620Sstevel@tonic-gate filesize = ip->di_size; 2630Sstevel@tonic-gate for (i = 0; i < NDADDR; i++) { 2640Sstevel@tonic-gate if (ip->di_db[i] != 0) 2650Sstevel@tonic-gate /* LINTED dblksize/blkoff does a safe cast here */ 2660Sstevel@tonic-gate dsrch(ip->di_db[i], (ulong_t)dblksize(sblock, ip, i), 2670Sstevel@tonic-gate filesize); 2680Sstevel@tonic-gate filesize -= (unsigned)(sblock->fs_bsize); 2690Sstevel@tonic-gate } 2700Sstevel@tonic-gate for (i = 0; i < NIADDR; i++) { 2710Sstevel@tonic-gate if (ip->di_ib[i] != 0) 2720Sstevel@tonic-gate indir(ip->di_ib[i], i, &filesize); 2730Sstevel@tonic-gate } 2740Sstevel@tonic-gate if (dadded) { 2750Sstevel@tonic-gate nadded++; 2760Sstevel@tonic-gate if (!BIT(ino, nodmap)) { 2770Sstevel@tonic-gate /* LINTED: 32-bit to 8-bit assignment ok */ 2780Sstevel@tonic-gate BIS(ino, nodmap); 2790Sstevel@tonic-gate if ((ip->di_mode & IFMT) == IFATTRDIR) { 2800Sstevel@tonic-gate /* attribute changes "auto-percolate" to root */ 2810Sstevel@tonic-gate BIS(UFSROOTINO, nodmap); 2820Sstevel@tonic-gate } 2830Sstevel@tonic-gate est(ip); 2840Sstevel@tonic-gate } 2850Sstevel@tonic-gate } 2860Sstevel@tonic-gate if (nsubdir == 0) { 2870Sstevel@tonic-gate if (!BIT(ino, nodmap)) { 2880Sstevel@tonic-gate /* LINTED: 32-bit to 8-bit assignment ok */ 2890Sstevel@tonic-gate BIC(ino, dirmap); 2900Sstevel@tonic-gate } 2910Sstevel@tonic-gate } 2920Sstevel@tonic-gate } 2930Sstevel@tonic-gate 2940Sstevel@tonic-gate static void 2950Sstevel@tonic-gate indir(d, n, filesize) 2960Sstevel@tonic-gate daddr32_t d; 2970Sstevel@tonic-gate int n; 2980Sstevel@tonic-gate u_offset_t *filesize; 2990Sstevel@tonic-gate { 3000Sstevel@tonic-gate int i; 3010Sstevel@tonic-gate daddr32_t idblk[MAXNINDIR]; 3020Sstevel@tonic-gate 3030Sstevel@tonic-gate if ((unsigned)(sblock->fs_bsize) > sizeof (idblk)) { 3040Sstevel@tonic-gate msg(gettext( 3050Sstevel@tonic-gate "Inconsistency detected: filesystem block size larger than valid maximum.\n")); 3060Sstevel@tonic-gate dumpabort(); 3070Sstevel@tonic-gate /*NOTREACHED*/ 3080Sstevel@tonic-gate } 3090Sstevel@tonic-gate 3100Sstevel@tonic-gate if ((unsigned)NINDIR(sblock) > MAXNINDIR) { 3110Sstevel@tonic-gate /*CSTYLED*/ 3120Sstevel@tonic-gate msg(gettext( 3130Sstevel@tonic-gate "Inconsistency detected: inode has more indirect \ 3140Sstevel@tonic-gate blocks than valid maximum.\n")); 3150Sstevel@tonic-gate dumpabort(); 3160Sstevel@tonic-gate /*NOTREACHED*/ 3170Sstevel@tonic-gate } 3180Sstevel@tonic-gate 3190Sstevel@tonic-gate if (dadded || *filesize == 0) 3200Sstevel@tonic-gate return; 3210Sstevel@tonic-gate 3220Sstevel@tonic-gate #ifdef lint 3230Sstevel@tonic-gate idblk[0] = '\0'; 3240Sstevel@tonic-gate #endif /* lint */ 3250Sstevel@tonic-gate 3260Sstevel@tonic-gate /* xxx sanity check sblock contents before trusting them */ 3270Sstevel@tonic-gate bread(fsbtodb(sblock, d), (uchar_t *)idblk, (size_t)sblock->fs_bsize); 3280Sstevel@tonic-gate if (n <= 0) { 3290Sstevel@tonic-gate for (i = 0; i < NINDIR(sblock); i++) { 3300Sstevel@tonic-gate d = idblk[i]; 3310Sstevel@tonic-gate if (d != 0) 3320Sstevel@tonic-gate dsrch(d, (ulong_t)(uint32_t)sblock->fs_bsize, 3330Sstevel@tonic-gate *filesize); 3340Sstevel@tonic-gate *filesize -= (unsigned)(sblock->fs_bsize); 3350Sstevel@tonic-gate } 3360Sstevel@tonic-gate } else { 3370Sstevel@tonic-gate n--; 3380Sstevel@tonic-gate for (i = 0; i < NINDIR(sblock); i++) { 3390Sstevel@tonic-gate d = idblk[i]; 3400Sstevel@tonic-gate if (d != 0) 3410Sstevel@tonic-gate indir(d, n, filesize); 3420Sstevel@tonic-gate } 3430Sstevel@tonic-gate } 3440Sstevel@tonic-gate } 3450Sstevel@tonic-gate 3460Sstevel@tonic-gate void 3470Sstevel@tonic-gate dirdump(ip) 3480Sstevel@tonic-gate struct dinode *ip; 3490Sstevel@tonic-gate { 3500Sstevel@tonic-gate /* watchout for dir inodes deleted and maybe reallocated */ 3510Sstevel@tonic-gate if (((ip->di_mode & IFMT) != IFDIR && 3520Sstevel@tonic-gate (ip->di_mode & IFMT) != IFATTRDIR) || ip->di_nlink < 2) { 3530Sstevel@tonic-gate (void) snprintf(msgbuf, sizeof (msgbuf), gettext( 3540Sstevel@tonic-gate "Warning - directory at inode `%lu' vanished!\n"), 3550Sstevel@tonic-gate ino); 3560Sstevel@tonic-gate msg(msgbuf); 3570Sstevel@tonic-gate return; 3580Sstevel@tonic-gate } 3590Sstevel@tonic-gate lf_dump(ip); 3600Sstevel@tonic-gate } 3610Sstevel@tonic-gate 3620Sstevel@tonic-gate static u_offset_t loffset; /* current offset in file (ufsdump) */ 3630Sstevel@tonic-gate 3640Sstevel@tonic-gate static void 3650Sstevel@tonic-gate lf_dumpmeta(ip) 3660Sstevel@tonic-gate struct dinode *ip; 3670Sstevel@tonic-gate { 3680Sstevel@tonic-gate if ((ip->di_shadow == 0) || shortmeta) 3690Sstevel@tonic-gate return; 3700Sstevel@tonic-gate 3710Sstevel@tonic-gate lf_dumpinode(getino((ino_t)(unsigned)(ip->di_shadow))); 3720Sstevel@tonic-gate } 3730Sstevel@tonic-gate 3740Sstevel@tonic-gate int 3750Sstevel@tonic-gate hasshortmeta(ip) 3760Sstevel@tonic-gate struct dinode **ip; 3770Sstevel@tonic-gate { 3780Sstevel@tonic-gate ino_t savino; 3790Sstevel@tonic-gate int rc; 3800Sstevel@tonic-gate 3810Sstevel@tonic-gate if ((*ip)->di_shadow == 0) 3820Sstevel@tonic-gate return (0); 3830Sstevel@tonic-gate savino = ino; 3840Sstevel@tonic-gate *ip = getino((ino_t)(unsigned)((*ip)->di_shadow)); 3850Sstevel@tonic-gate rc = ((*ip)->di_size <= sizeof (union u_shadow)); 3860Sstevel@tonic-gate *ip = getino(ino = savino); 3870Sstevel@tonic-gate return (rc); 3880Sstevel@tonic-gate } 3890Sstevel@tonic-gate 3900Sstevel@tonic-gate void 3910Sstevel@tonic-gate lf_dumpinode(ip) 3920Sstevel@tonic-gate struct dinode *ip; 3930Sstevel@tonic-gate { 3940Sstevel@tonic-gate int i; 3950Sstevel@tonic-gate u_offset_t size; 3960Sstevel@tonic-gate 3970Sstevel@tonic-gate i = ip->di_mode & IFMT; 3980Sstevel@tonic-gate 3990Sstevel@tonic-gate if (i == 0 || ip->di_nlink <= 0) 4000Sstevel@tonic-gate return; 4010Sstevel@tonic-gate 4020Sstevel@tonic-gate spcl.c_dinode = *ip; 4030Sstevel@tonic-gate spcl.c_count = 0; 4040Sstevel@tonic-gate 4050Sstevel@tonic-gate if ((i != IFDIR && i != IFATTRDIR && i != IFREG && i != IFLNK && 4060Sstevel@tonic-gate i != IFSHAD) || ip->di_size == 0) { 4070Sstevel@tonic-gate toslave(dospcl, ino); 4080Sstevel@tonic-gate return; 4090Sstevel@tonic-gate } 4100Sstevel@tonic-gate 4110Sstevel@tonic-gate size = NDADDR * (unsigned)(sblock->fs_bsize); 4120Sstevel@tonic-gate if (size > ip->di_size) 4130Sstevel@tonic-gate size = ip->di_size; 4140Sstevel@tonic-gate 4150Sstevel@tonic-gate lf_blksout(&ip->di_db[0], size); 4160Sstevel@tonic-gate 4170Sstevel@tonic-gate size = ip->di_size - size; 4180Sstevel@tonic-gate if (size > 0) { 4190Sstevel@tonic-gate for (i = 0; i < NIADDR; i++) { 4200Sstevel@tonic-gate lf_dmpindir(ip->di_ib[i], i, &size); 4210Sstevel@tonic-gate if (size == 0) 4220Sstevel@tonic-gate break; 4230Sstevel@tonic-gate } 4240Sstevel@tonic-gate } 4250Sstevel@tonic-gate } 4260Sstevel@tonic-gate 4270Sstevel@tonic-gate void 4280Sstevel@tonic-gate lf_dump(ip) 4290Sstevel@tonic-gate struct dinode *ip; 4300Sstevel@tonic-gate { 4310Sstevel@tonic-gate 4320Sstevel@tonic-gate if ((!BIT(ino, nodmap)) && (!BIT(ino, shamap))) 4330Sstevel@tonic-gate return; 4340Sstevel@tonic-gate 4350Sstevel@tonic-gate shortmeta = hasshortmeta(&ip); 4360Sstevel@tonic-gate if (shortmeta) { 4370Sstevel@tonic-gate ip = getino((ino_t)(unsigned)(ip->di_shadow)); 4380Sstevel@tonic-gate /* assume spcl.c_shadow is smaller than 1 block */ 4390Sstevel@tonic-gate bread(fsbtodb(sblock, ip->di_db[0]), 4400Sstevel@tonic-gate (uchar_t *)spcl.c_shadow.c_shadow, sizeof (spcl.c_shadow)); 4410Sstevel@tonic-gate spcl.c_flags |= DR_HASMETA; 4420Sstevel@tonic-gate } else { 4430Sstevel@tonic-gate spcl.c_flags &= ~DR_HASMETA; 4440Sstevel@tonic-gate } 4450Sstevel@tonic-gate ip = getino(ino); 4460Sstevel@tonic-gate 4470Sstevel@tonic-gate loffset = 0; 4480Sstevel@tonic-gate 4490Sstevel@tonic-gate if (newtape) { 4500Sstevel@tonic-gate spcl.c_type = TS_TAPE; 4510Sstevel@tonic-gate } else if (pos) 4520Sstevel@tonic-gate spcl.c_type = TS_ADDR; 4530Sstevel@tonic-gate else 4540Sstevel@tonic-gate spcl.c_type = TS_INODE; 4550Sstevel@tonic-gate 4560Sstevel@tonic-gate newtape = 0; 4570Sstevel@tonic-gate lf_dumpinode(ip); 4580Sstevel@tonic-gate lf_dumpmeta(ip); 4590Sstevel@tonic-gate pos = 0; 4600Sstevel@tonic-gate } 4610Sstevel@tonic-gate 4620Sstevel@tonic-gate static void 4630Sstevel@tonic-gate lf_dmpindir(blk, lvl, size) 4640Sstevel@tonic-gate daddr32_t blk; 4650Sstevel@tonic-gate int lvl; 4660Sstevel@tonic-gate u_offset_t *size; 4670Sstevel@tonic-gate { 4680Sstevel@tonic-gate int i; 4690Sstevel@tonic-gate u_offset_t cnt; 4700Sstevel@tonic-gate daddr32_t idblk[MAXNINDIR]; 4710Sstevel@tonic-gate 4720Sstevel@tonic-gate if ((unsigned)(sblock->fs_bsize) > sizeof (idblk)) { 4730Sstevel@tonic-gate msg(gettext( 4740Sstevel@tonic-gate "Inconsistency detected: filesystem block size larger than valid maximum.\n")); 4750Sstevel@tonic-gate dumpabort(); 4760Sstevel@tonic-gate /*NOTREACHED*/ 4770Sstevel@tonic-gate } 4780Sstevel@tonic-gate 4790Sstevel@tonic-gate if ((unsigned)NINDIR(sblock) > MAXNINDIR) { 4800Sstevel@tonic-gate msg(gettext( 4810Sstevel@tonic-gate "Inconsistency detected: inode has more indirect \ 4820Sstevel@tonic-gate blocks than valid maximum.\n")); 4830Sstevel@tonic-gate dumpabort(); 4840Sstevel@tonic-gate /*NOTREACHED*/ 4850Sstevel@tonic-gate } 4860Sstevel@tonic-gate 4870Sstevel@tonic-gate if (blk != 0) 4880Sstevel@tonic-gate bread(fsbtodb(sblock, blk), (uchar_t *)idblk, 4890Sstevel@tonic-gate (size_t)sblock->fs_bsize); 4900Sstevel@tonic-gate else 4910Sstevel@tonic-gate bzero((char *)idblk, (size_t)sblock->fs_bsize); 4920Sstevel@tonic-gate if (lvl <= 0) { 4930Sstevel@tonic-gate cnt = (u_offset_t)(unsigned)NINDIR(sblock) * 4940Sstevel@tonic-gate (u_offset_t)(unsigned)(sblock->fs_bsize); 4950Sstevel@tonic-gate if (cnt > *size) 4960Sstevel@tonic-gate cnt = *size; 4970Sstevel@tonic-gate *size -= cnt; 4980Sstevel@tonic-gate lf_blksout(&idblk[0], cnt); 4990Sstevel@tonic-gate return; 5000Sstevel@tonic-gate } 5010Sstevel@tonic-gate lvl--; 5020Sstevel@tonic-gate for (i = 0; i < NINDIR(sblock); i++) { 5030Sstevel@tonic-gate lf_dmpindir(idblk[i], lvl, size); 5040Sstevel@tonic-gate if (*size == 0) 5050Sstevel@tonic-gate return; 5060Sstevel@tonic-gate } 5070Sstevel@tonic-gate } 5080Sstevel@tonic-gate 5090Sstevel@tonic-gate static void 5100Sstevel@tonic-gate lf_blksout(blkp, bytes) 5110Sstevel@tonic-gate daddr32_t *blkp; 5120Sstevel@tonic-gate u_offset_t bytes; 5130Sstevel@tonic-gate { 5140Sstevel@tonic-gate u_offset_t i; 5150Sstevel@tonic-gate u_offset_t tbperfsb = (unsigned)(sblock->fs_bsize / tp_bsize); 5160Sstevel@tonic-gate 5170Sstevel@tonic-gate u_offset_t j, k, count; 5180Sstevel@tonic-gate 5190Sstevel@tonic-gate u_offset_t bytepos, diff; 5200Sstevel@tonic-gate u_offset_t bytecnt = 0; 5210Sstevel@tonic-gate off_t byteoff = 0; /* bytes to skip within first f/s block */ 5220Sstevel@tonic-gate off_t fragoff = 0; /* frags to skip within first f/s block */ 5230Sstevel@tonic-gate 5240Sstevel@tonic-gate u_offset_t tpblkoff = 0; /* tape blocks to skip in first f/s block */ 5250Sstevel@tonic-gate u_offset_t tpblkskip = 0; /* total tape blocks to skip */ 5260Sstevel@tonic-gate u_offset_t skip; /* tape blocks to skip this pass */ 5270Sstevel@tonic-gate 5280Sstevel@tonic-gate if (pos) { 5290Sstevel@tonic-gate /* 5300Sstevel@tonic-gate * We get here if a slave throws a signal to the 5310Sstevel@tonic-gate * master indicating a partially dumped file. 5320Sstevel@tonic-gate * Begin by figuring out what was undone. 5330Sstevel@tonic-gate */ 5340Sstevel@tonic-gate bytepos = (offset_t)pos * tp_bsize; 5350Sstevel@tonic-gate 5360Sstevel@tonic-gate if ((loffset + bytes) <= bytepos) { 5370Sstevel@tonic-gate /* This stuff was dumped already, forget it. */ 5380Sstevel@tonic-gate loffset += (u_offset_t)tp_bsize * 5390Sstevel@tonic-gate /* LINTED: spurious complaint on sign-extending */ 5400Sstevel@tonic-gate d_howmany(bytes, (u_offset_t)tp_bsize); 5410Sstevel@tonic-gate return; 5420Sstevel@tonic-gate } 5430Sstevel@tonic-gate 5440Sstevel@tonic-gate if (loffset < bytepos) { 5450Sstevel@tonic-gate /* 5460Sstevel@tonic-gate * Some of this was dumped, some wasn't. 5470Sstevel@tonic-gate * Figure out what was done and skip it. 5480Sstevel@tonic-gate */ 5490Sstevel@tonic-gate diff = bytepos - loffset; 5500Sstevel@tonic-gate /* LINTED: spurious complaint on sign-extending */ 5510Sstevel@tonic-gate tpblkskip = d_howmany(diff, (u_offset_t)tp_bsize); 5520Sstevel@tonic-gate /* LINTED room after EOT is only a few MB */ 5530Sstevel@tonic-gate blkp += (int)(diff / sblock->fs_bsize); 5540Sstevel@tonic-gate 5550Sstevel@tonic-gate bytecnt = diff % (unsigned)(sblock->fs_bsize); 5560Sstevel@tonic-gate /* LINTED: result fits, due to modulus */ 5570Sstevel@tonic-gate byteoff = bytecnt % (off_t)(sblock->fs_fsize); 5580Sstevel@tonic-gate /* LINTED: spurious complaint on sign-extending */ 5590Sstevel@tonic-gate tpblkoff = d_howmany(bytecnt, 5600Sstevel@tonic-gate (u_offset_t)(unsigned)tp_bsize); 5610Sstevel@tonic-gate /* LINTED: result fits, due to modulus */ 5620Sstevel@tonic-gate fragoff = bytecnt / (off_t)(sblock->fs_fsize); 5630Sstevel@tonic-gate bytecnt = (unsigned)(sblock->fs_bsize) - bytecnt; 5640Sstevel@tonic-gate } 5650Sstevel@tonic-gate } 5660Sstevel@tonic-gate 5670Sstevel@tonic-gate loffset += bytes; 5680Sstevel@tonic-gate 5690Sstevel@tonic-gate while (bytes > 0) { 5700Sstevel@tonic-gate if (bytes < TP_NINDIR*tp_bsize) 5710Sstevel@tonic-gate /* LINTED: spurious complaint on sign-extending */ 5720Sstevel@tonic-gate count = d_howmany(bytes, (u_offset_t)tp_bsize); 5730Sstevel@tonic-gate else 5740Sstevel@tonic-gate count = TP_NINDIR; 5750Sstevel@tonic-gate if (tpblkskip) { 5760Sstevel@tonic-gate if (tpblkskip < TP_NINDIR) { 5770Sstevel@tonic-gate bytes -= (tpblkskip * (u_offset_t)tp_bsize); 5780Sstevel@tonic-gate skip = tpblkskip; 5790Sstevel@tonic-gate tpblkskip = 0; 5800Sstevel@tonic-gate } else { 5810Sstevel@tonic-gate bytes -= (offset_t)TP_NINDIR*tp_bsize; 5820Sstevel@tonic-gate tpblkskip -= TP_NINDIR; 5830Sstevel@tonic-gate continue; 5840Sstevel@tonic-gate } 5850Sstevel@tonic-gate } else 5860Sstevel@tonic-gate skip = 0; 5870Sstevel@tonic-gate assert(tbperfsb >= tpblkoff); 5880Sstevel@tonic-gate assert((count - skip) <= TP_NINDIR); 5890Sstevel@tonic-gate for (j = 0, k = 0; j < count - skip; j++, k++) { 5900Sstevel@tonic-gate spcl.c_addr[j] = (blkp[k] != 0); 5910Sstevel@tonic-gate for (i = tbperfsb - tpblkoff; --i > 0; j++) 5920Sstevel@tonic-gate spcl.c_addr[j+1] = spcl.c_addr[j]; 5930Sstevel@tonic-gate tpblkoff = 0; 5940Sstevel@tonic-gate } 5950Sstevel@tonic-gate /* LINTED (count - skip) will always fit into an int32_t */ 5960Sstevel@tonic-gate spcl.c_count = count - skip; 5970Sstevel@tonic-gate toslave(dospcl, ino); 5980Sstevel@tonic-gate bytecnt = MIN(bytes, bytecnt ? 5990Sstevel@tonic-gate bytecnt : (unsigned)(sblock->fs_bsize)); 6000Sstevel@tonic-gate j = 0; 6010Sstevel@tonic-gate while (j < count - skip) { 6020Sstevel@tonic-gate if (*blkp != 0) { 6030Sstevel@tonic-gate /* LINTED: fragoff fits into 32 bits */ 6040Sstevel@tonic-gate dmpblk(*blkp+(int32_t)fragoff, 6050Sstevel@tonic-gate /* LINTED: bytecnt fits into 32 bits */ 6060Sstevel@tonic-gate (size_t)bytecnt, byteoff); 6070Sstevel@tonic-gate } 6080Sstevel@tonic-gate blkp++; 6090Sstevel@tonic-gate bytes -= bytecnt; 6100Sstevel@tonic-gate /* LINTED: spurious complaint on sign-extending */ 6110Sstevel@tonic-gate j += d_howmany(bytecnt, (u_offset_t)tp_bsize); 6120Sstevel@tonic-gate bytecnt = MIN(bytes, (unsigned)(sblock->fs_bsize)); 6130Sstevel@tonic-gate byteoff = 0; 6140Sstevel@tonic-gate fragoff = 0; 6150Sstevel@tonic-gate } 6160Sstevel@tonic-gate spcl.c_type = TS_ADDR; 6170Sstevel@tonic-gate bytecnt = 0; 6180Sstevel@tonic-gate } 6190Sstevel@tonic-gate pos = 0; 6200Sstevel@tonic-gate } 6210Sstevel@tonic-gate 6220Sstevel@tonic-gate void 6230Sstevel@tonic-gate bitmap(map, typ) 6240Sstevel@tonic-gate uchar_t *map; 6250Sstevel@tonic-gate int typ; 6260Sstevel@tonic-gate { 6270Sstevel@tonic-gate int i; 6280Sstevel@tonic-gate u_offset_t count; 6290Sstevel@tonic-gate uchar_t *cp; 6300Sstevel@tonic-gate 6310Sstevel@tonic-gate if (!newtape) 6320Sstevel@tonic-gate spcl.c_type = typ; 6330Sstevel@tonic-gate else 6340Sstevel@tonic-gate newtape = 0; 6350Sstevel@tonic-gate for (i = 0; i < TP_NINDIR; i++) 6360Sstevel@tonic-gate spcl.c_addr[i] = 1; 6370Sstevel@tonic-gate /* LINTED: spurious complaint on sign-extending */ 6380Sstevel@tonic-gate count = d_howmany(msiz * sizeof (map[0]), tp_bsize) - pos; 6390Sstevel@tonic-gate for (cp = &map[pos * tp_bsize]; count > 0; 6400Sstevel@tonic-gate count -= (u_offset_t)(unsigned)spcl.c_count) { 6410Sstevel@tonic-gate if (leftover) { 6420Sstevel@tonic-gate spcl.c_count = leftover; 6430Sstevel@tonic-gate leftover = 0; 6440Sstevel@tonic-gate } else { 6450Sstevel@tonic-gate /* LINTED value always less than INT32_MAX */ 6460Sstevel@tonic-gate spcl.c_count = count > TP_NINDIR ? TP_NINDIR : count; 6470Sstevel@tonic-gate } 6480Sstevel@tonic-gate spclrec(); 6490Sstevel@tonic-gate for (i = 0; i < spcl.c_count; i++, cp += tp_bsize) 6500Sstevel@tonic-gate taprec(cp, 0, tp_bsize); 6510Sstevel@tonic-gate spcl.c_type = TS_ADDR; 6520Sstevel@tonic-gate } 6530Sstevel@tonic-gate } 6540Sstevel@tonic-gate 6550Sstevel@tonic-gate static void 6560Sstevel@tonic-gate dsrch(d, size, filesize) 6570Sstevel@tonic-gate daddr32_t d; 6580Sstevel@tonic-gate ulong_t size; /* block size */ 6590Sstevel@tonic-gate u_offset_t filesize; 6600Sstevel@tonic-gate { 6610Sstevel@tonic-gate struct direct *dp; 6620Sstevel@tonic-gate struct dinode *ip; 6630Sstevel@tonic-gate ulong_t loc; 6640Sstevel@tonic-gate char dblk[MAXBSIZE]; 6650Sstevel@tonic-gate 6660Sstevel@tonic-gate if (dadded || filesize == 0) 6670Sstevel@tonic-gate return; 6680Sstevel@tonic-gate if (filesize > (u_offset_t)size) 6690Sstevel@tonic-gate filesize = (u_offset_t)size; 6700Sstevel@tonic-gate if (sizeof (dblk) < roundup(filesize, DEV_BSIZE)) { 6710Sstevel@tonic-gate msg(gettext( 6720Sstevel@tonic-gate "Inconsistency detected: filesystem block size larger than valid maximum.\n")); 6730Sstevel@tonic-gate dumpabort(); 6740Sstevel@tonic-gate /*NOTREACHED*/ 6750Sstevel@tonic-gate } 6760Sstevel@tonic-gate 6770Sstevel@tonic-gate #ifdef lint 6780Sstevel@tonic-gate dblk[0] = '\0'; 6790Sstevel@tonic-gate #endif /* lint */ 6800Sstevel@tonic-gate 6810Sstevel@tonic-gate /* LINTED ufs disk addresses always fit into 32 bits */ 6820Sstevel@tonic-gate bread(fsbtodb(sblock, d), (uchar_t *)dblk, 6830Sstevel@tonic-gate /* LINTED from sizeof check above, roundup() <= max(size_t) */ 6840Sstevel@tonic-gate (size_t)(roundup(filesize, DEV_BSIZE))); 6850Sstevel@tonic-gate loc = 0; 6860Sstevel@tonic-gate while ((u_offset_t)loc < filesize) { 6870Sstevel@tonic-gate /*LINTED [dblk is char[], loc (dp->d_reclen) % 4 == 0]*/ 6880Sstevel@tonic-gate dp = (struct direct *)(dblk + loc); 6890Sstevel@tonic-gate if (dp->d_reclen == 0) { 6900Sstevel@tonic-gate (void) snprintf(msgbuf, sizeof (msgbuf), gettext( 6910Sstevel@tonic-gate "Warning - directory at inode `%lu' is corrupted\n"), 6920Sstevel@tonic-gate ino); 6930Sstevel@tonic-gate msg(msgbuf); 6940Sstevel@tonic-gate break; 6950Sstevel@tonic-gate } 6960Sstevel@tonic-gate loc += dp->d_reclen; 6970Sstevel@tonic-gate if (dp->d_ino == 0) 6980Sstevel@tonic-gate continue; 6990Sstevel@tonic-gate if (dp->d_name[0] == '.') { 7000Sstevel@tonic-gate if (dp->d_name[1] == '\0') { 7010Sstevel@tonic-gate if ((ino_t)(dp->d_ino) != ino) { 7020Sstevel@tonic-gate (void) snprintf(msgbuf, sizeof (msgbuf), 7030Sstevel@tonic-gate gettext( 7040Sstevel@tonic-gate "Warning - directory at inode `%lu' is corrupted:\n\ 7050Sstevel@tonic-gate \t\".\" points to inode `%lu' - run fsck\n"), 7060Sstevel@tonic-gate ino, dp->d_ino); 7070Sstevel@tonic-gate msg(msgbuf); 7080Sstevel@tonic-gate } 7090Sstevel@tonic-gate continue; 7100Sstevel@tonic-gate } 7110Sstevel@tonic-gate if (dp->d_name[1] == '.' && dp->d_name[2] == '\0') { 7120Sstevel@tonic-gate if (!BIT(dp->d_ino, dirmap) && 7130Sstevel@tonic-gate ((ip = getino(ino)) == NULL || 7140Sstevel@tonic-gate (ip->di_mode & IFMT) != IFATTRDIR)) { 7150Sstevel@tonic-gate (void) snprintf(msgbuf, sizeof (msgbuf), 7160Sstevel@tonic-gate gettext( 7170Sstevel@tonic-gate "Warning - directory at inode `%lu' is corrupted:\n\ 7180Sstevel@tonic-gate \t\"..\" points to non-directory inode `%lu' - run fsck\n"), 7190Sstevel@tonic-gate ino, dp->d_ino); 7200Sstevel@tonic-gate msg(msgbuf); 7210Sstevel@tonic-gate } 7220Sstevel@tonic-gate continue; 7230Sstevel@tonic-gate } 7240Sstevel@tonic-gate } 7250Sstevel@tonic-gate if (BIT(dp->d_ino, nodmap)) { 7260Sstevel@tonic-gate dadded++; 7270Sstevel@tonic-gate return; 7280Sstevel@tonic-gate } 7290Sstevel@tonic-gate if (BIT(dp->d_ino, dirmap)) 7300Sstevel@tonic-gate nsubdir++; 7310Sstevel@tonic-gate } 7320Sstevel@tonic-gate } 7330Sstevel@tonic-gate 7340Sstevel@tonic-gate #define CACHESIZE 32 7350Sstevel@tonic-gate 7360Sstevel@tonic-gate struct dinode * 7370Sstevel@tonic-gate getino(ino) 7380Sstevel@tonic-gate ino_t ino; 7390Sstevel@tonic-gate { 7400Sstevel@tonic-gate static ino_t minino, maxino; 7410Sstevel@tonic-gate static struct dinode itab[MAXINOPB]; 7420Sstevel@tonic-gate static struct dinode icache[CACHESIZE]; 7430Sstevel@tonic-gate static ino_t icacheval[CACHESIZE], lasti = 0; 7440Sstevel@tonic-gate static int cacheoff = 0; 7450Sstevel@tonic-gate int i; 7460Sstevel@tonic-gate 7470Sstevel@tonic-gate if (ino >= minino && ino < maxino) { 7480Sstevel@tonic-gate lasti = ino; 7490Sstevel@tonic-gate return (&itab[ino - minino]); 7500Sstevel@tonic-gate } 7510Sstevel@tonic-gate 7520Sstevel@tonic-gate /* before we do major i/o, check for a secondary cache hit */ 7530Sstevel@tonic-gate for (i = 0; i < CACHESIZE; i++) 7540Sstevel@tonic-gate if (icacheval[i] == ino) 7550Sstevel@tonic-gate return (icache + i); 7560Sstevel@tonic-gate 7570Sstevel@tonic-gate /* we need to do major i/o. throw the last inode retrieved into */ 7580Sstevel@tonic-gate /* the cache. note: this copies garbage the first time it is */ 7590Sstevel@tonic-gate /* used, but no harm done. */ 7600Sstevel@tonic-gate icacheval[cacheoff] = lasti; 7610Sstevel@tonic-gate bcopy(itab + (lasti - minino), icache + cacheoff, sizeof (itab[0])); 7620Sstevel@tonic-gate lasti = ino; 7630Sstevel@tonic-gate if (++cacheoff >= CACHESIZE) 7640Sstevel@tonic-gate cacheoff = 0; 7650Sstevel@tonic-gate 7660Sstevel@tonic-gate #define INOPERDB (DEV_BSIZE / sizeof (struct dinode)) 7670Sstevel@tonic-gate minino = ino &~ (INOPERDB - 1); 7680Sstevel@tonic-gate maxino = ((itog(sblock, ino) + 1) * (unsigned)(sblock->fs_ipg)); 7690Sstevel@tonic-gate if (maxino > minino + MAXINOPB) 7700Sstevel@tonic-gate maxino = minino + MAXINOPB; 7710Sstevel@tonic-gate bread( 7720Sstevel@tonic-gate /* LINTED: can't make up for broken system macros here */ 7730Sstevel@tonic-gate (fsbtodb(sblock, itod(sblock, ino)) + itoo(sblock, ino) / INOPERDB), 7740Sstevel@tonic-gate /* LINTED: (max - min) * size fits into a size_t */ 7750Sstevel@tonic-gate (uchar_t *)itab, (size_t)((maxino - minino) * sizeof (*itab))); 7760Sstevel@tonic-gate return (&itab[ino - minino]); 7770Sstevel@tonic-gate } 7780Sstevel@tonic-gate 7790Sstevel@tonic-gate #define BREADEMAX 32 7800Sstevel@tonic-gate 7810Sstevel@tonic-gate #ifdef NO__LONGLONG__ 7820Sstevel@tonic-gate #define DEV_LSEEK(fd, offset, whence) \ 7830Sstevel@tonic-gate lseek((fd), (((off_t)(offset))*DEV_BSIZE), (whence)) 7840Sstevel@tonic-gate #else 7850Sstevel@tonic-gate #define DEV_LSEEK(fd, offset, whence) \ 786*2249Sns158690 llseek((fd), (((offset_t)((offset)))*DEV_BSIZE), (whence)) 7870Sstevel@tonic-gate #endif 7880Sstevel@tonic-gate 7890Sstevel@tonic-gate #define BREAD_FAIL(buf, size) { \ 7900Sstevel@tonic-gate breaderrors += 1; \ 7910Sstevel@tonic-gate bzero(buf, (size_t)size); \ 7920Sstevel@tonic-gate } 7930Sstevel@tonic-gate 7940Sstevel@tonic-gate 7950Sstevel@tonic-gate 7960Sstevel@tonic-gate void 7970Sstevel@tonic-gate bread(da, ba, cnt) 7980Sstevel@tonic-gate diskaddr_t da; 7990Sstevel@tonic-gate uchar_t *ba; 8000Sstevel@tonic-gate size_t cnt; 8010Sstevel@tonic-gate { 8020Sstevel@tonic-gate caddr_t maddr; 8030Sstevel@tonic-gate uchar_t *dest; 8040Sstevel@tonic-gate int saverr; 8050Sstevel@tonic-gate int n; 8060Sstevel@tonic-gate size_t len; 8070Sstevel@tonic-gate off64_t filoff; 8080Sstevel@tonic-gate off64_t mapoff; 8090Sstevel@tonic-gate off64_t displacement; 8100Sstevel@tonic-gate 8110Sstevel@tonic-gate static size_t pagesize = 0; 8120Sstevel@tonic-gate static int breaderrors = 0; 8130Sstevel@tonic-gate 8140Sstevel@tonic-gate /* mechanics for caching small bread requests. these are */ 8150Sstevel@tonic-gate /* often small ACLs that are used over and over. */ 8160Sstevel@tonic-gate static uchar_t bcache[DEV_BSIZE * CACHESIZE]; 8170Sstevel@tonic-gate static diskaddr_t bcacheval[CACHESIZE]; 8180Sstevel@tonic-gate static int cacheoff = 0; 8190Sstevel@tonic-gate int i; 8200Sstevel@tonic-gate 8210Sstevel@tonic-gate if ((cnt >= DEV_BSIZE) && (mapfd != -1)) { 8220Sstevel@tonic-gate if (pagesize == 0) 8230Sstevel@tonic-gate pagesize = getpagesize(); 8240Sstevel@tonic-gate /* 8250Sstevel@tonic-gate * We depend on mmap(2)'s guarantee that mapping a 8260Sstevel@tonic-gate * partial page will cause the remainder of the page 8270Sstevel@tonic-gate * to be zero-filled. 8280Sstevel@tonic-gate */ 8290Sstevel@tonic-gate filoff = ((off64_t)da) * DEV_BSIZE; 8300Sstevel@tonic-gate displacement = filoff & (pagesize - 1); 8310Sstevel@tonic-gate mapoff = filoff - displacement; 8320Sstevel@tonic-gate /* LINTED offset will fit into 32 bits */ 8330Sstevel@tonic-gate len = (size_t)roundup(cnt + (filoff - mapoff), pagesize); 8340Sstevel@tonic-gate maddr = mmap64(NULL, len, PROT_READ, MAP_SHARED, mapfd, mapoff); 8350Sstevel@tonic-gate if (maddr != MAP_FAILED) { 8360Sstevel@tonic-gate (void) memcpy(ba, maddr + displacement, cnt); 8370Sstevel@tonic-gate (void) munmap(maddr, len); 8380Sstevel@tonic-gate return; 8390Sstevel@tonic-gate } 8400Sstevel@tonic-gate } 8410Sstevel@tonic-gate 8420Sstevel@tonic-gate if (DEV_LSEEK(fi, da, L_SET) < 0) { 8430Sstevel@tonic-gate saverr = errno; 8440Sstevel@tonic-gate msg(gettext("bread: dev_seek error: %s\n"), strerror(saverr)); 8450Sstevel@tonic-gate /* Don't know where we are, return the least-harmful data */ 8460Sstevel@tonic-gate BREAD_FAIL(ba, cnt); 8470Sstevel@tonic-gate return; 8480Sstevel@tonic-gate } 8490Sstevel@tonic-gate 8500Sstevel@tonic-gate if (read(fi, ba, (size_t)cnt) == (size_t)cnt) 8510Sstevel@tonic-gate return; 8520Sstevel@tonic-gate 8530Sstevel@tonic-gate while (cnt != 0) { 8540Sstevel@tonic-gate 8550Sstevel@tonic-gate if (da >= fsbtodb(sblock, sblock->fs_size)) { 8560Sstevel@tonic-gate msg(gettext( 8570Sstevel@tonic-gate "Warning - block %llu is beyond the end of `%s'\n"), 8580Sstevel@tonic-gate da, disk); 8590Sstevel@tonic-gate BREAD_FAIL(ba, cnt); 8600Sstevel@tonic-gate break; 8610Sstevel@tonic-gate } 8620Sstevel@tonic-gate 8630Sstevel@tonic-gate if (DEV_LSEEK(fi, da, L_SET) < 0) { 8640Sstevel@tonic-gate msg(gettext("%s: %s error\n"), "bread", "DEV_LSEEK2"); 8650Sstevel@tonic-gate BREAD_FAIL(ba, cnt); 8660Sstevel@tonic-gate break; 8670Sstevel@tonic-gate } 8680Sstevel@tonic-gate 8690Sstevel@tonic-gate if (cnt < DEV_BSIZE) { 8700Sstevel@tonic-gate /* small read. check for cache hit. */ 8710Sstevel@tonic-gate for (i = 0; i < CACHESIZE; i++) 8720Sstevel@tonic-gate if (bcacheval[i] == da) { 8730Sstevel@tonic-gate bcopy(bcache + (i * DEV_BSIZE), 8740Sstevel@tonic-gate ba, cnt); 8750Sstevel@tonic-gate return; 8760Sstevel@tonic-gate } 8770Sstevel@tonic-gate 8780Sstevel@tonic-gate /* no cache hit; throw this one into the cache... */ 8790Sstevel@tonic-gate len = cnt; 8800Sstevel@tonic-gate dest = bcache + (cacheoff * DEV_BSIZE); 8810Sstevel@tonic-gate bcacheval[cacheoff] = da; 8820Sstevel@tonic-gate if (++cacheoff >= CACHESIZE) 8830Sstevel@tonic-gate cacheoff = 0; 8840Sstevel@tonic-gate } else { 8850Sstevel@tonic-gate len = DEV_BSIZE; 8860Sstevel@tonic-gate dest = ba; 8870Sstevel@tonic-gate } 8880Sstevel@tonic-gate 8890Sstevel@tonic-gate n = read(fi, dest, DEV_BSIZE); 8900Sstevel@tonic-gate if (n != DEV_BSIZE) { 8910Sstevel@tonic-gate n = MAX(n, 0); 8920Sstevel@tonic-gate bzero(dest+n, DEV_BSIZE-n); 8930Sstevel@tonic-gate breaderrors += 1; 8940Sstevel@tonic-gate msg(gettext( 8950Sstevel@tonic-gate "Warning - cannot read sector %llu of `%s'\n"), 8960Sstevel@tonic-gate da, disk); 8970Sstevel@tonic-gate } 8980Sstevel@tonic-gate if (dest != ba) 8990Sstevel@tonic-gate bcopy(dest, ba, len); 9000Sstevel@tonic-gate 9010Sstevel@tonic-gate da++; 9020Sstevel@tonic-gate /* LINTED character pointers aren't signed */ 9030Sstevel@tonic-gate ba += len; 9040Sstevel@tonic-gate cnt -= len; 9050Sstevel@tonic-gate } 9060Sstevel@tonic-gate 9070Sstevel@tonic-gate if (breaderrors > BREADEMAX) { 9080Sstevel@tonic-gate msg(gettext( 9090Sstevel@tonic-gate "More than %d block read errors from dump device `%s'\n"), 9100Sstevel@tonic-gate BREADEMAX, disk); 9110Sstevel@tonic-gate dumpailing(); 9120Sstevel@tonic-gate breaderrors = 0; 9130Sstevel@tonic-gate } 9140Sstevel@tonic-gate } 915