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