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
openi(fileid_t * filep,ino_t inode)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 *
find_fp(int fd)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
find(fileid_t * filep,char * path)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
sbmap(fileid_t * filep,daddr32_t bn)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
dlook(fileid_t * filep,char * path)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 *
readdir(struct dirinfo * dstuff)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
getblock(fileid_t * filep,caddr_t buf,int count,int * rcount)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
getblock_noopt(fileid_t * filep)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
bufs_read(int fd,caddr_t buf,size_t count)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
bufs_mountroot(char * str)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
bufs_unmountroot(void)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
bufs_open(char * filename,int flags)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
bufs_lseek(int fd,off_t addr,int whence)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
bufs_fstat(int fd,struct bootstat * stp)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
bufs_close(int fd)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
bufs_closeall(int flag)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
set_cache(int key,void * data,uint_t size)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 *
get_cache(int key)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
free_cache()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