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