1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <sys/types.h> 28 #include <sys/param.h> 29 #include <sys/vnode.h> 30 #include <sys/fs/ufs_fsdir.h> 31 #include <sys/fs/ufs_fs.h> 32 #include <sys/fs/ufs_inode.h> 33 #include <sys/sysmacros.h> 34 #include <sys/bootvfs.h> 35 #include <sys/filep.h> 36 37 #ifdef _BOOT 38 #include "../common/util.h" 39 #else 40 #include <sys/sunddi.h> 41 #endif 42 43 extern void *bkmem_alloc(size_t); 44 extern void bkmem_free(void *, size_t); 45 extern int cf_check_compressed(fileid_t *); 46 extern void cf_close(fileid_t *); 47 extern void cf_seek(fileid_t *, off_t, int); 48 extern int cf_read(fileid_t *, caddr_t, size_t); 49 50 int bootrd_debug; 51 #ifdef _BOOT 52 #define dprintf if (bootrd_debug) printf 53 #else 54 #define printf kobj_printf 55 #define dprintf if (bootrd_debug) kobj_printf 56 57 /* PRINTLIKE */ 58 extern void kobj_printf(char *, ...); 59 #endif 60 61 /* 62 * This fd is used when talking to the device file itself. 63 */ 64 static fileid_t *head; 65 66 /* Only got one of these...ergo, only 1 fs open at once */ 67 /* static */ 68 devid_t *ufs_devp; 69 70 struct dirinfo { 71 int loc; 72 fileid_t *fi; 73 }; 74 75 static int bufs_close(int); 76 static void bufs_closeall(int); 77 static ino_t find(fileid_t *filep, char *path); 78 static ino_t dlook(fileid_t *filep, char *path); 79 static daddr32_t sbmap(fileid_t *filep, daddr32_t bn); 80 static struct direct *readdir(struct dirinfo *dstuff); 81 static void set_cache(int, void *, uint_t); 82 static void *get_cache(int); 83 static void free_cache(); 84 85 86 /* 87 * There is only 1 open (mounted) device at any given time. 88 * So we can keep a single, global devp file descriptor to 89 * use to index into the di[] array. This is not true for the 90 * fi[] array. We can have more than one file open at once, 91 * so there is no global fd for the fi[]. 92 * The user program must save the fd passed back from open() 93 * and use it to do subsequent read()'s. 94 */ 95 96 static int 97 openi(fileid_t *filep, ino_t inode) 98 { 99 struct dinode *dp; 100 devid_t *devp = filep->fi_devp; 101 102 filep->fi_inode = get_cache((int)inode); 103 if (filep->fi_inode != 0) 104 return (0); 105 106 filep->fi_offset = 0; 107 filep->fi_blocknum = fsbtodb(&devp->un_fs.di_fs, 108 itod(&devp->un_fs.di_fs, inode)); 109 110 /* never more than 1 disk block */ 111 filep->fi_count = devp->un_fs.di_fs.fs_bsize; 112 filep->fi_memp = 0; /* cached read */ 113 if (diskread(filep) != 0) { 114 return (0); 115 } 116 117 dp = (struct dinode *)filep->fi_memp; 118 filep->fi_inode = (struct inode *) 119 bkmem_alloc(sizeof (struct inode)); 120 bzero((char *)filep->fi_inode, sizeof (struct inode)); 121 filep->fi_inode->i_ic = 122 dp[itoo(&devp->un_fs.di_fs, inode)].di_un.di_icom; 123 filep->fi_inode->i_number = inode; 124 set_cache((int)inode, (void *)filep->fi_inode, sizeof (struct inode)); 125 return (0); 126 } 127 128 static fileid_t * 129 find_fp(int fd) 130 { 131 fileid_t *filep = head; 132 133 if (fd >= 0) { 134 while ((filep = filep->fi_forw) != head) 135 if (fd == filep->fi_filedes) 136 return (filep->fi_taken ? filep : 0); 137 } 138 139 return (0); 140 } 141 142 static ino_t 143 find(fileid_t *filep, char *path) 144 { 145 char *q; 146 char c; 147 ino_t inode; 148 char lpath[MAXPATHLEN]; 149 char *lpathp = lpath; 150 int len, r; 151 devid_t *devp; 152 153 if (path == NULL || *path == '\0') { 154 printf("null path\n"); 155 return ((ino_t)0); 156 } 157 158 dprintf("openi: %s\n", path); 159 160 bzero(lpath, sizeof (lpath)); 161 bcopy(path, lpath, strlen(path)); 162 devp = filep->fi_devp; 163 while (*lpathp) { 164 /* if at the beginning of pathname get root inode */ 165 r = (lpathp == lpath); 166 if (r && openi(filep, (ino_t)UFSROOTINO)) 167 return ((ino_t)0); 168 while (*lpathp == '/') 169 lpathp++; /* skip leading slashes */ 170 q = lpathp; 171 while (*q != '/' && *q != '\0') 172 q++; /* find end of component */ 173 c = *q; 174 *q = '\0'; /* terminate component */ 175 176 /* Bail out early if opening root */ 177 if (r && (*lpathp == '\0')) 178 return ((ino_t)UFSROOTINO); 179 if ((inode = dlook(filep, lpathp)) != 0) { 180 if (openi(filep, inode)) 181 return ((ino_t)0); 182 if ((filep->fi_inode->i_smode & IFMT) == IFLNK) { 183 filep->fi_blocknum = 184 fsbtodb(&devp->un_fs.di_fs, 185 filep->fi_inode->i_db[0]); 186 filep->fi_count = DEV_BSIZE; 187 filep->fi_memp = 0; 188 if (diskread(filep) != 0) 189 return ((ino_t)0); 190 len = strlen(filep->fi_memp); 191 if (filep->fi_memp[0] == '/') 192 /* absolute link */ 193 lpathp = lpath; 194 /* copy rest of unprocessed path up */ 195 bcopy(q, lpathp + len, strlen(q + 1) + 2); 196 /* point to unprocessed path */ 197 *(lpathp + len) = c; 198 /* prepend link in before unprocessed path */ 199 bcopy(filep->fi_memp, lpathp, len); 200 lpathp = lpath; 201 continue; 202 } else 203 *q = c; 204 if (c == '\0') 205 break; 206 lpathp = q; 207 continue; 208 } else { 209 return ((ino_t)0); 210 } 211 } 212 return (inode); 213 } 214 215 static daddr32_t 216 sbmap(fileid_t *filep, daddr32_t bn) 217 { 218 struct inode *inodep; 219 int i, j, sh; 220 daddr32_t nb, *bap; 221 daddr32_t *db; 222 devid_t *devp; 223 224 devp = filep->fi_devp; 225 inodep = filep->fi_inode; 226 db = inodep->i_db; 227 228 /* 229 * blocks 0..NDADDR are direct blocks 230 */ 231 if (bn < NDADDR) { 232 nb = db[bn]; 233 return (nb); 234 } 235 236 /* 237 * addresses NIADDR have single and double indirect blocks. 238 * the first step is to determine how many levels of indirection. 239 */ 240 sh = 1; 241 bn -= NDADDR; 242 for (j = NIADDR; j > 0; j--) { 243 sh *= NINDIR(&devp->un_fs.di_fs); 244 if (bn < sh) 245 break; 246 bn -= sh; 247 } 248 if (j == 0) { 249 return ((daddr32_t)0); 250 } 251 252 /* 253 * fetch the first indirect block address from the inode 254 */ 255 nb = inodep->i_ib[NIADDR - j]; 256 if (nb == 0) { 257 return ((daddr32_t)0); 258 } 259 260 /* 261 * fetch through the indirect blocks 262 */ 263 for (; j <= NIADDR; j++) { 264 filep->fi_blocknum = fsbtodb(&devp->un_fs.di_fs, nb); 265 filep->fi_count = devp->un_fs.di_fs.fs_bsize; 266 filep->fi_memp = 0; 267 if (diskread(filep) != 0) 268 return (0); 269 bap = (daddr32_t *)filep->fi_memp; 270 sh /= NINDIR(&devp->un_fs.di_fs); 271 i = (bn / sh) % NINDIR(&devp->un_fs.di_fs); 272 nb = bap[i]; 273 if (nb == 0) { 274 return ((daddr32_t)0); 275 } 276 } 277 return (nb); 278 } 279 280 static ino_t 281 dlook(fileid_t *filep, char *path) 282 { 283 struct direct *dp; 284 struct inode *ip; 285 struct dirinfo dirp; 286 int len; 287 288 ip = filep->fi_inode; 289 if (path == NULL || *path == '\0') 290 return (0); 291 292 dprintf("dlook: %s\n", path); 293 294 if ((ip->i_smode & IFMT) != IFDIR) { 295 return (0); 296 } 297 if (ip->i_size == 0) { 298 return (0); 299 } 300 len = strlen(path); 301 dirp.loc = 0; 302 dirp.fi = filep; 303 for (dp = readdir(&dirp); dp != NULL; dp = readdir(&dirp)) { 304 if (dp->d_ino == 0) 305 continue; 306 if (dp->d_namlen == len && strcmp(path, dp->d_name) == 0) { 307 return (dp->d_ino); 308 } 309 /* Allow "*" to print all names at that level, w/out match */ 310 if (strcmp(path, "*") == 0) 311 dprintf("%s\n", dp->d_name); 312 } 313 return (0); 314 } 315 316 /* 317 * get next entry in a directory. 318 */ 319 struct direct * 320 readdir(struct dirinfo *dstuff) 321 { 322 struct direct *dp; 323 fileid_t *filep; 324 daddr32_t lbn, d; 325 int off; 326 devid_t *devp; 327 328 filep = dstuff->fi; 329 devp = filep->fi_devp; 330 for (;;) { 331 if (dstuff->loc >= filep->fi_inode->i_size) { 332 return (NULL); 333 } 334 off = blkoff(&devp->un_fs.di_fs, dstuff->loc); 335 dprintf("readdir: off = 0x%x\n", off); 336 if (off == 0) { 337 lbn = lblkno(&devp->un_fs.di_fs, dstuff->loc); 338 d = sbmap(filep, lbn); 339 340 if (d == 0) 341 return (NULL); 342 343 filep->fi_blocknum = fsbtodb(&devp->un_fs.di_fs, d); 344 filep->fi_count = 345 blksize(&devp->un_fs.di_fs, filep->fi_inode, lbn); 346 filep->fi_memp = 0; 347 if (diskread(filep) != 0) { 348 return (NULL); 349 } 350 } 351 dp = (struct direct *)(filep->fi_memp + off); 352 dstuff->loc += dp->d_reclen; 353 if (dp->d_ino == 0) 354 continue; 355 dprintf("readdir: name = %s\n", dp->d_name); 356 return (dp); 357 } 358 } 359 360 /* 361 * Get the next block of data from the file. If possible, dma right into 362 * user's buffer 363 */ 364 static int 365 getblock(fileid_t *filep, caddr_t buf, int count, int *rcount) 366 { 367 struct fs *fs; 368 caddr_t p; 369 int off, size, diff; 370 daddr32_t lbn; 371 devid_t *devp; 372 373 dprintf("getblock: buf 0x%p, count 0x%x\n", (void *)buf, count); 374 375 devp = filep->fi_devp; 376 p = filep->fi_memp; 377 if ((signed)filep->fi_count <= 0) { 378 379 /* find the amt left to be read in the file */ 380 diff = filep->fi_inode->i_size - filep->fi_offset; 381 if (diff <= 0) { 382 printf("Short read\n"); 383 return (-1); 384 } 385 386 fs = &devp->un_fs.di_fs; 387 /* which block (or frag) in the file do we read? */ 388 lbn = lblkno(fs, filep->fi_offset); 389 390 /* which physical block on the device do we read? */ 391 filep->fi_blocknum = fsbtodb(fs, sbmap(filep, lbn)); 392 393 off = blkoff(fs, filep->fi_offset); 394 395 /* either blksize or fragsize */ 396 size = blksize(fs, filep->fi_inode, lbn); 397 filep->fi_count = size; 398 filep->fi_memp = filep->fi_buf; 399 400 /* 401 * optimization if we are reading large blocks of data then 402 * we can go directly to user's buffer 403 */ 404 *rcount = 0; 405 if (off == 0 && count >= size) { 406 filep->fi_memp = buf; 407 if (diskread(filep)) { 408 return (-1); 409 } 410 *rcount = size; 411 filep->fi_count = 0; 412 return (0); 413 } else if (diskread(filep)) 414 return (-1); 415 416 if (filep->fi_offset - off + size >= filep->fi_inode->i_size) 417 filep->fi_count = diff + off; 418 filep->fi_count -= off; 419 p = &filep->fi_memp[off]; 420 } 421 filep->fi_memp = p; 422 return (0); 423 } 424 425 /* 426 * Get the next block of data from the file. Don't attempt to go directly 427 * to user's buffer. 428 */ 429 static int 430 getblock_noopt(fileid_t *filep) 431 { 432 struct fs *fs; 433 caddr_t p; 434 int off, size, diff; 435 daddr32_t lbn; 436 devid_t *devp; 437 438 dprintf("getblock_noopt: start\n"); 439 440 devp = filep->fi_devp; 441 p = filep->fi_memp; 442 if ((signed)filep->fi_count <= 0) { 443 444 /* find the amt left to be read in the file */ 445 diff = filep->fi_inode->i_size - filep->fi_offset; 446 if (diff <= 0) { 447 printf("Short read\n"); 448 return (-1); 449 } 450 451 fs = &devp->un_fs.di_fs; 452 /* which block (or frag) in the file do we read? */ 453 lbn = lblkno(fs, filep->fi_offset); 454 455 /* which physical block on the device do we read? */ 456 filep->fi_blocknum = fsbtodb(fs, sbmap(filep, lbn)); 457 458 off = blkoff(fs, filep->fi_offset); 459 460 /* either blksize or fragsize */ 461 size = blksize(fs, filep->fi_inode, lbn); 462 filep->fi_count = size; 463 /* reading on a ramdisk, just get a pointer to the data */ 464 filep->fi_memp = NULL; 465 466 if (diskread(filep)) 467 return (-1); 468 469 if (filep->fi_offset - off + size >= filep->fi_inode->i_size) 470 filep->fi_count = diff + off; 471 filep->fi_count -= off; 472 p = &filep->fi_memp[off]; 473 } 474 filep->fi_memp = p; 475 return (0); 476 } 477 478 479 /* 480 * This is the high-level read function. It works like this. 481 * We assume that our IO device buffers up some amount of 482 * data and that we can get a ptr to it. Thus we need 483 * to actually call the device func about filesize/blocksize times 484 * and this greatly increases our IO speed. When we already 485 * have data in the buffer, we just return that data (with bcopy() ). 486 */ 487 488 static ssize_t 489 bufs_read(int fd, caddr_t buf, size_t count) 490 { 491 size_t i, j; 492 caddr_t n; 493 int rcount; 494 fileid_t *filep; 495 496 if (!(filep = find_fp(fd))) { 497 return (-1); 498 } 499 500 if ((filep->fi_flags & FI_COMPRESSED) == 0 && 501 filep->fi_offset + count > filep->fi_inode->i_size) 502 count = filep->fi_inode->i_size - filep->fi_offset; 503 504 /* that was easy */ 505 if ((i = count) == 0) 506 return (0); 507 508 n = buf; 509 while (i > 0) { 510 if (filep->fi_flags & FI_COMPRESSED) { 511 if ((j = cf_read(filep, buf, count)) < 0) 512 return (0); /* encountered an error */ 513 if (j < i) 514 i = j; /* short read, must have hit EOF */ 515 } else { 516 /* If we need to reload the buffer, do so */ 517 if ((j = filep->fi_count) == 0) { 518 (void) getblock(filep, buf, i, &rcount); 519 i -= rcount; 520 buf += rcount; 521 filep->fi_offset += rcount; 522 continue; 523 } else { 524 /* else just bcopy from our buffer */ 525 j = MIN(i, j); 526 bcopy(filep->fi_memp, buf, (unsigned)j); 527 } 528 } 529 buf += j; 530 filep->fi_memp += j; 531 filep->fi_offset += j; 532 filep->fi_count -= j; 533 i -= j; 534 } 535 return (buf - n); 536 } 537 538 /* 539 * This routine will open a device as it is known by the V2 OBP. 540 * Interface Defn: 541 * err = mountroot(string); 542 * err = 0 on success 543 * err = -1 on failure 544 * string: char string describing the properties of the device. 545 * We must not dork with any fi[]'s here. Save that for later. 546 */ 547 548 static int 549 bufs_mountroot(char *str) 550 { 551 if (ufs_devp) /* already mounted */ 552 return (0); 553 554 ufs_devp = (devid_t *)bkmem_alloc(sizeof (devid_t)); 555 ufs_devp->di_taken = 1; 556 ufs_devp->di_dcookie = 0; 557 ufs_devp->di_desc = (char *)bkmem_alloc(strlen(str) + 1); 558 (void) strcpy(ufs_devp->di_desc, str); 559 bzero(ufs_devp->un_fs.dummy, SBSIZE); 560 head = (fileid_t *)bkmem_alloc(sizeof (fileid_t)); 561 head->fi_back = head->fi_forw = head; 562 head->fi_filedes = 0; 563 head->fi_taken = 0; 564 565 /* Setup read of the superblock */ 566 head->fi_devp = ufs_devp; 567 head->fi_blocknum = SBLOCK; 568 head->fi_count = (uint_t)SBSIZE; 569 head->fi_memp = (caddr_t)&(ufs_devp->un_fs.di_fs); 570 head->fi_offset = 0; 571 572 if (diskread(head)) { 573 printf("failed to read superblock\n"); 574 (void) bufs_closeall(1); 575 return (-1); 576 } 577 578 if (ufs_devp->un_fs.di_fs.fs_magic != FS_MAGIC) { 579 dprintf("fs magic = 0x%x\n", ufs_devp->un_fs.di_fs.fs_magic); 580 (void) bufs_closeall(1); 581 return (-1); 582 } 583 dprintf("mountroot succeeded\n"); 584 return (0); 585 } 586 587 /* 588 * Unmount the currently mounted root fs. In practice, this means 589 * closing all open files and releasing resources. All of this 590 * is done by closeall(). 591 */ 592 593 static int 594 bufs_unmountroot(void) 595 { 596 if (ufs_devp == NULL) 597 return (-1); 598 599 (void) bufs_closeall(1); 600 601 return (0); 602 } 603 604 /* 605 * We allocate an fd here for use when talking 606 * to the file itself. 607 */ 608 609 /*ARGSUSED*/ 610 static int 611 bufs_open(char *filename, int flags) 612 { 613 fileid_t *filep; 614 ino_t inode; 615 static int filedes = 1; 616 617 dprintf("open: %s\n", filename); 618 619 /* build and link a new file descriptor */ 620 filep = (fileid_t *)bkmem_alloc(sizeof (fileid_t)); 621 filep->fi_back = head->fi_back; 622 filep->fi_forw = head; 623 head->fi_back->fi_forw = filep; 624 head->fi_back = filep; 625 filep->fi_filedes = filedes++; 626 filep->fi_taken = 1; 627 filep->fi_path = (char *)bkmem_alloc(strlen(filename) + 1); 628 (void) strcpy(filep->fi_path, filename); 629 filep->fi_devp = ufs_devp; /* dev is already "mounted" */ 630 filep->fi_inode = NULL; 631 bzero(filep->fi_buf, MAXBSIZE); 632 filep->fi_getblock = getblock_noopt; 633 filep->fi_flags = 0; 634 635 inode = find(filep, (char *)filename); 636 if (inode == (ino_t)0) { 637 dprintf("open: cannot find %s\n", filename); 638 (void) bufs_close(filep->fi_filedes); 639 return (-1); 640 } 641 if (openi(filep, inode)) { 642 printf("open: cannot open %s\n", filename); 643 (void) bufs_close(filep->fi_filedes); 644 return (-1); 645 } 646 647 filep->fi_offset = filep->fi_count = 0; 648 649 if (cf_check_compressed(filep) != 0) 650 return (-1); 651 return (filep->fi_filedes); 652 } 653 654 /* 655 * We don't do any IO here. 656 * We just play games with the device pointers. 657 */ 658 659 static off_t 660 bufs_lseek(int fd, off_t addr, int whence) 661 { 662 fileid_t *filep; 663 664 /* Make sure user knows what file he is talking to */ 665 if (!(filep = find_fp(fd))) 666 return (-1); 667 668 if (filep->fi_flags & FI_COMPRESSED) { 669 cf_seek(filep, addr, whence); 670 } else { 671 switch (whence) { 672 case SEEK_CUR: 673 filep->fi_offset += addr; 674 break; 675 case SEEK_SET: 676 filep->fi_offset = addr; 677 break; 678 default: 679 case SEEK_END: 680 printf("lseek(): invalid whence value %d\n", whence); 681 break; 682 } 683 filep->fi_blocknum = addr / DEV_BSIZE; 684 } 685 686 filep->fi_count = 0; 687 688 return (0); 689 } 690 691 692 int 693 bufs_fstat(int fd, struct bootstat *stp) 694 { 695 fileid_t *filep; 696 struct inode *ip; 697 698 if (!(filep = find_fp(fd))) 699 return (-1); 700 701 ip = filep->fi_inode; 702 703 stp->st_mode = 0; 704 stp->st_size = 0; 705 706 if (ip == NULL) 707 return (0); 708 709 switch (ip->i_smode & IFMT) { 710 case IFLNK: 711 stp->st_mode = S_IFLNK; 712 break; 713 case IFREG: 714 stp->st_mode = S_IFREG; 715 break; 716 default: 717 break; 718 } 719 /* 720 * NOTE: this size will be the compressed size for a compressed file 721 * This could confuse the caller since we decompress the file behind 722 * the scenes when the file is read. 723 */ 724 stp->st_size = ip->i_size; 725 stp->st_atim.tv_sec = ip->i_atime.tv_sec; 726 stp->st_atim.tv_nsec = ip->i_atime.tv_usec * 1000; 727 stp->st_mtim.tv_sec = ip->i_mtime.tv_sec; 728 stp->st_mtim.tv_nsec = ip->i_mtime.tv_usec * 1000; 729 stp->st_ctim.tv_sec = ip->i_ctime.tv_sec; 730 stp->st_ctim.tv_nsec = ip->i_ctime.tv_usec * 1000; 731 732 return (0); 733 } 734 735 736 static int 737 bufs_close(int fd) 738 { 739 fileid_t *filep; 740 741 /* Make sure user knows what file he is talking to */ 742 if (!(filep = find_fp(fd))) 743 return (-1); 744 745 if (filep->fi_taken && (filep != head)) { 746 /* Clear the ranks */ 747 bkmem_free(filep->fi_path, strlen(filep->fi_path)+1); 748 filep->fi_blocknum = filep->fi_count = filep->fi_offset = 0; 749 filep->fi_memp = (caddr_t)0; 750 filep->fi_devp = 0; 751 filep->fi_taken = 0; 752 753 /* unlink and deallocate node */ 754 filep->fi_forw->fi_back = filep->fi_back; 755 filep->fi_back->fi_forw = filep->fi_forw; 756 cf_close(filep); 757 bkmem_free((char *)filep, sizeof (fileid_t)); 758 759 return (0); 760 } else { 761 /* Big problem */ 762 printf("\nFile descrip %d not allocated!", fd); 763 return (-1); 764 } 765 } 766 767 /*ARGSUSED*/ 768 static void 769 bufs_closeall(int flag) 770 { 771 fileid_t *filep = head; 772 773 while ((filep = filep->fi_forw) != head) 774 if (filep->fi_taken) 775 if (bufs_close(filep->fi_filedes)) 776 printf("Filesystem may be inconsistent.\n"); 777 778 ufs_devp->di_taken = 0; 779 bkmem_free((char *)ufs_devp, sizeof (devid_t)); 780 bkmem_free((char *)head, sizeof (fileid_t)); 781 ufs_devp = (devid_t *)NULL; 782 head = (fileid_t *)NULL; 783 free_cache(); 784 } 785 786 static struct cache { 787 struct cache *next; 788 void *data; 789 int key; 790 uint_t size; 791 } *icache; 792 793 void 794 set_cache(int key, void *data, uint_t size) 795 { 796 struct cache *entry = bkmem_alloc(sizeof (*entry)); 797 entry->key = key; 798 entry->data = data; 799 entry->size = size; 800 if (icache) { 801 entry->next = icache; 802 icache = entry; 803 } else { 804 icache = entry; 805 entry->next = 0; 806 } 807 } 808 809 void * 810 get_cache(int key) 811 { 812 struct cache *entry = icache; 813 while (entry) { 814 if (entry->key == key) 815 return (entry->data); 816 entry = entry->next; 817 } 818 return (NULL); 819 } 820 821 void 822 free_cache() 823 { 824 struct cache *next, *entry = icache; 825 while (entry) { 826 next = entry->next; 827 bkmem_free(entry->data, entry->size); 828 bkmem_free(entry, sizeof (*entry)); 829 entry = next; 830 } 831 icache = 0; 832 } 833 834 struct boot_fs_ops bufs_ops = { 835 "boot_ufs", 836 bufs_mountroot, 837 bufs_unmountroot, 838 bufs_open, 839 bufs_close, 840 bufs_read, 841 bufs_lseek, 842 bufs_fstat, 843 NULL 844 }; 845