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 * Copyright 2025 MNX Cloud, Inc. 28 */ 29 30 #include <sys/types.h> 31 #include <sys/param.h> 32 #include <sys/vnode.h> 33 #include <sys/fs/ufs_fsdir.h> 34 #include <sys/fs/ufs_fs.h> 35 #include <sys/fs/ufs_inode.h> 36 #include <sys/sysmacros.h> 37 #include <sys/bootvfs.h> 38 #include <sys/filep.h> 39 #include <sys/kmem.h> 40 #include <sys/kobj.h> 41 #include <sys/sunddi.h> 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 extern int bootrd_debug; 51 52 /* 53 * This fd is used when talking to the device file itself. 54 */ 55 static fileid_t *head; 56 57 /* Only got one of these...ergo, only 1 fs open at once */ 58 /* static */ 59 devid_t *ufs_devp; 60 61 struct dirinfo { 62 int loc; 63 fileid_t *fi; 64 }; 65 66 static int bufs_close(int); 67 static void bufs_closeall(int); 68 static ino_t find(fileid_t *filep, char *path); 69 static ino_t dlook(fileid_t *filep, char *path); 70 static daddr32_t sbmap(fileid_t *filep, daddr32_t bn); 71 static struct direct *readdir(struct dirinfo *dstuff); 72 static void set_cache(int, void *, uint_t); 73 static void *get_cache(int); 74 static void free_cache(); 75 76 77 /* 78 * There is only 1 open (mounted) device at any given time. 79 * So we can keep a single, global devp file descriptor to 80 * use to index into the di[] array. This is not true for the 81 * fi[] array. We can have more than one file open at once, 82 * so there is no global fd for the fi[]. 83 * The user program must save the fd passed back from open() 84 * and use it to do subsequent read()'s. 85 */ 86 87 static int 88 openi(fileid_t *filep, ino_t inode) 89 { 90 struct dinode *dp; 91 devid_t *devp = filep->fi_devp; 92 93 filep->fi_inode = get_cache((int)inode); 94 if (filep->fi_inode != 0) 95 return (0); 96 97 filep->fi_offset = 0; 98 filep->fi_blocknum = fsbtodb(&devp->un_fs.di_fs, 99 itod(&devp->un_fs.di_fs, inode)); 100 101 /* never more than 1 disk block */ 102 filep->fi_count = devp->un_fs.di_fs.fs_bsize; 103 filep->fi_memp = 0; /* cached read */ 104 if (diskread(filep) != 0) { 105 return (0); 106 } 107 108 dp = (struct dinode *)filep->fi_memp; 109 filep->fi_inode = (struct inode *) 110 bkmem_alloc(sizeof (struct inode)); 111 bzero((char *)filep->fi_inode, sizeof (struct inode)); 112 filep->fi_inode->i_ic = 113 dp[itoo(&devp->un_fs.di_fs, inode)].di_un.di_icom; 114 filep->fi_inode->i_number = inode; 115 set_cache((int)inode, (void *)filep->fi_inode, sizeof (struct inode)); 116 return (0); 117 } 118 119 static fileid_t * 120 find_fp(int fd) 121 { 122 fileid_t *filep = head; 123 124 if (fd >= 0) { 125 while ((filep = filep->fi_forw) != head) 126 if (fd == filep->fi_filedes) 127 return (filep->fi_taken ? filep : 0); 128 } 129 130 return (0); 131 } 132 133 static ino_t 134 find(fileid_t *filep, char *path) 135 { 136 char *q; 137 char c; 138 ino_t inode; 139 char lpath[MAXPATHLEN]; 140 char *lpathp = lpath; 141 int len, r; 142 devid_t *devp; 143 144 inode = 0; 145 if (path == NULL || *path == '\0') { 146 kobj_printf("null path\n"); 147 return (inode); 148 } 149 150 if (bootrd_debug) 151 kobj_printf("openi: %s\n", path); 152 153 bzero(lpath, sizeof (lpath)); 154 bcopy(path, lpath, strlen(path)); 155 devp = filep->fi_devp; 156 while (*lpathp) { 157 /* if at the beginning of pathname get root inode */ 158 r = (lpathp == lpath); 159 if (r && openi(filep, (ino_t)UFSROOTINO)) 160 return ((ino_t)0); 161 while (*lpathp == '/') 162 lpathp++; /* skip leading slashes */ 163 q = lpathp; 164 while (*q != '/' && *q != '\0') 165 q++; /* find end of component */ 166 c = *q; 167 *q = '\0'; /* terminate component */ 168 169 /* Bail out early if opening root */ 170 if (r && (*lpathp == '\0')) 171 return ((ino_t)UFSROOTINO); 172 if ((inode = dlook(filep, lpathp)) != 0) { 173 if (openi(filep, inode)) 174 return ((ino_t)0); 175 if ((filep->fi_inode->i_smode & IFMT) == IFLNK) { 176 filep->fi_blocknum = 177 fsbtodb(&devp->un_fs.di_fs, 178 filep->fi_inode->i_db[0]); 179 filep->fi_count = DEV_BSIZE; 180 filep->fi_memp = 0; 181 if (diskread(filep) != 0) 182 return ((ino_t)0); 183 len = strlen(filep->fi_memp); 184 if (filep->fi_memp[0] == '/') 185 /* absolute link */ 186 lpathp = lpath; 187 /* copy rest of unprocessed path up */ 188 bcopy(q, lpathp + len, strlen(q + 1) + 2); 189 /* point to unprocessed path */ 190 *(lpathp + len) = c; 191 /* prepend link in before unprocessed path */ 192 bcopy(filep->fi_memp, lpathp, len); 193 lpathp = lpath; 194 continue; 195 } else 196 *q = c; 197 if (c == '\0') 198 break; 199 lpathp = q; 200 continue; 201 } else { 202 return ((ino_t)0); 203 } 204 } 205 return (inode); 206 } 207 208 static daddr32_t 209 sbmap(fileid_t *filep, daddr32_t bn) 210 { 211 struct inode *inodep; 212 int i, j, sh; 213 daddr32_t nb, *bap; 214 daddr32_t *db; 215 devid_t *devp; 216 217 devp = filep->fi_devp; 218 inodep = filep->fi_inode; 219 db = inodep->i_db; 220 221 /* 222 * blocks 0..NDADDR are direct blocks 223 */ 224 if (bn < NDADDR) { 225 nb = db[bn]; 226 return (nb); 227 } 228 229 /* 230 * addresses NIADDR have single and double indirect blocks. 231 * the first step is to determine how many levels of indirection. 232 */ 233 sh = 1; 234 bn -= NDADDR; 235 for (j = NIADDR; j > 0; j--) { 236 sh *= NINDIR(&devp->un_fs.di_fs); 237 if (bn < sh) 238 break; 239 bn -= sh; 240 } 241 if (j == 0) { 242 return ((daddr32_t)0); 243 } 244 245 /* 246 * fetch the first indirect block address from the inode 247 */ 248 nb = inodep->i_ib[NIADDR - j]; 249 if (nb == 0) { 250 return ((daddr32_t)0); 251 } 252 253 /* 254 * fetch through the indirect blocks 255 */ 256 for (; j <= NIADDR; j++) { 257 filep->fi_blocknum = fsbtodb(&devp->un_fs.di_fs, nb); 258 filep->fi_count = devp->un_fs.di_fs.fs_bsize; 259 filep->fi_memp = 0; 260 if (diskread(filep) != 0) 261 return (0); 262 bap = (daddr32_t *)filep->fi_memp; 263 sh /= NINDIR(&devp->un_fs.di_fs); 264 i = (bn / sh) % NINDIR(&devp->un_fs.di_fs); 265 nb = bap[i]; 266 if (nb == 0) { 267 return ((daddr32_t)0); 268 } 269 } 270 return (nb); 271 } 272 273 static ino_t 274 dlook(fileid_t *filep, char *path) 275 { 276 struct direct *dp; 277 struct inode *ip; 278 struct dirinfo dirp; 279 int len; 280 281 ip = filep->fi_inode; 282 if (path == NULL || *path == '\0') 283 return (0); 284 285 if (bootrd_debug) 286 kobj_printf("dlook: %s\n", path); 287 288 if ((ip->i_smode & IFMT) != IFDIR) { 289 return (0); 290 } 291 if (ip->i_size == 0) { 292 return (0); 293 } 294 len = strlen(path); 295 dirp.loc = 0; 296 dirp.fi = filep; 297 for (dp = readdir(&dirp); dp != NULL; dp = readdir(&dirp)) { 298 if (dp->d_ino == 0) 299 continue; 300 if (dp->d_namlen == len && strcmp(path, dp->d_name) == 0) { 301 return (dp->d_ino); 302 } 303 /* Allow "*" to print all names at that level, w/out match */ 304 if (strcmp(path, "*") == 0 && bootrd_debug) 305 kobj_printf("%s\n", dp->d_name); 306 } 307 return (0); 308 } 309 310 /* 311 * get next entry in a directory. 312 */ 313 struct direct * 314 readdir(struct dirinfo *dstuff) 315 { 316 struct direct *dp; 317 fileid_t *filep; 318 daddr32_t lbn, d; 319 int off; 320 devid_t *devp; 321 322 filep = dstuff->fi; 323 devp = filep->fi_devp; 324 for (;;) { 325 if (dstuff->loc >= filep->fi_inode->i_size) { 326 return (NULL); 327 } 328 off = blkoff(&devp->un_fs.di_fs, dstuff->loc); 329 if (bootrd_debug) 330 kobj_printf("readdir: off = 0x%x\n", off); 331 if (off == 0) { 332 lbn = lblkno(&devp->un_fs.di_fs, dstuff->loc); 333 d = sbmap(filep, lbn); 334 335 if (d == 0) 336 return (NULL); 337 338 filep->fi_blocknum = fsbtodb(&devp->un_fs.di_fs, d); 339 filep->fi_count = 340 blksize(&devp->un_fs.di_fs, filep->fi_inode, lbn); 341 filep->fi_memp = 0; 342 if (diskread(filep) != 0) { 343 return (NULL); 344 } 345 } 346 dp = (struct direct *)(filep->fi_memp + off); 347 dstuff->loc += dp->d_reclen; 348 if (dp->d_ino == 0) 349 continue; 350 if (bootrd_debug) 351 kobj_printf("readdir: name = %s\n", dp->d_name); 352 return (dp); 353 } 354 } 355 356 /* 357 * Get the next block of data from the file. If possible, dma right into 358 * user's buffer 359 */ 360 static int 361 getblock(fileid_t *filep, caddr_t buf, int count, int *rcount) 362 { 363 struct fs *fs; 364 caddr_t p; 365 int off, size, diff; 366 daddr32_t lbn; 367 devid_t *devp; 368 369 if (bootrd_debug) 370 kobj_printf("getblock: buf 0x%p, count 0x%x\n", 371 (void *)buf, count); 372 373 devp = filep->fi_devp; 374 p = filep->fi_memp; 375 if ((signed)filep->fi_count <= 0) { 376 377 /* find the amt left to be read in the file */ 378 diff = filep->fi_inode->i_size - filep->fi_offset; 379 if (diff <= 0) { 380 kobj_printf("Short read\n"); 381 return (-1); 382 } 383 384 fs = &devp->un_fs.di_fs; 385 /* which block (or frag) in the file do we read? */ 386 lbn = lblkno(fs, filep->fi_offset); 387 388 /* which physical block on the device do we read? */ 389 filep->fi_blocknum = fsbtodb(fs, sbmap(filep, lbn)); 390 391 off = blkoff(fs, filep->fi_offset); 392 393 /* either blksize or fragsize */ 394 size = blksize(fs, filep->fi_inode, lbn); 395 filep->fi_count = size; 396 filep->fi_memp = filep->fi_buf; 397 398 /* 399 * optimization if we are reading large blocks of data then 400 * we can go directly to user's buffer 401 */ 402 *rcount = 0; 403 if (off == 0 && count >= size) { 404 filep->fi_memp = buf; 405 if (diskread(filep)) { 406 return (-1); 407 } 408 *rcount = size; 409 filep->fi_count = 0; 410 return (0); 411 } else if (diskread(filep)) 412 return (-1); 413 414 if (filep->fi_offset - off + size >= filep->fi_inode->i_size) 415 filep->fi_count = diff + off; 416 filep->fi_count -= off; 417 p = &filep->fi_memp[off]; 418 } 419 filep->fi_memp = p; 420 return (0); 421 } 422 423 /* 424 * Get the next block of data from the file. Don't attempt to go directly 425 * to user's buffer. 426 */ 427 static int 428 getblock_noopt(fileid_t *filep) 429 { 430 struct fs *fs; 431 caddr_t p; 432 int off, size, diff; 433 daddr32_t lbn; 434 devid_t *devp; 435 436 if (bootrd_debug) 437 kobj_printf("getblock_noopt: start\n"); 438 439 devp = filep->fi_devp; 440 p = filep->fi_memp; 441 if ((signed)filep->fi_count <= 0) { 442 443 /* find the amt left to be read in the file */ 444 diff = filep->fi_inode->i_size - filep->fi_offset; 445 if (diff <= 0) { 446 kobj_printf("Short read\n"); 447 return (-1); 448 } 449 450 fs = &devp->un_fs.di_fs; 451 /* which block (or frag) in the file do we read? */ 452 lbn = lblkno(fs, filep->fi_offset); 453 454 /* which physical block on the device do we read? */ 455 filep->fi_blocknum = fsbtodb(fs, sbmap(filep, lbn)); 456 457 off = blkoff(fs, filep->fi_offset); 458 459 /* either blksize or fragsize */ 460 size = blksize(fs, filep->fi_inode, lbn); 461 filep->fi_count = size; 462 /* reading on a ramdisk, just get a pointer to the data */ 463 filep->fi_memp = NULL; 464 465 if (diskread(filep)) 466 return (-1); 467 468 if (filep->fi_offset - off + size >= filep->fi_inode->i_size) 469 filep->fi_count = diff + off; 470 filep->fi_count -= off; 471 p = &filep->fi_memp[off]; 472 } 473 filep->fi_memp = p; 474 return (0); 475 } 476 477 478 /* 479 * This is the high-level read function. It works like this. 480 * We assume that our IO device buffers up some amount of 481 * data and that we can get a ptr to it. Thus we need 482 * to actually call the device func about filesize/blocksize times 483 * and this greatly increases our IO speed. When we already 484 * have data in the buffer, we just return that data (with bcopy() ). 485 */ 486 487 static ssize_t 488 bufs_read(int fd, caddr_t buf, size_t count) 489 { 490 size_t i, j; 491 caddr_t n; 492 int rcount; 493 fileid_t *filep; 494 495 if (!(filep = find_fp(fd))) { 496 return (-1); 497 } 498 499 if ((filep->fi_flags & FI_COMPRESSED) == 0 && 500 filep->fi_offset + count > filep->fi_inode->i_size) 501 count = filep->fi_inode->i_size - filep->fi_offset; 502 503 /* that was easy */ 504 if ((i = count) == 0) 505 return (0); 506 507 n = buf; 508 while (i > 0) { 509 if (filep->fi_flags & FI_COMPRESSED) { 510 int rval; 511 512 if ((rval = cf_read(filep, buf, count)) < 0) 513 return (0); /* encountered an error */ 514 j = (size_t)rval; 515 if (j < i) 516 i = j; /* short read, must have hit EOF */ 517 } else { 518 /* If we need to reload the buffer, do so */ 519 if ((j = filep->fi_count) == 0) { 520 (void) getblock(filep, buf, i, &rcount); 521 i -= rcount; 522 buf += rcount; 523 filep->fi_offset += rcount; 524 continue; 525 } else { 526 /* else just bcopy from our buffer */ 527 j = MIN(i, j); 528 bcopy(filep->fi_memp, buf, (unsigned)j); 529 } 530 } 531 buf += j; 532 filep->fi_memp += j; 533 filep->fi_offset += j; 534 filep->fi_count -= j; 535 i -= j; 536 } 537 return (buf - n); 538 } 539 540 /* 541 * This routine will open a device as it is known by the V2 OBP. 542 * Interface Defn: 543 * err = mountroot(string); 544 * err = 0 on success 545 * err = -1 on failure 546 * string: char string describing the properties of the device. 547 * We must not dork with any fi[]'s here. Save that for later. 548 */ 549 550 static int 551 bufs_mountroot(char *str) 552 { 553 if (ufs_devp) /* already mounted */ 554 return (0); 555 556 ufs_devp = (devid_t *)bkmem_alloc(sizeof (devid_t)); 557 ufs_devp->di_taken = 1; 558 ufs_devp->di_dcookie = 0; 559 ufs_devp->di_desc = (char *)bkmem_alloc(strlen(str) + 1); 560 (void) strcpy(ufs_devp->di_desc, str); 561 bzero(ufs_devp->un_fs.dummy, SBSIZE); 562 head = (fileid_t *)bkmem_alloc(sizeof (fileid_t)); 563 head->fi_back = head->fi_forw = head; 564 head->fi_filedes = 0; 565 head->fi_taken = 0; 566 567 /* Setup read of the superblock */ 568 head->fi_devp = ufs_devp; 569 head->fi_blocknum = SBLOCK; 570 head->fi_count = (uint_t)SBSIZE; 571 head->fi_memp = (caddr_t)&(ufs_devp->un_fs.di_fs); 572 head->fi_offset = 0; 573 574 if (diskread(head)) { 575 kobj_printf("failed to read superblock\n"); 576 (void) bufs_closeall(1); 577 return (-1); 578 } 579 580 if (ufs_devp->un_fs.di_fs.fs_magic != FS_MAGIC) { 581 if (bootrd_debug) 582 kobj_printf("fs magic = 0x%x\n", 583 ufs_devp->un_fs.di_fs.fs_magic); 584 (void) bufs_closeall(1); 585 return (-1); 586 } 587 if (bootrd_debug) 588 kobj_printf("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 static int 615 bufs_open(char *filename, int flags __unused) 616 { 617 fileid_t *filep; 618 ino_t inode; 619 static int filedes = 1; 620 621 if (bootrd_debug) 622 kobj_printf("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 == 0) { 642 if (bootrd_debug) 643 kobj_printf("open: cannot find %s\n", filename); 644 (void) bufs_close(filep->fi_filedes); 645 return (-1); 646 } 647 if (openi(filep, inode)) { 648 kobj_printf("open: cannot open %s\n", filename); 649 (void) bufs_close(filep->fi_filedes); 650 return (-1); 651 } 652 653 filep->fi_offset = filep->fi_count = 0; 654 655 if (cf_check_compressed(filep) != 0) 656 return (-1); 657 return (filep->fi_filedes); 658 } 659 660 /* 661 * We don't do any IO here. 662 * We just play games with the device pointers. 663 */ 664 665 static off_t 666 bufs_lseek(int fd, off_t addr, int whence) 667 { 668 fileid_t *filep; 669 670 /* Make sure user knows what file they are talking to */ 671 if (!(filep = find_fp(fd))) 672 return (-1); 673 674 if (filep->fi_flags & FI_COMPRESSED) { 675 cf_seek(filep, addr, whence); 676 } else { 677 switch (whence) { 678 case SEEK_CUR: 679 filep->fi_offset += addr; 680 break; 681 case SEEK_SET: 682 filep->fi_offset = addr; 683 break; 684 default: 685 case SEEK_END: 686 kobj_printf("lseek(): invalid whence value %d\n", 687 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 kobj_printf("\nFile descrip %d not allocated!", fd); 781 return (-1); 782 } 783 } 784 785 static void 786 bufs_closeall(int flag __unused) 787 { 788 fileid_t *filep = head; 789 790 while ((filep = filep->fi_forw) != head) 791 if (filep->fi_taken) 792 if (bufs_close(filep->fi_filedes)) 793 kobj_printf( 794 "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 = NULL; 800 head = 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