1 /* 2 * Copyright 1996, 1998, 2001-2003 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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)(((unsigned)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 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