dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / backup / dump / dumptraverse.c
blobac0822365ad52a5c61f82c6c9d7e5635d22bca31
1 /*
2 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
6 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
7 /* All Rights Reserved */
9 /*
10 * Copyright (c) 1980 Regents of the University of California.
11 * All rights reserved. The Berkeley software License Agreement
12 * specifies the terms and conditions for redistribution.
15 #pragma ident "%Z%%M% %I% %E% SMI"
17 #include "dump.h"
18 #include <sys/file.h>
19 #include <sys/mman.h>
21 #ifdef __STDC__
22 static void lf_dmpindir(daddr32_t, int, uoff_t *);
23 static void indir(daddr32_t, int, uoff_t *);
24 static void lf_blksout(daddr32_t *, uoff_t);
25 static void lf_dumpinode(struct dinode *);
26 static void dsrch(daddr32_t, ulong_t, uoff_t);
27 void lf_dump(struct dinode *);
28 #else
29 static void lf_dmpindir();
30 static void indir();
31 static void lf_blksout();
32 static void dsrch();
33 void lf_dump();
34 #endif
36 static char msgbuf[256];
38 void
39 pass(fn, map)
40 void (*fn)(struct dinode *);
41 uchar_t *map;
43 int bits;
44 ino_t maxino;
46 maxino = (unsigned)(sblock->fs_ipg * sblock->fs_ncg - 1);
48 * Handle pass restarts. We don't check for UFSROOTINO just in
49 * case we need to restart on the root inode.
51 if (ino != 0) {
52 bits = ~0;
53 if (map != NULL) {
54 /* LINTED: lint seems to think map is signed */
55 map += (ino / NBBY);
56 bits = *map++;
58 bits >>= (ino % NBBY);
59 resetino(ino);
60 goto restart;
62 while (ino < maxino) {
63 if ((ino % NBBY) == 0) {
64 bits = ~0;
65 if (map != NULL)
66 bits = *map++;
68 restart:
69 ino++;
71 * Ignore any inode less than UFSROOTINO and inodes that
72 * we have already done on a previous pass.
74 if ((ino >= UFSROOTINO) && (bits & 1)) {
76 * The following test is merely an optimization
77 * for common case where "add" will just return.
79 if (!(fn == add && BIT(ino, nodmap)))
80 (*fn)(getino(ino));
82 bits >>= 1;
86 void
87 mark(ip)
88 struct dinode *ip;
90 int f;
92 f = ip->di_mode & IFMT;
93 if (f == 0 || ip->di_nlink <= 0) {
94 /* LINTED: 32-bit to 8-bit assignment ok */
95 BIC(ino, clrmap);
96 return;
98 /* LINTED: 32-bit to 8-bit assignment ok */
99 BIS(ino, clrmap);
100 if (f == IFDIR || f == IFATTRDIR) {
101 /* LINTED: 32-bit to 8-bit assignment ok */
102 BIS(ino, dirmap);
104 if (ip->di_ctime >= spcl.c_ddate) {
105 if (f == IFSHAD)
106 return;
107 /* LINTED: 32-bit to 8-bit assignment ok */
108 BIS(ino, nodmap);
109 /* attribute changes impact the root */
110 if (f == IFATTRDIR)
111 BIS(UFSROOTINO, nodmap);
112 if (f != IFREG && f != IFDIR && f != IFATTRDIR && f != IFLNK) {
113 o_esize += 1;
114 return;
116 est(ip);
120 void
121 active_mark(ip)
122 struct dinode *ip;
124 int f;
126 f = ip->di_mode & IFMT;
127 if (f == 0 || ip->di_nlink <= 0) {
128 /* LINTED: 32-bit to 8-bit assignment ok */
129 BIC(ino, clrmap);
130 return;
132 /* LINTED: 32-bit to 8-bit assignment ok */
133 BIS(ino, clrmap);
134 if (f == IFDIR || f == IFATTRDIR) {
135 /* LINTED: 32-bit to 8-bit assignment ok */
136 BIS(ino, dirmap);
138 if (BIT(ino, activemap)) {
139 /* LINTED: 32-bit to 8-bit assignment ok */
140 BIS(ino, nodmap);
141 /* attribute changes impact the root */
142 if (f == IFATTRDIR)
143 BIS(UFSROOTINO, nodmap);
144 if (f != IFREG && f != IFDIR && f != IFATTRDIR && f != IFLNK) {
145 o_esize += 1;
146 return;
148 est(ip);
152 static struct shcount {
153 struct shcount *higher, *lower;
154 ino_t ino;
155 unsigned long count;
156 } shcounts = {
157 NULL, NULL,
161 static struct shcount *shc = NULL;
163 void
164 markshad(ip)
165 struct dinode *ip;
167 ino_t shadow;
169 if (ip->di_shadow == 0)
170 return;
171 if (shc == NULL)
172 shc = &shcounts;
174 shadow = (ino_t)(unsigned)(ip->di_shadow);
175 while ((shadow > shc->ino) && (shc->higher))
176 shc = shc->higher;
177 while ((shadow < shc->ino) && (shc->lower))
178 shc = shc->lower;
179 if (shadow != shc->ino) {
180 struct shcount *new;
182 new = (struct shcount *)xcalloc(1, sizeof (*new));
183 new->higher = shc->higher;
184 if (shc->higher != NULL)
185 shc->higher->lower = new;
186 shc->higher = new;
187 new->lower = shc;
188 shc = new;
189 shc->ino = shadow;
192 /* LINTED: 32-bit to 8-bit assignment ok */
193 BIS(shadow, shamap);
194 shc->count++;
197 void
198 estshad(ip)
199 struct dinode *ip;
201 uoff_t esizeprime;
202 uoff_t tmpesize;
204 if (ip->di_size <= sizeof (union u_shadow))
205 return;
207 while ((ino > shc->ino) && (shc->higher))
208 shc = shc->higher;
209 while ((ino < shc->ino) && (shc->lower))
210 shc = shc->lower;
211 if (ino != shc->ino)
212 return; /* xxx panic? complain? */
214 tmpesize = (o_esize + f_esize);
215 esizeprime = tmpesize;
216 est(ip);
217 esizeprime = tmpesize - esizeprime;
218 esizeprime *= shc->count - 1;
219 f_esize += esizeprime;
222 void
223 freeshad()
225 if (shc == NULL)
226 return;
228 while (shc->higher)
229 shc = shc->higher;
230 while (shc->lower) {
231 shc = shc->lower;
232 if (shc->higher) /* else panic? */
233 (void) free(shc->higher);
236 * This should be unnecessary, but do it just to be safe.
237 * Note that shc might be malloc'd or static, so can't free().
239 bzero(shc, sizeof (*shc));
242 void
243 add(ip)
244 struct dinode *ip;
246 int i;
247 uoff_t filesize;
249 if (BIT(ino, nodmap))
250 return;
251 if ((ip->di_mode & IFMT) != IFDIR &&
252 (ip->di_mode & IFMT) != IFATTRDIR) {
253 (void) snprintf(msgbuf, sizeof (msgbuf), gettext(
254 "Warning - directory at inode `%lu' vanished!\n"), ino);
255 msg(msgbuf);
256 /* LINTED: 32-bit to 8-bit assignment ok */
257 BIC(ino, dirmap);
258 return;
260 nsubdir = 0;
261 dadded = 0;
262 filesize = ip->di_size;
263 for (i = 0; i < NDADDR; i++) {
264 if (ip->di_db[i] != 0)
265 /* LINTED dblksize/blkoff does a safe cast here */
266 dsrch(ip->di_db[i], (ulong_t)dblksize(sblock, ip, i),
267 filesize);
268 filesize -= (unsigned)(sblock->fs_bsize);
270 for (i = 0; i < NIADDR; i++) {
271 if (ip->di_ib[i] != 0)
272 indir(ip->di_ib[i], i, &filesize);
274 if (dadded) {
275 nadded++;
276 if (!BIT(ino, nodmap)) {
277 /* LINTED: 32-bit to 8-bit assignment ok */
278 BIS(ino, nodmap);
279 if ((ip->di_mode & IFMT) == IFATTRDIR) {
280 /* attribute changes "auto-percolate" to root */
281 BIS(UFSROOTINO, nodmap);
283 est(ip);
286 if (nsubdir == 0) {
287 if (!BIT(ino, nodmap)) {
288 /* LINTED: 32-bit to 8-bit assignment ok */
289 BIC(ino, dirmap);
294 static void
295 indir(d, n, filesize)
296 daddr32_t d;
297 int n;
298 uoff_t *filesize;
300 int i;
301 daddr32_t idblk[MAXNINDIR];
303 if ((unsigned)(sblock->fs_bsize) > sizeof (idblk)) {
304 msg(gettext(
305 "Inconsistency detected: filesystem block size larger than valid maximum.\n"));
306 dumpabort();
307 /*NOTREACHED*/
310 if ((unsigned)NINDIR(sblock) > MAXNINDIR) {
311 /*CSTYLED*/
312 msg(gettext(
313 "Inconsistency detected: inode has more indirect \
314 blocks than valid maximum.\n"));
315 dumpabort();
316 /*NOTREACHED*/
319 if (dadded || *filesize == 0)
320 return;
323 /* xxx sanity check sblock contents before trusting them */
324 bread(fsbtodb(sblock, d), (uchar_t *)idblk, (size_t)sblock->fs_bsize);
325 if (n <= 0) {
326 for (i = 0; i < NINDIR(sblock); i++) {
327 d = idblk[i];
328 if (d != 0)
329 dsrch(d, (ulong_t)(uint32_t)sblock->fs_bsize,
330 *filesize);
331 *filesize -= (unsigned)(sblock->fs_bsize);
333 } else {
334 n--;
335 for (i = 0; i < NINDIR(sblock); i++) {
336 d = idblk[i];
337 if (d != 0)
338 indir(d, n, filesize);
343 void
344 dirdump(ip)
345 struct dinode *ip;
347 /* watchout for dir inodes deleted and maybe reallocated */
348 if (((ip->di_mode & IFMT) != IFDIR &&
349 (ip->di_mode & IFMT) != IFATTRDIR) || ip->di_nlink < 2) {
350 (void) snprintf(msgbuf, sizeof (msgbuf), gettext(
351 "Warning - directory at inode `%lu' vanished!\n"),
352 ino);
353 msg(msgbuf);
354 return;
356 lf_dump(ip);
359 static uoff_t loffset; /* current offset in file (ufsdump) */
361 static void
362 lf_dumpmeta(ip)
363 struct dinode *ip;
365 if ((ip->di_shadow == 0) || shortmeta)
366 return;
368 lf_dumpinode(getino((ino_t)(unsigned)(ip->di_shadow)));
372 hasshortmeta(ip)
373 struct dinode **ip;
375 ino_t savino;
376 int rc;
378 if ((*ip)->di_shadow == 0)
379 return (0);
380 savino = ino;
381 *ip = getino((ino_t)(unsigned)((*ip)->di_shadow));
382 rc = ((*ip)->di_size <= sizeof (union u_shadow));
383 *ip = getino(ino = savino);
384 return (rc);
387 void
388 lf_dumpinode(ip)
389 struct dinode *ip;
391 int i;
392 uoff_t size;
394 i = ip->di_mode & IFMT;
396 if (i == 0 || ip->di_nlink <= 0)
397 return;
399 spcl.c_dinode = *ip;
400 spcl.c_count = 0;
402 if ((i != IFDIR && i != IFATTRDIR && i != IFREG && i != IFLNK &&
403 i != IFSHAD) || ip->di_size == 0) {
404 toslave(dospcl, ino);
405 return;
408 size = NDADDR * (unsigned)(sblock->fs_bsize);
409 if (size > ip->di_size)
410 size = ip->di_size;
412 lf_blksout(&ip->di_db[0], size);
414 size = ip->di_size - size;
415 if (size > 0) {
416 for (i = 0; i < NIADDR; i++) {
417 lf_dmpindir(ip->di_ib[i], i, &size);
418 if (size == 0)
419 break;
424 void
425 lf_dump(ip)
426 struct dinode *ip;
429 if ((!BIT(ino, nodmap)) && (!BIT(ino, shamap)))
430 return;
432 shortmeta = hasshortmeta(&ip);
433 if (shortmeta) {
434 ip = getino((ino_t)(unsigned)(ip->di_shadow));
435 /* assume spcl.c_shadow is smaller than 1 block */
436 bread(fsbtodb(sblock, ip->di_db[0]),
437 (uchar_t *)spcl.c_shadow.c_shadow, sizeof (spcl.c_shadow));
438 spcl.c_flags |= DR_HASMETA;
439 } else {
440 spcl.c_flags &= ~DR_HASMETA;
442 ip = getino(ino);
444 loffset = 0;
446 if (newtape) {
447 spcl.c_type = TS_TAPE;
448 } else if (pos)
449 spcl.c_type = TS_ADDR;
450 else
451 spcl.c_type = TS_INODE;
453 newtape = 0;
454 lf_dumpinode(ip);
455 lf_dumpmeta(ip);
456 pos = 0;
459 static void
460 lf_dmpindir(blk, lvl, size)
461 daddr32_t blk;
462 int lvl;
463 uoff_t *size;
465 int i;
466 uoff_t cnt;
467 daddr32_t idblk[MAXNINDIR];
469 if ((unsigned)(sblock->fs_bsize) > sizeof (idblk)) {
470 msg(gettext(
471 "Inconsistency detected: filesystem block size larger than valid maximum.\n"));
472 dumpabort();
473 /*NOTREACHED*/
476 if ((unsigned)NINDIR(sblock) > MAXNINDIR) {
477 msg(gettext(
478 "Inconsistency detected: inode has more indirect \
479 blocks than valid maximum.\n"));
480 dumpabort();
481 /*NOTREACHED*/
484 if (blk != 0)
485 bread(fsbtodb(sblock, blk), (uchar_t *)idblk,
486 (size_t)sblock->fs_bsize);
487 else
488 bzero((char *)idblk, (size_t)sblock->fs_bsize);
489 if (lvl <= 0) {
490 cnt = (uoff_t)(unsigned)NINDIR(sblock) *
491 (uoff_t)(unsigned)(sblock->fs_bsize);
492 if (cnt > *size)
493 cnt = *size;
494 *size -= cnt;
495 lf_blksout(&idblk[0], cnt);
496 return;
498 lvl--;
499 for (i = 0; i < NINDIR(sblock); i++) {
500 lf_dmpindir(idblk[i], lvl, size);
501 if (*size == 0)
502 return;
506 static void
507 lf_blksout(blkp, bytes)
508 daddr32_t *blkp;
509 uoff_t bytes;
511 uoff_t i;
512 uoff_t tbperfsb = (unsigned)(sblock->fs_bsize / tp_bsize);
514 uoff_t j, k, count;
516 uoff_t bytepos, diff;
517 uoff_t bytecnt = 0;
518 off_t byteoff = 0; /* bytes to skip within first f/s block */
519 off_t fragoff = 0; /* frags to skip within first f/s block */
521 uoff_t tpblkoff = 0; /* tape blocks to skip in first f/s block */
522 uoff_t tpblkskip = 0; /* total tape blocks to skip */
523 uoff_t skip; /* tape blocks to skip this pass */
525 if (pos) {
527 * We get here if a slave throws a signal to the
528 * master indicating a partially dumped file.
529 * Begin by figuring out what was undone.
531 bytepos = (offset_t)pos * tp_bsize;
533 if ((loffset + bytes) <= bytepos) {
534 /* This stuff was dumped already, forget it. */
535 loffset += (uoff_t)tp_bsize *
536 /* LINTED: spurious complaint on sign-extending */
537 d_howmany(bytes, (uoff_t)tp_bsize);
538 return;
541 if (loffset < bytepos) {
543 * Some of this was dumped, some wasn't.
544 * Figure out what was done and skip it.
546 diff = bytepos - loffset;
547 /* LINTED: spurious complaint on sign-extending */
548 tpblkskip = d_howmany(diff, (uoff_t)tp_bsize);
549 /* LINTED room after EOT is only a few MB */
550 blkp += (int)(diff / sblock->fs_bsize);
552 bytecnt = diff % (unsigned)(sblock->fs_bsize);
553 /* LINTED: result fits, due to modulus */
554 byteoff = bytecnt % (off_t)(sblock->fs_fsize);
555 /* LINTED: spurious complaint on sign-extending */
556 tpblkoff = d_howmany(bytecnt,
557 (uoff_t)(unsigned)tp_bsize);
558 /* LINTED: result fits, due to modulus */
559 fragoff = bytecnt / (off_t)(sblock->fs_fsize);
560 bytecnt = (unsigned)(sblock->fs_bsize) - bytecnt;
564 loffset += bytes;
566 while (bytes > 0) {
567 if (bytes < TP_NINDIR*tp_bsize)
568 /* LINTED: spurious complaint on sign-extending */
569 count = d_howmany(bytes, (uoff_t)tp_bsize);
570 else
571 count = TP_NINDIR;
572 if (tpblkskip) {
573 if (tpblkskip < TP_NINDIR) {
574 bytes -= (tpblkskip * (uoff_t)tp_bsize);
575 skip = tpblkskip;
576 tpblkskip = 0;
577 } else {
578 bytes -= (offset_t)TP_NINDIR*tp_bsize;
579 tpblkskip -= TP_NINDIR;
580 continue;
582 } else
583 skip = 0;
584 assert(tbperfsb >= tpblkoff);
585 assert((count - skip) <= TP_NINDIR);
586 for (j = 0, k = 0; j < count - skip; j++, k++) {
587 spcl.c_addr[j] = (blkp[k] != 0);
588 for (i = tbperfsb - tpblkoff; --i > 0; j++)
589 spcl.c_addr[j+1] = spcl.c_addr[j];
590 tpblkoff = 0;
592 /* LINTED (count - skip) will always fit into an int32_t */
593 spcl.c_count = count - skip;
594 toslave(dospcl, ino);
595 bytecnt = MIN(bytes, bytecnt ?
596 bytecnt : (unsigned)(sblock->fs_bsize));
597 j = 0;
598 while (j < count - skip) {
599 if (*blkp != 0) {
600 /* LINTED: fragoff fits into 32 bits */
601 dmpblk(*blkp+(int32_t)fragoff,
602 /* LINTED: bytecnt fits into 32 bits */
603 (size_t)bytecnt, byteoff);
605 blkp++;
606 bytes -= bytecnt;
607 /* LINTED: spurious complaint on sign-extending */
608 j += d_howmany(bytecnt, (uoff_t)tp_bsize);
609 bytecnt = MIN(bytes, (unsigned)(sblock->fs_bsize));
610 byteoff = 0;
611 fragoff = 0;
613 spcl.c_type = TS_ADDR;
614 bytecnt = 0;
616 pos = 0;
619 void
620 bitmap(map, typ)
621 uchar_t *map;
622 int typ;
624 int i;
625 uoff_t count;
626 uchar_t *cp;
628 if (!newtape)
629 spcl.c_type = typ;
630 else
631 newtape = 0;
632 for (i = 0; i < TP_NINDIR; i++)
633 spcl.c_addr[i] = 1;
634 /* LINTED: spurious complaint on sign-extending */
635 count = d_howmany(msiz * sizeof (map[0]), tp_bsize) - pos;
636 for (cp = &map[pos * tp_bsize]; count > 0;
637 count -= (uoff_t)(unsigned)spcl.c_count) {
638 if (leftover) {
639 spcl.c_count = leftover;
640 leftover = 0;
641 } else {
642 /* LINTED value always less than INT32_MAX */
643 spcl.c_count = count > TP_NINDIR ? TP_NINDIR : count;
645 spclrec();
646 for (i = 0; i < spcl.c_count; i++, cp += tp_bsize)
647 taprec(cp, 0, tp_bsize);
648 spcl.c_type = TS_ADDR;
652 static void
653 dsrch(d, size, filesize)
654 daddr32_t d;
655 ulong_t size; /* block size */
656 uoff_t filesize;
658 struct direct *dp;
659 struct dinode *ip;
660 ulong_t loc;
661 char dblk[MAXBSIZE];
663 if (dadded || filesize == 0)
664 return;
665 if (filesize > (uoff_t)size)
666 filesize = (uoff_t)size;
667 if (sizeof (dblk) < roundup(filesize, DEV_BSIZE)) {
668 msg(gettext(
669 "Inconsistency detected: filesystem block size larger than valid maximum.\n"));
670 dumpabort();
671 /*NOTREACHED*/
675 /* LINTED ufs disk addresses always fit into 32 bits */
676 bread(fsbtodb(sblock, d), (uchar_t *)dblk,
677 /* LINTED from sizeof check above, roundup() <= max(size_t) */
678 (size_t)(roundup(filesize, DEV_BSIZE)));
679 loc = 0;
680 while ((uoff_t)loc < filesize) {
681 /*LINTED [dblk is char[], loc (dp->d_reclen) % 4 == 0]*/
682 dp = (struct direct *)(dblk + loc);
683 if (dp->d_reclen == 0) {
684 (void) snprintf(msgbuf, sizeof (msgbuf), gettext(
685 "Warning - directory at inode `%lu' is corrupted\n"),
686 ino);
687 msg(msgbuf);
688 break;
690 loc += dp->d_reclen;
691 if (dp->d_ino == 0)
692 continue;
693 if (dp->d_name[0] == '.') {
694 if (dp->d_name[1] == '\0') {
695 if ((ino_t)(dp->d_ino) != ino) {
696 (void) snprintf(msgbuf, sizeof (msgbuf),
697 gettext(
698 "Warning - directory at inode `%lu' is corrupted:\n\
699 \t\".\" points to inode `%lu' - run fsck\n"),
700 ino, dp->d_ino);
701 msg(msgbuf);
703 continue;
705 if (dp->d_name[1] == '.' && dp->d_name[2] == '\0') {
706 if (!BIT(dp->d_ino, dirmap) &&
707 ((ip = getino(ino)) == NULL ||
708 (ip->di_mode & IFMT) != IFATTRDIR)) {
709 (void) snprintf(msgbuf, sizeof (msgbuf),
710 gettext(
711 "Warning - directory at inode `%lu' is corrupted:\n\
712 \t\"..\" points to non-directory inode `%lu' - run fsck\n"),
713 ino, dp->d_ino);
714 msg(msgbuf);
716 continue;
719 if (BIT(dp->d_ino, nodmap)) {
720 dadded++;
721 return;
723 if (BIT(dp->d_ino, dirmap))
724 nsubdir++;
728 #define CACHESIZE 32
730 struct dinode *
731 getino(ino)
732 ino_t ino;
734 static ino_t minino, maxino;
735 static struct dinode itab[MAXINOPB];
736 static struct dinode icache[CACHESIZE];
737 static ino_t icacheval[CACHESIZE], lasti = 0;
738 static int cacheoff = 0;
739 int i;
741 if (ino >= minino && ino < maxino) {
742 lasti = ino;
743 return (&itab[ino - minino]);
746 /* before we do major i/o, check for a secondary cache hit */
747 for (i = 0; i < CACHESIZE; i++)
748 if (icacheval[i] == ino)
749 return (icache + i);
751 /* we need to do major i/o. throw the last inode retrieved into */
752 /* the cache. note: this copies garbage the first time it is */
753 /* used, but no harm done. */
754 icacheval[cacheoff] = lasti;
755 bcopy(itab + (lasti - minino), icache + cacheoff, sizeof (itab[0]));
756 lasti = ino;
757 if (++cacheoff >= CACHESIZE)
758 cacheoff = 0;
760 #define INOPERDB (DEV_BSIZE / sizeof (struct dinode))
761 minino = ino &~ (INOPERDB - 1);
762 maxino = ((itog(sblock, ino) + 1) * (unsigned)(sblock->fs_ipg));
763 if (maxino > minino + MAXINOPB)
764 maxino = minino + MAXINOPB;
765 bread(
766 /* LINTED: can't make up for broken system macros here */
767 (fsbtodb(sblock, itod(sblock, ino)) + itoo(sblock, ino) / INOPERDB),
768 /* LINTED: (max - min) * size fits into a size_t */
769 (uchar_t *)itab, (size_t)((maxino - minino) * sizeof (*itab)));
770 return (&itab[ino - minino]);
773 #define BREADEMAX 32
775 #ifdef NO__LONGLONG__
776 #define DEV_LSEEK(fd, offset, whence) \
777 lseek((fd), (((off_t)(offset))*DEV_BSIZE), (whence))
778 #else
779 #define DEV_LSEEK(fd, offset, whence) \
780 llseek((fd), (((offset_t)((offset)))*DEV_BSIZE), (whence))
781 #endif
783 #define BREAD_FAIL(buf, size) { \
784 breaderrors += 1; \
785 bzero(buf, (size_t)size); \
790 void
791 bread(da, ba, cnt)
792 diskaddr_t da;
793 uchar_t *ba;
794 size_t cnt;
796 caddr_t maddr;
797 uchar_t *dest;
798 int saverr;
799 int n;
800 size_t len;
801 off64_t filoff;
802 off64_t mapoff;
803 off64_t displacement;
805 static size_t pagesize = 0;
806 static int breaderrors = 0;
808 /* mechanics for caching small bread requests. these are */
809 /* often small ACLs that are used over and over. */
810 static uchar_t bcache[DEV_BSIZE * CACHESIZE];
811 static diskaddr_t bcacheval[CACHESIZE];
812 static int cacheoff = 0;
813 int i;
815 if ((cnt >= DEV_BSIZE) && (mapfd != -1)) {
816 if (pagesize == 0)
817 pagesize = getpagesize();
819 * We depend on mmap(2)'s guarantee that mapping a
820 * partial page will cause the remainder of the page
821 * to be zero-filled.
823 filoff = ((off64_t)da) * DEV_BSIZE;
824 displacement = filoff & (pagesize - 1);
825 mapoff = filoff - displacement;
826 /* LINTED offset will fit into 32 bits */
827 len = (size_t)roundup(cnt + (filoff - mapoff), pagesize);
828 maddr = mmap64(NULL, len, PROT_READ, MAP_SHARED, mapfd, mapoff);
829 if (maddr != MAP_FAILED) {
830 (void) memcpy(ba, maddr + displacement, cnt);
831 (void) munmap(maddr, len);
832 return;
836 if (DEV_LSEEK(fi, da, L_SET) < 0) {
837 saverr = errno;
838 msg(gettext("bread: dev_seek error: %s\n"), strerror(saverr));
839 /* Don't know where we are, return the least-harmful data */
840 BREAD_FAIL(ba, cnt);
841 return;
844 if (read(fi, ba, (size_t)cnt) == (size_t)cnt)
845 return;
847 while (cnt != 0) {
849 if (da >= fsbtodb(sblock, sblock->fs_size)) {
850 msg(gettext(
851 "Warning - block %llu is beyond the end of `%s'\n"),
852 da, disk);
853 BREAD_FAIL(ba, cnt);
854 break;
857 if (DEV_LSEEK(fi, da, L_SET) < 0) {
858 msg(gettext("%s: %s error\n"), "bread", "DEV_LSEEK2");
859 BREAD_FAIL(ba, cnt);
860 break;
863 if (cnt < DEV_BSIZE) {
864 /* small read. check for cache hit. */
865 for (i = 0; i < CACHESIZE; i++)
866 if (bcacheval[i] == da) {
867 bcopy(bcache + (i * DEV_BSIZE),
868 ba, cnt);
869 return;
872 /* no cache hit; throw this one into the cache... */
873 len = cnt;
874 dest = bcache + (cacheoff * DEV_BSIZE);
875 bcacheval[cacheoff] = da;
876 if (++cacheoff >= CACHESIZE)
877 cacheoff = 0;
878 } else {
879 len = DEV_BSIZE;
880 dest = ba;
883 n = read(fi, dest, DEV_BSIZE);
884 if (n != DEV_BSIZE) {
885 n = MAX(n, 0);
886 bzero(dest+n, DEV_BSIZE-n);
887 breaderrors += 1;
888 msg(gettext(
889 "Warning - cannot read sector %llu of `%s'\n"),
890 da, disk);
892 if (dest != ba)
893 bcopy(dest, ba, len);
895 da++;
896 /* LINTED character pointers aren't signed */
897 ba += len;
898 cnt -= len;
901 if (breaderrors > BREADEMAX) {
902 msg(gettext(
903 "More than %d block read errors from dump device `%s'\n"),
904 BREADEMAX, disk);
905 dumpailing();
906 breaderrors = 0;