xref: /illumos-gate/usr/src/common/fs/ufsops.c (revision 44af466baa3420f5636d8d7d1c9279f8bf27ce23)
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