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