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