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