xref: /onnv-gate/usr/src/cmd/backup/dump/dumptraverse.c (revision 2249:62244621db53)
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
mark(ip)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
active_mark(ip)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
markshad(ip)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
estshad(ip)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
freeshad()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
add(ip)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
indir(d,n,filesize)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
dirdump(ip)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
lf_dumpmeta(ip)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
hasshortmeta(ip)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
lf_dumpinode(ip)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
lf_dump(ip)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
lf_dmpindir(blk,lvl,size)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
lf_blksout(blkp,bytes)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
bitmap(map,typ)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
dsrch(d,size,filesize)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 *
getino(ino)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
bread(da,ba,cnt)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