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
openi(fileid_t * filep,ino_t inode)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 *
find_fp(int fd)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
find(fileid_t * filep,char * path)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
sbmap(fileid_t * filep,daddr32_t bn)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
dlook(fileid_t * filep,char * path)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 *
readdir(struct dirinfo * dstuff)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
getblock(fileid_t * filep,caddr_t buf,int count,int * rcount)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
getblock_noopt(fileid_t * filep)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
bufs_read(int fd,caddr_t buf,size_t count)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
bufs_mountroot(char * str)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
bufs_unmountroot(void)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
bufs_open(char * filename,int flags __unused)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
bufs_lseek(int fd,off_t addr,int whence)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
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 kobj_printf("\nFile descrip %d not allocated!", fd);
781 return (-1);
782 }
783 }
784
785 static void
bufs_closeall(int flag __unused)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
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