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