1 /*
2 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5
6 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
7 /* All Rights Reserved */
8
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.
13 */
14
15 #pragma ident "%Z%%M% %I% %E% SMI"
16
17 #include "dump.h"
18 #include <sys/file.h>
19 #include <sys/mman.h>
20
21 #ifdef __STDC__
22 static void lf_dmpindir(daddr32_t, int, u_offset_t *);
23 static void indir(daddr32_t, int, u_offset_t *);
24 static void lf_blksout(daddr32_t *, u_offset_t);
25 static void lf_dumpinode(struct dinode *);
26 static void dsrch(daddr32_t, ulong_t, u_offset_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
35
36 static char msgbuf[256];
37
38 void
39 pass(fn, map)
40 void (*fn)(struct dinode *);
41 uchar_t *map;
42 {
43 int bits;
44 ino_t maxino;
45
46 maxino = (unsigned)(sblock->fs_ipg * sblock->fs_ncg - 1);
47 /*
48 * Handle pass restarts. We don't check for UFSROOTINO just in
49 * case we need to restart on the root inode.
50 */
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++;
57 }
58 bits >>= (ino % NBBY);
59 resetino(ino);
60 goto restart;
61 }
62 while (ino < maxino) {
63 if ((ino % NBBY) == 0) {
64 bits = ~0;
65 if (map != NULL)
66 bits = *map++;
67 }
68 restart:
69 ino++;
70 /*
71 * Ignore any inode less than UFSROOTINO and inodes that
72 * we have already done on a previous pass.
73 */
74 if ((ino >= UFSROOTINO) && (bits & 1)) {
75 /*
76 * The following test is merely an optimization
77 * for common case where "add" will just return.
78 */
79 if (!(fn == add && BIT(ino, nodmap)))
80 (*fn)(getino(ino));
81 }
82 bits >>= 1;
83 }
84 }
85
86 void
mark(ip)87 mark(ip)
88 struct dinode *ip;
89 {
90 int f;
91
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;
97 }
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);
103 }
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;
115 }
116 est(ip);
117 }
118 }
119
120 void
active_mark(ip)121 active_mark(ip)
122 struct dinode *ip;
123 {
124 int f;
125
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;
131 }
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);
137 }
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;
147 }
148 est(ip);
149 }
150 }
151
152 static struct shcount {
153 struct shcount *higher, *lower;
154 ino_t ino;
155 unsigned long count;
156 } shcounts = {
157 NULL, NULL,
158 0,
159 0
160 };
161 static struct shcount *shc = NULL;
162
163 void
markshad(ip)164 markshad(ip)
165 struct dinode *ip;
166 {
167 ino_t shadow;
168
169 if (ip->di_shadow == 0)
170 return;
171 if (shc == NULL)
172 shc = &shcounts;
173
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;
181
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;
190 }
191
192 /* LINTED: 32-bit to 8-bit assignment ok */
193 BIS(shadow, shamap);
194 shc->count++;
195 }
196
197 void
estshad(ip)198 estshad(ip)
199 struct dinode *ip;
200 {
201 u_offset_t esizeprime;
202 u_offset_t tmpesize;
203
204 if (ip->di_size <= sizeof (union u_shadow))
205 return;
206
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? */
213
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;
220 }
221
222 void
freeshad()223 freeshad()
224 {
225 if (shc == NULL)
226 return;
227
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);
234 }
235 /*
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().
238 */
239 bzero(shc, sizeof (*shc));
240 }
241
242 void
add(ip)243 add(ip)
244 struct dinode *ip;
245 {
246 int i;
247 u_offset_t filesize;
248
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;
259 }
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);
269 }
270 for (i = 0; i < NIADDR; i++) {
271 if (ip->di_ib[i] != 0)
272 indir(ip->di_ib[i], i, &filesize);
273 }
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);
282 }
283 est(ip);
284 }
285 }
286 if (nsubdir == 0) {
287 if (!BIT(ino, nodmap)) {
288 /* LINTED: 32-bit to 8-bit assignment ok */
289 BIC(ino, dirmap);
290 }
291 }
292 }
293
294 static void
indir(d,n,filesize)295 indir(d, n, filesize)
296 daddr32_t d;
297 int n;
298 u_offset_t *filesize;
299 {
300 int i;
301 daddr32_t idblk[MAXNINDIR];
302
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*/
308 }
309
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*/
317 }
318
319 if (dadded || *filesize == 0)
320 return;
321
322 #ifdef lint
323 idblk[0] = '\0';
324 #endif /* lint */
325
326 /* xxx sanity check sblock contents before trusting them */
327 bread(fsbtodb(sblock, d), (uchar_t *)idblk, (size_t)sblock->fs_bsize);
328 if (n <= 0) {
329 for (i = 0; i < NINDIR(sblock); i++) {
330 d = idblk[i];
331 if (d != 0)
332 dsrch(d, (ulong_t)(uint32_t)sblock->fs_bsize,
333 *filesize);
334 *filesize -= (unsigned)(sblock->fs_bsize);
335 }
336 } else {
337 n--;
338 for (i = 0; i < NINDIR(sblock); i++) {
339 d = idblk[i];
340 if (d != 0)
341 indir(d, n, filesize);
342 }
343 }
344 }
345
346 void
dirdump(ip)347 dirdump(ip)
348 struct dinode *ip;
349 {
350 /* watchout for dir inodes deleted and maybe reallocated */
351 if (((ip->di_mode & IFMT) != IFDIR &&
352 (ip->di_mode & IFMT) != IFATTRDIR) || ip->di_nlink < 2) {
353 (void) snprintf(msgbuf, sizeof (msgbuf), gettext(
354 "Warning - directory at inode `%lu' vanished!\n"),
355 ino);
356 msg(msgbuf);
357 return;
358 }
359 lf_dump(ip);
360 }
361
362 static u_offset_t loffset; /* current offset in file (ufsdump) */
363
364 static void
lf_dumpmeta(ip)365 lf_dumpmeta(ip)
366 struct dinode *ip;
367 {
368 if ((ip->di_shadow == 0) || shortmeta)
369 return;
370
371 lf_dumpinode(getino((ino_t)(unsigned)(ip->di_shadow)));
372 }
373
374 int
hasshortmeta(ip)375 hasshortmeta(ip)
376 struct dinode **ip;
377 {
378 ino_t savino;
379 int rc;
380
381 if ((*ip)->di_shadow == 0)
382 return (0);
383 savino = ino;
384 *ip = getino((ino_t)(unsigned)((*ip)->di_shadow));
385 rc = ((*ip)->di_size <= sizeof (union u_shadow));
386 *ip = getino(ino = savino);
387 return (rc);
388 }
389
390 void
lf_dumpinode(ip)391 lf_dumpinode(ip)
392 struct dinode *ip;
393 {
394 int i;
395 u_offset_t size;
396
397 i = ip->di_mode & IFMT;
398
399 if (i == 0 || ip->di_nlink <= 0)
400 return;
401
402 spcl.c_dinode = *ip;
403 spcl.c_count = 0;
404
405 if ((i != IFDIR && i != IFATTRDIR && i != IFREG && i != IFLNK &&
406 i != IFSHAD) || ip->di_size == 0) {
407 toslave(dospcl, ino);
408 return;
409 }
410
411 size = NDADDR * (unsigned)(sblock->fs_bsize);
412 if (size > ip->di_size)
413 size = ip->di_size;
414
415 lf_blksout(&ip->di_db[0], size);
416
417 size = ip->di_size - size;
418 if (size > 0) {
419 for (i = 0; i < NIADDR; i++) {
420 lf_dmpindir(ip->di_ib[i], i, &size);
421 if (size == 0)
422 break;
423 }
424 }
425 }
426
427 void
lf_dump(ip)428 lf_dump(ip)
429 struct dinode *ip;
430 {
431
432 if ((!BIT(ino, nodmap)) && (!BIT(ino, shamap)))
433 return;
434
435 shortmeta = hasshortmeta(&ip);
436 if (shortmeta) {
437 ip = getino((ino_t)(unsigned)(ip->di_shadow));
438 /* assume spcl.c_shadow is smaller than 1 block */
439 bread(fsbtodb(sblock, ip->di_db[0]),
440 (uchar_t *)spcl.c_shadow.c_shadow, sizeof (spcl.c_shadow));
441 spcl.c_flags |= DR_HASMETA;
442 } else {
443 spcl.c_flags &= ~DR_HASMETA;
444 }
445 ip = getino(ino);
446
447 loffset = 0;
448
449 if (newtape) {
450 spcl.c_type = TS_TAPE;
451 } else if (pos)
452 spcl.c_type = TS_ADDR;
453 else
454 spcl.c_type = TS_INODE;
455
456 newtape = 0;
457 lf_dumpinode(ip);
458 lf_dumpmeta(ip);
459 pos = 0;
460 }
461
462 static void
lf_dmpindir(blk,lvl,size)463 lf_dmpindir(blk, lvl, size)
464 daddr32_t blk;
465 int lvl;
466 u_offset_t *size;
467 {
468 int i;
469 u_offset_t cnt;
470 daddr32_t idblk[MAXNINDIR];
471
472 if ((unsigned)(sblock->fs_bsize) > sizeof (idblk)) {
473 msg(gettext(
474 "Inconsistency detected: filesystem block size larger than valid maximum.\n"));
475 dumpabort();
476 /*NOTREACHED*/
477 }
478
479 if ((unsigned)NINDIR(sblock) > MAXNINDIR) {
480 msg(gettext(
481 "Inconsistency detected: inode has more indirect \
482 blocks than valid maximum.\n"));
483 dumpabort();
484 /*NOTREACHED*/
485 }
486
487 if (blk != 0)
488 bread(fsbtodb(sblock, blk), (uchar_t *)idblk,
489 (size_t)sblock->fs_bsize);
490 else
491 bzero((char *)idblk, (size_t)sblock->fs_bsize);
492 if (lvl <= 0) {
493 cnt = (u_offset_t)(unsigned)NINDIR(sblock) *
494 (u_offset_t)(unsigned)(sblock->fs_bsize);
495 if (cnt > *size)
496 cnt = *size;
497 *size -= cnt;
498 lf_blksout(&idblk[0], cnt);
499 return;
500 }
501 lvl--;
502 for (i = 0; i < NINDIR(sblock); i++) {
503 lf_dmpindir(idblk[i], lvl, size);
504 if (*size == 0)
505 return;
506 }
507 }
508
509 static void
lf_blksout(blkp,bytes)510 lf_blksout(blkp, bytes)
511 daddr32_t *blkp;
512 u_offset_t bytes;
513 {
514 u_offset_t i;
515 u_offset_t tbperfsb = (unsigned)(sblock->fs_bsize / tp_bsize);
516
517 u_offset_t j, k, count;
518
519 u_offset_t bytepos, diff;
520 u_offset_t bytecnt = 0;
521 off_t byteoff = 0; /* bytes to skip within first f/s block */
522 off_t fragoff = 0; /* frags to skip within first f/s block */
523
524 u_offset_t tpblkoff = 0; /* tape blocks to skip in first f/s block */
525 u_offset_t tpblkskip = 0; /* total tape blocks to skip */
526 u_offset_t skip; /* tape blocks to skip this pass */
527
528 if (pos) {
529 /*
530 * We get here if a slave throws a signal to the
531 * master indicating a partially dumped file.
532 * Begin by figuring out what was undone.
533 */
534 bytepos = (offset_t)pos * tp_bsize;
535
536 if ((loffset + bytes) <= bytepos) {
537 /* This stuff was dumped already, forget it. */
538 loffset += (u_offset_t)tp_bsize *
539 /* LINTED: spurious complaint on sign-extending */
540 d_howmany(bytes, (u_offset_t)tp_bsize);
541 return;
542 }
543
544 if (loffset < bytepos) {
545 /*
546 * Some of this was dumped, some wasn't.
547 * Figure out what was done and skip it.
548 */
549 diff = bytepos - loffset;
550 /* LINTED: spurious complaint on sign-extending */
551 tpblkskip = d_howmany(diff, (u_offset_t)tp_bsize);
552 /* LINTED room after EOT is only a few MB */
553 blkp += (int)(diff / sblock->fs_bsize);
554
555 bytecnt = diff % (unsigned)(sblock->fs_bsize);
556 /* LINTED: result fits, due to modulus */
557 byteoff = bytecnt % (off_t)(sblock->fs_fsize);
558 /* LINTED: spurious complaint on sign-extending */
559 tpblkoff = d_howmany(bytecnt,
560 (u_offset_t)(unsigned)tp_bsize);
561 /* LINTED: result fits, due to modulus */
562 fragoff = bytecnt / (off_t)(sblock->fs_fsize);
563 bytecnt = (unsigned)(sblock->fs_bsize) - bytecnt;
564 }
565 }
566
567 loffset += bytes;
568
569 while (bytes > 0) {
570 if (bytes < TP_NINDIR*tp_bsize)
571 /* LINTED: spurious complaint on sign-extending */
572 count = d_howmany(bytes, (u_offset_t)tp_bsize);
573 else
574 count = TP_NINDIR;
575 if (tpblkskip) {
576 if (tpblkskip < TP_NINDIR) {
577 bytes -= (tpblkskip * (u_offset_t)tp_bsize);
578 skip = tpblkskip;
579 tpblkskip = 0;
580 } else {
581 bytes -= (offset_t)TP_NINDIR*tp_bsize;
582 tpblkskip -= TP_NINDIR;
583 continue;
584 }
585 } else
586 skip = 0;
587 assert(tbperfsb >= tpblkoff);
588 assert((count - skip) <= TP_NINDIR);
589 for (j = 0, k = 0; j < count - skip; j++, k++) {
590 spcl.c_addr[j] = (blkp[k] != 0);
591 for (i = tbperfsb - tpblkoff; --i > 0; j++)
592 spcl.c_addr[j+1] = spcl.c_addr[j];
593 tpblkoff = 0;
594 }
595 /* LINTED (count - skip) will always fit into an int32_t */
596 spcl.c_count = count - skip;
597 toslave(dospcl, ino);
598 bytecnt = MIN(bytes, bytecnt ?
599 bytecnt : (unsigned)(sblock->fs_bsize));
600 j = 0;
601 while (j < count - skip) {
602 if (*blkp != 0) {
603 /* LINTED: fragoff fits into 32 bits */
604 dmpblk(*blkp+(int32_t)fragoff,
605 /* LINTED: bytecnt fits into 32 bits */
606 (size_t)bytecnt, byteoff);
607 }
608 blkp++;
609 bytes -= bytecnt;
610 /* LINTED: spurious complaint on sign-extending */
611 j += d_howmany(bytecnt, (u_offset_t)tp_bsize);
612 bytecnt = MIN(bytes, (unsigned)(sblock->fs_bsize));
613 byteoff = 0;
614 fragoff = 0;
615 }
616 spcl.c_type = TS_ADDR;
617 bytecnt = 0;
618 }
619 pos = 0;
620 }
621
622 void
bitmap(map,typ)623 bitmap(map, typ)
624 uchar_t *map;
625 int typ;
626 {
627 int i;
628 u_offset_t count;
629 uchar_t *cp;
630
631 if (!newtape)
632 spcl.c_type = typ;
633 else
634 newtape = 0;
635 for (i = 0; i < TP_NINDIR; i++)
636 spcl.c_addr[i] = 1;
637 /* LINTED: spurious complaint on sign-extending */
638 count = d_howmany(msiz * sizeof (map[0]), tp_bsize) - pos;
639 for (cp = &map[pos * tp_bsize]; count > 0;
640 count -= (u_offset_t)(unsigned)spcl.c_count) {
641 if (leftover) {
642 spcl.c_count = leftover;
643 leftover = 0;
644 } else {
645 /* LINTED value always less than INT32_MAX */
646 spcl.c_count = count > TP_NINDIR ? TP_NINDIR : count;
647 }
648 spclrec();
649 for (i = 0; i < spcl.c_count; i++, cp += tp_bsize)
650 taprec(cp, 0, tp_bsize);
651 spcl.c_type = TS_ADDR;
652 }
653 }
654
655 static void
dsrch(d,size,filesize)656 dsrch(d, size, filesize)
657 daddr32_t d;
658 ulong_t size; /* block size */
659 u_offset_t filesize;
660 {
661 struct direct *dp;
662 struct dinode *ip;
663 ulong_t loc;
664 char dblk[MAXBSIZE];
665
666 if (dadded || filesize == 0)
667 return;
668 if (filesize > (u_offset_t)size)
669 filesize = (u_offset_t)size;
670 if (sizeof (dblk) < roundup(filesize, DEV_BSIZE)) {
671 msg(gettext(
672 "Inconsistency detected: filesystem block size larger than valid maximum.\n"));
673 dumpabort();
674 /*NOTREACHED*/
675 }
676
677 #ifdef lint
678 dblk[0] = '\0';
679 #endif /* lint */
680
681 /* LINTED ufs disk addresses always fit into 32 bits */
682 bread(fsbtodb(sblock, d), (uchar_t *)dblk,
683 /* LINTED from sizeof check above, roundup() <= max(size_t) */
684 (size_t)(roundup(filesize, DEV_BSIZE)));
685 loc = 0;
686 while ((u_offset_t)loc < filesize) {
687 /*LINTED [dblk is char[], loc (dp->d_reclen) % 4 == 0]*/
688 dp = (struct direct *)(dblk + loc);
689 if (dp->d_reclen == 0) {
690 (void) snprintf(msgbuf, sizeof (msgbuf), gettext(
691 "Warning - directory at inode `%lu' is corrupted\n"),
692 ino);
693 msg(msgbuf);
694 break;
695 }
696 loc += dp->d_reclen;
697 if (dp->d_ino == 0)
698 continue;
699 if (dp->d_name[0] == '.') {
700 if (dp->d_name[1] == '\0') {
701 if ((ino_t)(dp->d_ino) != ino) {
702 (void) snprintf(msgbuf, sizeof (msgbuf),
703 gettext(
704 "Warning - directory at inode `%lu' is corrupted:\n\
705 \t\".\" points to inode `%lu' - run fsck\n"),
706 ino, dp->d_ino);
707 msg(msgbuf);
708 }
709 continue;
710 }
711 if (dp->d_name[1] == '.' && dp->d_name[2] == '\0') {
712 if (!BIT(dp->d_ino, dirmap) &&
713 ((ip = getino(ino)) == NULL ||
714 (ip->di_mode & IFMT) != IFATTRDIR)) {
715 (void) snprintf(msgbuf, sizeof (msgbuf),
716 gettext(
717 "Warning - directory at inode `%lu' is corrupted:\n\
718 \t\"..\" points to non-directory inode `%lu' - run fsck\n"),
719 ino, dp->d_ino);
720 msg(msgbuf);
721 }
722 continue;
723 }
724 }
725 if (BIT(dp->d_ino, nodmap)) {
726 dadded++;
727 return;
728 }
729 if (BIT(dp->d_ino, dirmap))
730 nsubdir++;
731 }
732 }
733
734 #define CACHESIZE 32
735
736 struct dinode *
getino(ino)737 getino(ino)
738 ino_t ino;
739 {
740 static ino_t minino, maxino;
741 static struct dinode itab[MAXINOPB];
742 static struct dinode icache[CACHESIZE];
743 static ino_t icacheval[CACHESIZE], lasti = 0;
744 static int cacheoff = 0;
745 int i;
746
747 if (ino >= minino && ino < maxino) {
748 lasti = ino;
749 return (&itab[ino - minino]);
750 }
751
752 /* before we do major i/o, check for a secondary cache hit */
753 for (i = 0; i < CACHESIZE; i++)
754 if (icacheval[i] == ino)
755 return (icache + i);
756
757 /* we need to do major i/o. throw the last inode retrieved into */
758 /* the cache. note: this copies garbage the first time it is */
759 /* used, but no harm done. */
760 icacheval[cacheoff] = lasti;
761 bcopy(itab + (lasti - minino), icache + cacheoff, sizeof (itab[0]));
762 lasti = ino;
763 if (++cacheoff >= CACHESIZE)
764 cacheoff = 0;
765
766 #define INOPERDB (DEV_BSIZE / sizeof (struct dinode))
767 minino = ino &~ (INOPERDB - 1);
768 maxino = ((itog(sblock, ino) + 1) * (unsigned)(sblock->fs_ipg));
769 if (maxino > minino + MAXINOPB)
770 maxino = minino + MAXINOPB;
771 bread(
772 /* LINTED: can't make up for broken system macros here */
773 (fsbtodb(sblock, itod(sblock, ino)) + itoo(sblock, ino) / INOPERDB),
774 /* LINTED: (max - min) * size fits into a size_t */
775 (uchar_t *)itab, (size_t)((maxino - minino) * sizeof (*itab)));
776 return (&itab[ino - minino]);
777 }
778
779 #define BREADEMAX 32
780
781 #ifdef NO__LONGLONG__
782 #define DEV_LSEEK(fd, offset, whence) \
783 lseek((fd), (((off_t)(offset))*DEV_BSIZE), (whence))
784 #else
785 #define DEV_LSEEK(fd, offset, whence) \
786 llseek((fd), (((offset_t)((offset)))*DEV_BSIZE), (whence))
787 #endif
788
789 #define BREAD_FAIL(buf, size) { \
790 breaderrors += 1; \
791 bzero(buf, (size_t)size); \
792 }
793
794
795
796 void
bread(da,ba,cnt)797 bread(da, ba, cnt)
798 diskaddr_t da;
799 uchar_t *ba;
800 size_t cnt;
801 {
802 caddr_t maddr;
803 uchar_t *dest;
804 int saverr;
805 int n;
806 size_t len;
807 off64_t filoff;
808 off64_t mapoff;
809 off64_t displacement;
810
811 static size_t pagesize = 0;
812 static int breaderrors = 0;
813
814 /* mechanics for caching small bread requests. these are */
815 /* often small ACLs that are used over and over. */
816 static uchar_t bcache[DEV_BSIZE * CACHESIZE];
817 static diskaddr_t bcacheval[CACHESIZE];
818 static int cacheoff = 0;
819 int i;
820
821 if ((cnt >= DEV_BSIZE) && (mapfd != -1)) {
822 if (pagesize == 0)
823 pagesize = getpagesize();
824 /*
825 * We depend on mmap(2)'s guarantee that mapping a
826 * partial page will cause the remainder of the page
827 * to be zero-filled.
828 */
829 filoff = ((off64_t)da) * DEV_BSIZE;
830 displacement = filoff & (pagesize - 1);
831 mapoff = filoff - displacement;
832 /* LINTED offset will fit into 32 bits */
833 len = (size_t)roundup(cnt + (filoff - mapoff), pagesize);
834 maddr = mmap64(NULL, len, PROT_READ, MAP_SHARED, mapfd, mapoff);
835 if (maddr != MAP_FAILED) {
836 (void) memcpy(ba, maddr + displacement, cnt);
837 (void) munmap(maddr, len);
838 return;
839 }
840 }
841
842 if (DEV_LSEEK(fi, da, L_SET) < 0) {
843 saverr = errno;
844 msg(gettext("bread: dev_seek error: %s\n"), strerror(saverr));
845 /* Don't know where we are, return the least-harmful data */
846 BREAD_FAIL(ba, cnt);
847 return;
848 }
849
850 if (read(fi, ba, (size_t)cnt) == (size_t)cnt)
851 return;
852
853 while (cnt != 0) {
854
855 if (da >= fsbtodb(sblock, sblock->fs_size)) {
856 msg(gettext(
857 "Warning - block %llu is beyond the end of `%s'\n"),
858 da, disk);
859 BREAD_FAIL(ba, cnt);
860 break;
861 }
862
863 if (DEV_LSEEK(fi, da, L_SET) < 0) {
864 msg(gettext("%s: %s error\n"), "bread", "DEV_LSEEK2");
865 BREAD_FAIL(ba, cnt);
866 break;
867 }
868
869 if (cnt < DEV_BSIZE) {
870 /* small read. check for cache hit. */
871 for (i = 0; i < CACHESIZE; i++)
872 if (bcacheval[i] == da) {
873 bcopy(bcache + (i * DEV_BSIZE),
874 ba, cnt);
875 return;
876 }
877
878 /* no cache hit; throw this one into the cache... */
879 len = cnt;
880 dest = bcache + (cacheoff * DEV_BSIZE);
881 bcacheval[cacheoff] = da;
882 if (++cacheoff >= CACHESIZE)
883 cacheoff = 0;
884 } else {
885 len = DEV_BSIZE;
886 dest = ba;
887 }
888
889 n = read(fi, dest, DEV_BSIZE);
890 if (n != DEV_BSIZE) {
891 n = MAX(n, 0);
892 bzero(dest+n, DEV_BSIZE-n);
893 breaderrors += 1;
894 msg(gettext(
895 "Warning - cannot read sector %llu of `%s'\n"),
896 da, disk);
897 }
898 if (dest != ba)
899 bcopy(dest, ba, len);
900
901 da++;
902 /* LINTED character pointers aren't signed */
903 ba += len;
904 cnt -= len;
905 }
906
907 if (breaderrors > BREADEMAX) {
908 msg(gettext(
909 "More than %d block read errors from dump device `%s'\n"),
910 BREADEMAX, disk);
911 dumpailing();
912 breaderrors = 0;
913 }
914 }
915