176ca3cb0SRobert Mustacchi /*
276ca3cb0SRobert Mustacchi  * This file and its contents are supplied under the terms of the
376ca3cb0SRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
476ca3cb0SRobert Mustacchi  * You may only use this file in accordance with the terms of version
576ca3cb0SRobert Mustacchi  * 1.0 of the CDDL.
676ca3cb0SRobert Mustacchi  *
776ca3cb0SRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
876ca3cb0SRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
976ca3cb0SRobert Mustacchi  * http://www.illumos.org/license/CDDL.
1076ca3cb0SRobert Mustacchi  */
1176ca3cb0SRobert Mustacchi 
1276ca3cb0SRobert Mustacchi /*
13337260d7SRobert Mustacchi  * Copyright (c) 2015 Joyent, Inc.  All rights reserved.
1476ca3cb0SRobert Mustacchi  */
1576ca3cb0SRobert Mustacchi 
1676ca3cb0SRobert Mustacchi /*
1776ca3cb0SRobert Mustacchi  * bootfs vnode operations
1876ca3cb0SRobert Mustacchi  */
1976ca3cb0SRobert Mustacchi 
2076ca3cb0SRobert Mustacchi #include <sys/types.h>
2176ca3cb0SRobert Mustacchi #include <sys/uio.h>
2276ca3cb0SRobert Mustacchi #include <sys/sunddi.h>
2376ca3cb0SRobert Mustacchi #include <sys/errno.h>
2476ca3cb0SRobert Mustacchi #include <sys/vfs_opreg.h>
2576ca3cb0SRobert Mustacchi #include <sys/vnode.h>
2676ca3cb0SRobert Mustacchi #include <sys/mman.h>
2776ca3cb0SRobert Mustacchi #include <fs/fs_subr.h>
2876ca3cb0SRobert Mustacchi #include <sys/policy.h>
2976ca3cb0SRobert Mustacchi #include <sys/sysmacros.h>
3076ca3cb0SRobert Mustacchi #include <sys/dirent.h>
3176ca3cb0SRobert Mustacchi #include <sys/uio.h>
3276ca3cb0SRobert Mustacchi #include <vm/pvn.h>
3376ca3cb0SRobert Mustacchi #include <vm/hat.h>
3476ca3cb0SRobert Mustacchi #include <vm/seg_map.h>
3576ca3cb0SRobert Mustacchi #include <vm/seg_vn.h>
3676ca3cb0SRobert Mustacchi #include <sys/vmsystm.h>
3776ca3cb0SRobert Mustacchi 
3876ca3cb0SRobert Mustacchi #include <sys/fs/bootfs_impl.h>
3976ca3cb0SRobert Mustacchi 
4076ca3cb0SRobert Mustacchi struct vnodeops *bootfs_vnodeops;
4176ca3cb0SRobert Mustacchi 
4276ca3cb0SRobert Mustacchi /*ARGSUSED*/
4376ca3cb0SRobert Mustacchi static int
bootfs_open(vnode_t ** vpp,int flag,cred_t * cr,caller_context_t * ct)4476ca3cb0SRobert Mustacchi bootfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
4576ca3cb0SRobert Mustacchi {
4676ca3cb0SRobert Mustacchi 	return (0);
4776ca3cb0SRobert Mustacchi }
4876ca3cb0SRobert Mustacchi 
4976ca3cb0SRobert Mustacchi /*ARGSUSED*/
5076ca3cb0SRobert Mustacchi static int
bootfs_close(vnode_t * vp,int flag,int count,offset_t offset,cred_t * cr,caller_context_t * ct)5176ca3cb0SRobert Mustacchi bootfs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
5276ca3cb0SRobert Mustacchi     caller_context_t *ct)
5376ca3cb0SRobert Mustacchi {
5476ca3cb0SRobert Mustacchi 	return (0);
5576ca3cb0SRobert Mustacchi }
5676ca3cb0SRobert Mustacchi 
5776ca3cb0SRobert Mustacchi /*ARGSUSED*/
5876ca3cb0SRobert Mustacchi static int
bootfs_read(vnode_t * vp,struct uio * uiop,int ioflag,cred_t * cr,caller_context_t * ct)5976ca3cb0SRobert Mustacchi bootfs_read(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
6076ca3cb0SRobert Mustacchi     caller_context_t *ct)
6176ca3cb0SRobert Mustacchi {
6276ca3cb0SRobert Mustacchi 	int err;
6376ca3cb0SRobert Mustacchi 	ssize_t sres = uiop->uio_resid;
6476ca3cb0SRobert Mustacchi 	bootfs_node_t *bnp = vp->v_data;
6576ca3cb0SRobert Mustacchi 
6676ca3cb0SRobert Mustacchi 	if (vp->v_type == VDIR)
6776ca3cb0SRobert Mustacchi 		return (EISDIR);
6876ca3cb0SRobert Mustacchi 
6976ca3cb0SRobert Mustacchi 	if (vp->v_type != VREG)
7076ca3cb0SRobert Mustacchi 		return (EINVAL);
7176ca3cb0SRobert Mustacchi 
7276ca3cb0SRobert Mustacchi 	if (uiop->uio_loffset < 0)
7376ca3cb0SRobert Mustacchi 		return (EINVAL);
7476ca3cb0SRobert Mustacchi 
7576ca3cb0SRobert Mustacchi 	if (uiop->uio_loffset >= bnp->bvn_size)
7676ca3cb0SRobert Mustacchi 		return (0);
7776ca3cb0SRobert Mustacchi 
7876ca3cb0SRobert Mustacchi 	err = 0;
7976ca3cb0SRobert Mustacchi 	while (uiop->uio_resid != 0) {
8076ca3cb0SRobert Mustacchi 		caddr_t base;
8176ca3cb0SRobert Mustacchi 		long offset, frem;
8276ca3cb0SRobert Mustacchi 		ulong_t poff, segoff;
8376ca3cb0SRobert Mustacchi 		size_t bytes;
8476ca3cb0SRobert Mustacchi 		int relerr;
8576ca3cb0SRobert Mustacchi 
8676ca3cb0SRobert Mustacchi 		offset = uiop->uio_loffset;
8776ca3cb0SRobert Mustacchi 		poff = offset & PAGEOFFSET;
8876ca3cb0SRobert Mustacchi 		bytes = MIN(PAGESIZE - poff, uiop->uio_resid);
8976ca3cb0SRobert Mustacchi 
9076ca3cb0SRobert Mustacchi 		frem = bnp->bvn_size - offset;
9176ca3cb0SRobert Mustacchi 		if (frem <= 0) {
9276ca3cb0SRobert Mustacchi 			err = 0;
9376ca3cb0SRobert Mustacchi 			break;
9476ca3cb0SRobert Mustacchi 		}
9576ca3cb0SRobert Mustacchi 
9676ca3cb0SRobert Mustacchi 		/* Don't read past EOF */
9776ca3cb0SRobert Mustacchi 		bytes = MIN(bytes, frem);
9876ca3cb0SRobert Mustacchi 
9976ca3cb0SRobert Mustacchi 		/*
10076ca3cb0SRobert Mustacchi 		 * Segmaps are likely larger than our page size, so make sure we
10176ca3cb0SRobert Mustacchi 		 * have the proper offfset into the resulting segmap data.
10276ca3cb0SRobert Mustacchi 		 */
10376ca3cb0SRobert Mustacchi 		segoff = (offset & PAGEMASK) & MAXBOFFSET;
10476ca3cb0SRobert Mustacchi 
10576ca3cb0SRobert Mustacchi 		base = segmap_getmapflt(segkmap, vp, offset & MAXBMASK, bytes,
10676ca3cb0SRobert Mustacchi 		    1, S_READ);
10776ca3cb0SRobert Mustacchi 
10876ca3cb0SRobert Mustacchi 		err = uiomove(base + segoff + poff, bytes, UIO_READ, uiop);
10976ca3cb0SRobert Mustacchi 		relerr = segmap_release(segkmap, base, 0);
11076ca3cb0SRobert Mustacchi 
11176ca3cb0SRobert Mustacchi 		if (err == 0)
11276ca3cb0SRobert Mustacchi 			err = relerr;
11376ca3cb0SRobert Mustacchi 
11476ca3cb0SRobert Mustacchi 		if (err != 0)
11576ca3cb0SRobert Mustacchi 			break;
11676ca3cb0SRobert Mustacchi 	}
11776ca3cb0SRobert Mustacchi 
11876ca3cb0SRobert Mustacchi 	/* Even if we had an error in a partial read, return success */
11976ca3cb0SRobert Mustacchi 	if (uiop->uio_resid > sres)
12076ca3cb0SRobert Mustacchi 		err = 0;
12176ca3cb0SRobert Mustacchi 
12276ca3cb0SRobert Mustacchi 	gethrestime(&bnp->bvn_attr.va_atime);
12376ca3cb0SRobert Mustacchi 
12476ca3cb0SRobert Mustacchi 	return (err);
12576ca3cb0SRobert Mustacchi }
12676ca3cb0SRobert Mustacchi 
12776ca3cb0SRobert Mustacchi /*ARGSUSED*/
12876ca3cb0SRobert Mustacchi static int
bootfs_ioctl(vnode_t * vp,int cmd,intptr_t data,int flag,cred_t * cr,int * rvalp,caller_context_t * ct)12976ca3cb0SRobert Mustacchi bootfs_ioctl(vnode_t *vp, int cmd, intptr_t data, int flag,
13076ca3cb0SRobert Mustacchi     cred_t *cr, int *rvalp, caller_context_t *ct)
13176ca3cb0SRobert Mustacchi {
13276ca3cb0SRobert Mustacchi 	return (ENOTTY);
13376ca3cb0SRobert Mustacchi }
13476ca3cb0SRobert Mustacchi 
13576ca3cb0SRobert Mustacchi /*ARGSUSED*/
13676ca3cb0SRobert Mustacchi static int
bootfs_getattr(vnode_t * vp,vattr_t * vap,int flags,cred_t * cr,caller_context_t * ct)13776ca3cb0SRobert Mustacchi bootfs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
13876ca3cb0SRobert Mustacchi     caller_context_t *ct)
13976ca3cb0SRobert Mustacchi {
14076ca3cb0SRobert Mustacchi 	uint32_t mask;
14176ca3cb0SRobert Mustacchi 	bootfs_node_t *bpn = (bootfs_node_t *)vp->v_data;
14276ca3cb0SRobert Mustacchi 
14376ca3cb0SRobert Mustacchi 	mask = vap->va_mask;
14476ca3cb0SRobert Mustacchi 	bcopy(&bpn->bvn_attr, vap, sizeof (vattr_t));
14576ca3cb0SRobert Mustacchi 	vap->va_mask = mask;
14676ca3cb0SRobert Mustacchi 	return (0);
14776ca3cb0SRobert Mustacchi }
14876ca3cb0SRobert Mustacchi 
14976ca3cb0SRobert Mustacchi /*ARGSUSED*/
15076ca3cb0SRobert Mustacchi static int
bootfs_access(vnode_t * vp,int mode,int flags,cred_t * cr,caller_context_t * ct)15176ca3cb0SRobert Mustacchi bootfs_access(vnode_t *vp, int mode, int flags, cred_t *cr,
15276ca3cb0SRobert Mustacchi     caller_context_t *ct)
15376ca3cb0SRobert Mustacchi {
15476ca3cb0SRobert Mustacchi 	int shift = 0;
15576ca3cb0SRobert Mustacchi 	bootfs_node_t *bpn = (bootfs_node_t *)vp->v_data;
15676ca3cb0SRobert Mustacchi 
15776ca3cb0SRobert Mustacchi 	if (crgetuid(cr) != bpn->bvn_attr.va_uid) {
15876ca3cb0SRobert Mustacchi 		shift += 3;
15976ca3cb0SRobert Mustacchi 		if (groupmember(bpn->bvn_attr.va_gid, cr) == 0)
16076ca3cb0SRobert Mustacchi 			shift += 3;
16176ca3cb0SRobert Mustacchi 	}
16276ca3cb0SRobert Mustacchi 
16376ca3cb0SRobert Mustacchi 	return (secpolicy_vnode_access2(cr, vp, bpn->bvn_attr.va_uid,
16476ca3cb0SRobert Mustacchi 	    bpn->bvn_attr.va_mode << shift, mode));
16576ca3cb0SRobert Mustacchi }
16676ca3cb0SRobert Mustacchi 
16776ca3cb0SRobert Mustacchi /*ARGSUSED*/
16876ca3cb0SRobert Mustacchi static int
bootfs_lookup(vnode_t * dvp,char * nm,vnode_t ** vpp,struct pathname * pnp,int flags,vnode_t * rdir,cred_t * cr,caller_context_t * ct,int * direntflags,pathname_t * realpnp)16976ca3cb0SRobert Mustacchi bootfs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp,
17076ca3cb0SRobert Mustacchi     int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
17176ca3cb0SRobert Mustacchi     int *direntflags, pathname_t *realpnp)
17276ca3cb0SRobert Mustacchi {
17376ca3cb0SRobert Mustacchi 	avl_index_t where;
17476ca3cb0SRobert Mustacchi 	bootfs_node_t sn, *bnp;
17576ca3cb0SRobert Mustacchi 	bootfs_node_t *bpp = (bootfs_node_t *)dvp->v_data;
17676ca3cb0SRobert Mustacchi 
17776ca3cb0SRobert Mustacchi 	if (flags & LOOKUP_XATTR)
17876ca3cb0SRobert Mustacchi 		return (EINVAL);
17976ca3cb0SRobert Mustacchi 
18076ca3cb0SRobert Mustacchi 	if (bpp->bvn_attr.va_type != VDIR)
18176ca3cb0SRobert Mustacchi 		return (ENOTDIR);
18276ca3cb0SRobert Mustacchi 
18376ca3cb0SRobert Mustacchi 	if (*nm == '\0' || strcmp(nm, ".") == 0) {
18476ca3cb0SRobert Mustacchi 		VN_HOLD(dvp);
18576ca3cb0SRobert Mustacchi 		*vpp = dvp;
18676ca3cb0SRobert Mustacchi 		return (0);
18776ca3cb0SRobert Mustacchi 	}
18876ca3cb0SRobert Mustacchi 
18976ca3cb0SRobert Mustacchi 	if (strcmp(nm, "..") == 0) {
19076ca3cb0SRobert Mustacchi 		VN_HOLD(bpp->bvn_parent->bvn_vnp);
19176ca3cb0SRobert Mustacchi 		*vpp = bpp->bvn_parent->bvn_vnp;
19276ca3cb0SRobert Mustacchi 		return (0);
19376ca3cb0SRobert Mustacchi 	}
19476ca3cb0SRobert Mustacchi 
19576ca3cb0SRobert Mustacchi 	sn.bvn_name = nm;
19676ca3cb0SRobert Mustacchi 	bnp = avl_find(&bpp->bvn_dir, &sn, &where);
19776ca3cb0SRobert Mustacchi 	if (bnp == NULL)
19876ca3cb0SRobert Mustacchi 		return (ENOENT);
19976ca3cb0SRobert Mustacchi 
20076ca3cb0SRobert Mustacchi 	VN_HOLD(bnp->bvn_vnp);
20176ca3cb0SRobert Mustacchi 	*vpp = bnp->bvn_vnp;
20276ca3cb0SRobert Mustacchi 	return (0);
20376ca3cb0SRobert Mustacchi }
20476ca3cb0SRobert Mustacchi 
20576ca3cb0SRobert Mustacchi /*ARGSUSED*/
20676ca3cb0SRobert Mustacchi static int
bootfs_readdir(vnode_t * vp,struct uio * uiop,cred_t * cr,int * eofp,caller_context_t * ct,int flags)20776ca3cb0SRobert Mustacchi bootfs_readdir(vnode_t *vp, struct uio *uiop, cred_t *cr, int *eofp,
20876ca3cb0SRobert Mustacchi     caller_context_t *ct, int flags)
20976ca3cb0SRobert Mustacchi {
21076ca3cb0SRobert Mustacchi 	bootfs_node_t *bnp = (bootfs_node_t *)vp->v_data;
21176ca3cb0SRobert Mustacchi 	dirent64_t *dp;
21276ca3cb0SRobert Mustacchi 	void *buf;
21376ca3cb0SRobert Mustacchi 	ulong_t bsize, brem;
21476ca3cb0SRobert Mustacchi 	offset_t coff, roff;
21576ca3cb0SRobert Mustacchi 	int dlen, ret;
21676ca3cb0SRobert Mustacchi 	bootfs_node_t *dnp;
21776ca3cb0SRobert Mustacchi 	boolean_t first = B_TRUE;
21876ca3cb0SRobert Mustacchi 
21976ca3cb0SRobert Mustacchi 	if (uiop->uio_loffset >= MAXOFF_T) {
22076ca3cb0SRobert Mustacchi 		if (eofp != NULL)
22176ca3cb0SRobert Mustacchi 			*eofp = 1;
22276ca3cb0SRobert Mustacchi 		return (0);
22376ca3cb0SRobert Mustacchi 	}
22476ca3cb0SRobert Mustacchi 
22576ca3cb0SRobert Mustacchi 	if (uiop->uio_iovcnt != 1)
22676ca3cb0SRobert Mustacchi 		return (EINVAL);
22776ca3cb0SRobert Mustacchi 
22876ca3cb0SRobert Mustacchi 	if (!(uiop->uio_iov->iov_len > 0))
22976ca3cb0SRobert Mustacchi 		return (EINVAL);
23076ca3cb0SRobert Mustacchi 
23176ca3cb0SRobert Mustacchi 	if (vp->v_type != VDIR)
23276ca3cb0SRobert Mustacchi 		return (ENOTDIR);
23376ca3cb0SRobert Mustacchi 
23476ca3cb0SRobert Mustacchi 	roff = uiop->uio_loffset;
23576ca3cb0SRobert Mustacchi 	coff = 0;
23676ca3cb0SRobert Mustacchi 	brem = bsize = uiop->uio_iov->iov_len;
23776ca3cb0SRobert Mustacchi 	buf = kmem_alloc(bsize, KM_SLEEP);
23876ca3cb0SRobert Mustacchi 	dp = buf;
23976ca3cb0SRobert Mustacchi 
24076ca3cb0SRobert Mustacchi 	/*
24176ca3cb0SRobert Mustacchi 	 * Recall that offsets here are done based on the name of the dirent
24276ca3cb0SRobert Mustacchi 	 * excluding the null terminator. Therefore `.` is always at 0, `..` is
24376ca3cb0SRobert Mustacchi 	 * always at 1, and then the first real dirent is at 3. This offset is
24476ca3cb0SRobert Mustacchi 	 * what's actually stored when we update the offset in the structure.
24576ca3cb0SRobert Mustacchi 	 */
24676ca3cb0SRobert Mustacchi 	if (roff == 0) {
24776ca3cb0SRobert Mustacchi 		dlen = DIRENT64_RECLEN(1);
24876ca3cb0SRobert Mustacchi 		if (first == B_TRUE) {
24976ca3cb0SRobert Mustacchi 			if (dlen > brem) {
25076ca3cb0SRobert Mustacchi 				kmem_free(buf, bsize);
25176ca3cb0SRobert Mustacchi 				return (EINVAL);
25276ca3cb0SRobert Mustacchi 			}
25376ca3cb0SRobert Mustacchi 			first = B_FALSE;
25476ca3cb0SRobert Mustacchi 		}
25576ca3cb0SRobert Mustacchi 		dp->d_ino = (ino64_t)bnp->bvn_attr.va_nodeid;
25676ca3cb0SRobert Mustacchi 		dp->d_off = 0;
25776ca3cb0SRobert Mustacchi 		dp->d_reclen = (ushort_t)dlen;
25876ca3cb0SRobert Mustacchi 		(void) strncpy(dp->d_name, ".", DIRENT64_NAMELEN(dlen));
25976ca3cb0SRobert Mustacchi 		dp = (struct dirent64 *)((uintptr_t)dp + dp->d_reclen);
26076ca3cb0SRobert Mustacchi 		brem -= dlen;
26176ca3cb0SRobert Mustacchi 	}
26276ca3cb0SRobert Mustacchi 
26376ca3cb0SRobert Mustacchi 	if (roff <= 1) {
26476ca3cb0SRobert Mustacchi 		dlen = DIRENT64_RECLEN(2);
26576ca3cb0SRobert Mustacchi 		if (first == B_TRUE) {
26676ca3cb0SRobert Mustacchi 			if (dlen > brem) {
26776ca3cb0SRobert Mustacchi 				kmem_free(buf, bsize);
26876ca3cb0SRobert Mustacchi 				return (EINVAL);
26976ca3cb0SRobert Mustacchi 			}
27076ca3cb0SRobert Mustacchi 			first = B_FALSE;
27176ca3cb0SRobert Mustacchi 		}
27276ca3cb0SRobert Mustacchi 		dp->d_ino = (ino64_t)bnp->bvn_parent->bvn_attr.va_nodeid;
27376ca3cb0SRobert Mustacchi 		dp->d_off = 1;
27476ca3cb0SRobert Mustacchi 		dp->d_reclen = (ushort_t)dlen;
27576ca3cb0SRobert Mustacchi 		(void) strncpy(dp->d_name, "..", DIRENT64_NAMELEN(dlen));
27676ca3cb0SRobert Mustacchi 		dp = (struct dirent64 *)((uintptr_t)dp + dp->d_reclen);
27776ca3cb0SRobert Mustacchi 		brem -= dlen;
27876ca3cb0SRobert Mustacchi 	}
27976ca3cb0SRobert Mustacchi 
28076ca3cb0SRobert Mustacchi 	coff = 3;
28176ca3cb0SRobert Mustacchi 	for (dnp = avl_first(&bnp->bvn_dir); dnp != NULL;
28276ca3cb0SRobert Mustacchi 	    dnp = AVL_NEXT(&bnp->bvn_dir, dnp)) {
28376ca3cb0SRobert Mustacchi 		size_t nlen = strlen(dnp->bvn_name);
28476ca3cb0SRobert Mustacchi 
28576ca3cb0SRobert Mustacchi 		if (roff > coff) {
28676ca3cb0SRobert Mustacchi 			coff += nlen;
28776ca3cb0SRobert Mustacchi 			continue;
28876ca3cb0SRobert Mustacchi 		}
28976ca3cb0SRobert Mustacchi 
29076ca3cb0SRobert Mustacchi 		dlen = DIRENT64_RECLEN(nlen);
29176ca3cb0SRobert Mustacchi 		if (dlen > brem) {
29276ca3cb0SRobert Mustacchi 			if (first == B_TRUE) {
29376ca3cb0SRobert Mustacchi 				kmem_free(buf, bsize);
29476ca3cb0SRobert Mustacchi 				return (EINVAL);
29576ca3cb0SRobert Mustacchi 			}
29676ca3cb0SRobert Mustacchi 			break;
29776ca3cb0SRobert Mustacchi 		}
29876ca3cb0SRobert Mustacchi 		first = B_FALSE;
29976ca3cb0SRobert Mustacchi 
30076ca3cb0SRobert Mustacchi 		dp->d_ino = (ino64_t)dnp->bvn_attr.va_nodeid;
30176ca3cb0SRobert Mustacchi 		dp->d_off = coff;
30276ca3cb0SRobert Mustacchi 		dp->d_reclen = (ushort_t)dlen;
30376ca3cb0SRobert Mustacchi 		(void) strncpy(dp->d_name, dnp->bvn_name,
30476ca3cb0SRobert Mustacchi 		    DIRENT64_NAMELEN(dlen));
30576ca3cb0SRobert Mustacchi 		dp = (struct dirent64 *)((uintptr_t)dp + dp->d_reclen);
30676ca3cb0SRobert Mustacchi 		brem -= dlen;
30776ca3cb0SRobert Mustacchi 		coff += nlen;
30876ca3cb0SRobert Mustacchi 	}
30976ca3cb0SRobert Mustacchi 
31076ca3cb0SRobert Mustacchi 	ret = uiomove(buf, (bsize - brem), UIO_READ, uiop);
31176ca3cb0SRobert Mustacchi 
31276ca3cb0SRobert Mustacchi 	if (ret == 0) {
31376ca3cb0SRobert Mustacchi 		if (dnp == NULL) {
31476ca3cb0SRobert Mustacchi 			coff++;
31576ca3cb0SRobert Mustacchi 			if (eofp != NULL)
31676ca3cb0SRobert Mustacchi 				*eofp = 1;
31776ca3cb0SRobert Mustacchi 		} else if (eofp != NULL) {
31876ca3cb0SRobert Mustacchi 			*eofp = 0;
31976ca3cb0SRobert Mustacchi 		}
32076ca3cb0SRobert Mustacchi 		uiop->uio_loffset = coff;
32176ca3cb0SRobert Mustacchi 	}
32276ca3cb0SRobert Mustacchi 	gethrestime(&bnp->bvn_attr.va_atime);
32376ca3cb0SRobert Mustacchi 	kmem_free(buf, bsize);
32476ca3cb0SRobert Mustacchi 	return (ret);
32576ca3cb0SRobert Mustacchi }
32676ca3cb0SRobert Mustacchi 
32776ca3cb0SRobert Mustacchi /*ARGSUSED*/
32876ca3cb0SRobert Mustacchi static void
bootfs_inactive(vnode_t * vp,cred_t * cr,caller_context_t * ct)32976ca3cb0SRobert Mustacchi bootfs_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
33076ca3cb0SRobert Mustacchi {
33176ca3cb0SRobert Mustacchi }
33276ca3cb0SRobert Mustacchi 
33376ca3cb0SRobert Mustacchi /*ARGSUSED*/
33476ca3cb0SRobert Mustacchi static int
bootfs_rwlock(vnode_t * vp,int write_lock,caller_context_t * ct)33576ca3cb0SRobert Mustacchi bootfs_rwlock(vnode_t *vp, int write_lock, caller_context_t *ct)
33676ca3cb0SRobert Mustacchi {
33776ca3cb0SRobert Mustacchi 	if (write_lock != 0)
33876ca3cb0SRobert Mustacchi 		return (EINVAL);
33976ca3cb0SRobert Mustacchi 	return (0);
34076ca3cb0SRobert Mustacchi }
34176ca3cb0SRobert Mustacchi 
34276ca3cb0SRobert Mustacchi /*ARGSUSED*/
34376ca3cb0SRobert Mustacchi static void
bootfs_rwunlock(vnode_t * vp,int write_lock,caller_context_t * ct)34476ca3cb0SRobert Mustacchi bootfs_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ct)
34576ca3cb0SRobert Mustacchi {
34676ca3cb0SRobert Mustacchi }
34776ca3cb0SRobert Mustacchi 
34876ca3cb0SRobert Mustacchi /*ARGSUSED*/
34976ca3cb0SRobert Mustacchi static int
bootfs_seek(vnode_t * vp,offset_t ooff,offset_t * noffp,caller_context_t * ct)35076ca3cb0SRobert Mustacchi bootfs_seek(vnode_t *vp, offset_t ooff, offset_t *noffp,
35176ca3cb0SRobert Mustacchi     caller_context_t *ct)
35276ca3cb0SRobert Mustacchi {
35376ca3cb0SRobert Mustacchi 	bootfs_node_t *bnp = (bootfs_node_t *)vp->v_data;
35476ca3cb0SRobert Mustacchi 	if (vp->v_type == VDIR)
35576ca3cb0SRobert Mustacchi 		return (0);
35676ca3cb0SRobert Mustacchi 	return ((*noffp < 0 || *noffp > bnp->bvn_size ? EINVAL : 0));
35776ca3cb0SRobert Mustacchi }
35876ca3cb0SRobert Mustacchi 
35976ca3cb0SRobert Mustacchi /*
36076ca3cb0SRobert Mustacchi  * We need to fill in a single page of a vnode's memory based on the actual data
36176ca3cb0SRobert Mustacchi  * from the kernel. We'll use this node's sliding window into physical memory
36276ca3cb0SRobert Mustacchi  * and update one page at a time.
36376ca3cb0SRobert Mustacchi  */
36476ca3cb0SRobert Mustacchi /*ARGSUSED*/
36576ca3cb0SRobert Mustacchi static int
bootfs_getapage(vnode_t * vp,u_offset_t off,size_t len,uint_t * protp,page_t * pl[],size_t plsz,struct seg * seg,caddr_t addr,enum seg_rw rw,cred_t * cr)36676ca3cb0SRobert Mustacchi bootfs_getapage(vnode_t *vp, u_offset_t off, size_t len, uint_t *protp,
36776ca3cb0SRobert Mustacchi     page_t *pl[], size_t plsz, struct seg *seg, caddr_t addr, enum seg_rw rw,
36876ca3cb0SRobert Mustacchi     cred_t *cr)
36976ca3cb0SRobert Mustacchi {
37076ca3cb0SRobert Mustacchi 	bootfs_node_t *bnp = vp->v_data;
37176ca3cb0SRobert Mustacchi 	page_t *pp, *fpp;
37276ca3cb0SRobert Mustacchi 	pfn_t pfn;
37376ca3cb0SRobert Mustacchi 
37476ca3cb0SRobert Mustacchi 	for (;;) {
37576ca3cb0SRobert Mustacchi 		/* Easy case where the page exists */
37676ca3cb0SRobert Mustacchi 		pp = page_lookup(vp, off, rw == S_CREATE ? SE_EXCL : SE_SHARED);
37776ca3cb0SRobert Mustacchi 		if (pp != NULL) {
37876ca3cb0SRobert Mustacchi 			if (pl != NULL) {
37976ca3cb0SRobert Mustacchi 				pl[0] = pp;
38076ca3cb0SRobert Mustacchi 				pl[1] = NULL;
38176ca3cb0SRobert Mustacchi 			} else {
38276ca3cb0SRobert Mustacchi 				page_unlock(pp);
38376ca3cb0SRobert Mustacchi 			}
38476ca3cb0SRobert Mustacchi 			return (0);
38576ca3cb0SRobert Mustacchi 		}
38676ca3cb0SRobert Mustacchi 
38776ca3cb0SRobert Mustacchi 		pp = page_create_va(vp, off, PAGESIZE, PG_EXCL | PG_WAIT, seg,
38876ca3cb0SRobert Mustacchi 		    addr);
38976ca3cb0SRobert Mustacchi 
39076ca3cb0SRobert Mustacchi 		/*
39176ca3cb0SRobert Mustacchi 		 * If we didn't get the page, that means someone else beat us to
39276ca3cb0SRobert Mustacchi 		 * creating this so we need to try again.
39376ca3cb0SRobert Mustacchi 		 */
39476ca3cb0SRobert Mustacchi 		if (pp != NULL)
39576ca3cb0SRobert Mustacchi 			break;
39676ca3cb0SRobert Mustacchi 	}
39776ca3cb0SRobert Mustacchi 
39876ca3cb0SRobert Mustacchi 	pfn = btop((bnp->bvn_addr + off) & PAGEMASK);
39976ca3cb0SRobert Mustacchi 	fpp = page_numtopp_nolock(pfn);
40076ca3cb0SRobert Mustacchi 
40176ca3cb0SRobert Mustacchi 	if (ppcopy(fpp, pp) == 0) {
40276ca3cb0SRobert Mustacchi 		pvn_read_done(pp, B_ERROR);
40376ca3cb0SRobert Mustacchi 		return (EIO);
40476ca3cb0SRobert Mustacchi 	}
40576ca3cb0SRobert Mustacchi 
40676ca3cb0SRobert Mustacchi 	if (pl != NULL) {
40776ca3cb0SRobert Mustacchi 		pvn_plist_init(pp, pl, plsz, off, PAGESIZE, rw);
40876ca3cb0SRobert Mustacchi 	} else {
40976ca3cb0SRobert Mustacchi 		pvn_io_done(pp);
41076ca3cb0SRobert Mustacchi 	}
41176ca3cb0SRobert Mustacchi 
41276ca3cb0SRobert Mustacchi 	return (0);
41376ca3cb0SRobert Mustacchi }
41476ca3cb0SRobert Mustacchi 
41576ca3cb0SRobert Mustacchi /*ARGSUSED*/
41676ca3cb0SRobert Mustacchi static int
bootfs_getpage(vnode_t * vp,offset_t off,size_t len,uint_t * protp,page_t * pl[],size_t plsz,struct seg * seg,caddr_t addr,enum seg_rw rw,cred_t * cr,caller_context_t * ct)41776ca3cb0SRobert Mustacchi bootfs_getpage(vnode_t *vp, offset_t off, size_t len, uint_t *protp,
41876ca3cb0SRobert Mustacchi     page_t *pl[], size_t plsz, struct seg *seg, caddr_t addr, enum seg_rw rw,
41976ca3cb0SRobert Mustacchi     cred_t *cr, caller_context_t *ct)
42076ca3cb0SRobert Mustacchi {
42176ca3cb0SRobert Mustacchi 	int err;
42276ca3cb0SRobert Mustacchi 	bootfs_node_t *bnp = vp->v_data;
42376ca3cb0SRobert Mustacchi 
42476ca3cb0SRobert Mustacchi 	if (off + len > bnp->bvn_size + PAGEOFFSET)
42576ca3cb0SRobert Mustacchi 		return (EFAULT);
42676ca3cb0SRobert Mustacchi 
427337260d7SRobert Mustacchi 	if (protp != NULL)
428337260d7SRobert Mustacchi 		*protp = PROT_ALL;
429337260d7SRobert Mustacchi 
43076ca3cb0SRobert Mustacchi 	if (len <= PAGESIZE)
43176ca3cb0SRobert Mustacchi 		err = bootfs_getapage(vp, (u_offset_t)off, len, protp, pl,
43276ca3cb0SRobert Mustacchi 		    plsz, seg, addr, rw, cr);
43376ca3cb0SRobert Mustacchi 	else
43476ca3cb0SRobert Mustacchi 		err = pvn_getpages(bootfs_getapage, vp, (u_offset_t)off, len,
43576ca3cb0SRobert Mustacchi 		    protp, pl, plsz, seg, addr, rw, cr);
43676ca3cb0SRobert Mustacchi 
43776ca3cb0SRobert Mustacchi 	return (err);
43876ca3cb0SRobert Mustacchi }
43976ca3cb0SRobert Mustacchi 
44076ca3cb0SRobert Mustacchi /*ARGSUSED*/
44176ca3cb0SRobert Mustacchi static int
bootfs_map(vnode_t * vp,offset_t off,struct as * as,caddr_t * addrp,size_t len,uchar_t prot,uchar_t maxprot,uint_t flags,cred_t * cr,caller_context_t * ct)44276ca3cb0SRobert Mustacchi bootfs_map(vnode_t *vp, offset_t off, struct as *as, caddr_t *addrp,
44376ca3cb0SRobert Mustacchi     size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cr,
44476ca3cb0SRobert Mustacchi     caller_context_t *ct)
44576ca3cb0SRobert Mustacchi {
44676ca3cb0SRobert Mustacchi 	int ret;
44776ca3cb0SRobert Mustacchi 	segvn_crargs_t vn_a;
44876ca3cb0SRobert Mustacchi 
44976ca3cb0SRobert Mustacchi #ifdef	_ILP32
45076ca3cb0SRobert Mustacchi 	if (len > MAXOFF_T)
45176ca3cb0SRobert Mustacchi 		return (ENOMEM);
45276ca3cb0SRobert Mustacchi #endif
45376ca3cb0SRobert Mustacchi 
45476ca3cb0SRobert Mustacchi 	if (vp->v_flag & VNOMAP)
45576ca3cb0SRobert Mustacchi 		return (ENOSYS);
45676ca3cb0SRobert Mustacchi 
45776ca3cb0SRobert Mustacchi 	if (off < 0 || off > MAXOFFSET_T - off)
45876ca3cb0SRobert Mustacchi 		return (ENXIO);
45976ca3cb0SRobert Mustacchi 
46076ca3cb0SRobert Mustacchi 	if (vp->v_type != VREG)
46176ca3cb0SRobert Mustacchi 		return (ENODEV);
46276ca3cb0SRobert Mustacchi 
463*043552b7SRobert Mustacchi 	if ((prot & PROT_WRITE) && (flags & MAP_SHARED))
46476ca3cb0SRobert Mustacchi 		return (ENOTSUP);
46576ca3cb0SRobert Mustacchi 
46676ca3cb0SRobert Mustacchi 	as_rangelock(as);
46776ca3cb0SRobert Mustacchi 	ret = choose_addr(as, addrp, len, off, ADDR_VACALIGN, flags);
46876ca3cb0SRobert Mustacchi 	if (ret != 0) {
46976ca3cb0SRobert Mustacchi 		as_rangeunlock(as);
47076ca3cb0SRobert Mustacchi 		return (ret);
47176ca3cb0SRobert Mustacchi 	}
47276ca3cb0SRobert Mustacchi 
47376ca3cb0SRobert Mustacchi 	vn_a.vp = vp;
47476ca3cb0SRobert Mustacchi 	vn_a.offset = (u_offset_t)off;
47576ca3cb0SRobert Mustacchi 	vn_a.type = flags & MAP_TYPE;
47676ca3cb0SRobert Mustacchi 	vn_a.prot = prot;
47776ca3cb0SRobert Mustacchi 	vn_a.maxprot = maxprot;
47876ca3cb0SRobert Mustacchi 	vn_a.cred = cr;
47976ca3cb0SRobert Mustacchi 	vn_a.amp = NULL;
48076ca3cb0SRobert Mustacchi 	vn_a.flags = flags & ~MAP_TYPE;
48176ca3cb0SRobert Mustacchi 	vn_a.szc = 0;
48276ca3cb0SRobert Mustacchi 	vn_a.lgrp_mem_policy_flags = 0;
48376ca3cb0SRobert Mustacchi 
48476ca3cb0SRobert Mustacchi 	ret = as_map(as, *addrp, len, segvn_create, &vn_a);
48576ca3cb0SRobert Mustacchi 
48676ca3cb0SRobert Mustacchi 	as_rangeunlock(as);
48776ca3cb0SRobert Mustacchi 	return (ret);
48876ca3cb0SRobert Mustacchi 
48976ca3cb0SRobert Mustacchi }
49076ca3cb0SRobert Mustacchi 
49176ca3cb0SRobert Mustacchi /*ARGSUSED*/
49276ca3cb0SRobert Mustacchi static int
bootfs_addmap(vnode_t * vp,offset_t off,struct as * as,caddr_t addr,size_t len,uchar_t prot,uchar_t maxprot,uint_t flags,cred_t * cr,caller_context_t * ct)49376ca3cb0SRobert Mustacchi bootfs_addmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
49476ca3cb0SRobert Mustacchi     size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cr,
49576ca3cb0SRobert Mustacchi     caller_context_t *ct)
49676ca3cb0SRobert Mustacchi {
49776ca3cb0SRobert Mustacchi 	return (0);
49876ca3cb0SRobert Mustacchi }
49976ca3cb0SRobert Mustacchi 
50076ca3cb0SRobert Mustacchi /*ARGSUSED*/
50176ca3cb0SRobert Mustacchi static int
bootfs_delmap(vnode_t * vp,offset_t off,struct as * as,caddr_t addr,size_t len,uint_t prot,uint_t maxprot,uint_t flags,cred_t * cr,caller_context_t * ct)50276ca3cb0SRobert Mustacchi bootfs_delmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
50376ca3cb0SRobert Mustacchi     size_t len, uint_t prot, uint_t maxprot, uint_t flags, cred_t *cr,
50476ca3cb0SRobert Mustacchi     caller_context_t *ct)
50576ca3cb0SRobert Mustacchi {
50676ca3cb0SRobert Mustacchi 	return (0);
50776ca3cb0SRobert Mustacchi }
50876ca3cb0SRobert Mustacchi 
50976ca3cb0SRobert Mustacchi static int
bootfs_pathconf(vnode_t * vp,int cmd,ulong_t * valp,cred_t * cr,caller_context_t * ct)51076ca3cb0SRobert Mustacchi bootfs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
51176ca3cb0SRobert Mustacchi     caller_context_t *ct)
51276ca3cb0SRobert Mustacchi {
51376ca3cb0SRobert Mustacchi 	int ret;
51476ca3cb0SRobert Mustacchi 
51576ca3cb0SRobert Mustacchi 	switch (cmd) {
51676ca3cb0SRobert Mustacchi 	case _PC_TIMESTAMP_RESOLUTION:
51776ca3cb0SRobert Mustacchi 		*valp = 1L;
51876ca3cb0SRobert Mustacchi 		ret = 0;
51976ca3cb0SRobert Mustacchi 		break;
52076ca3cb0SRobert Mustacchi 	default:
52176ca3cb0SRobert Mustacchi 		ret = fs_pathconf(vp, cmd, valp, cr, ct);
52276ca3cb0SRobert Mustacchi 	}
52376ca3cb0SRobert Mustacchi 
52476ca3cb0SRobert Mustacchi 	return (ret);
52576ca3cb0SRobert Mustacchi }
52676ca3cb0SRobert Mustacchi 
52776ca3cb0SRobert Mustacchi const fs_operation_def_t bootfs_vnodeops_template[] = {
52876ca3cb0SRobert Mustacchi 	VOPNAME_OPEN,		{ .vop_open = bootfs_open },
52976ca3cb0SRobert Mustacchi 	VOPNAME_CLOSE,		{ .vop_close = bootfs_close },
53076ca3cb0SRobert Mustacchi 	VOPNAME_READ,		{ .vop_read = bootfs_read },
53176ca3cb0SRobert Mustacchi 	VOPNAME_IOCTL,		{ .vop_ioctl = bootfs_ioctl },
53276ca3cb0SRobert Mustacchi 	VOPNAME_GETATTR,	{ .vop_getattr = bootfs_getattr },
53376ca3cb0SRobert Mustacchi 	VOPNAME_ACCESS,		{ .vop_access = bootfs_access },
53476ca3cb0SRobert Mustacchi 	VOPNAME_LOOKUP,		{ .vop_lookup = bootfs_lookup },
53576ca3cb0SRobert Mustacchi 	VOPNAME_READDIR,	{ .vop_readdir = bootfs_readdir },
53676ca3cb0SRobert Mustacchi 	VOPNAME_INACTIVE,	{ .vop_inactive = bootfs_inactive },
53776ca3cb0SRobert Mustacchi 	VOPNAME_RWLOCK,		{ .vop_rwlock = bootfs_rwlock },
53876ca3cb0SRobert Mustacchi 	VOPNAME_RWUNLOCK,	{ .vop_rwunlock = bootfs_rwunlock },
53976ca3cb0SRobert Mustacchi 	VOPNAME_SEEK,		{ .vop_seek = bootfs_seek },
54076ca3cb0SRobert Mustacchi 	VOPNAME_GETPAGE,	{ .vop_getpage = bootfs_getpage },
54176ca3cb0SRobert Mustacchi 	VOPNAME_MAP,		{ .vop_map = bootfs_map },
54276ca3cb0SRobert Mustacchi 	VOPNAME_ADDMAP,		{ .vop_addmap = bootfs_addmap },
54376ca3cb0SRobert Mustacchi 	VOPNAME_DELMAP,		{ .vop_delmap = bootfs_delmap },
54476ca3cb0SRobert Mustacchi 	VOPNAME_PATHCONF,	{ .vop_pathconf = bootfs_pathconf },
54576ca3cb0SRobert Mustacchi 	VOPNAME_VNEVENT,	{ .vop_vnevent = fs_vnevent_nosupport },
54676ca3cb0SRobert Mustacchi 	NULL,			NULL
54776ca3cb0SRobert Mustacchi };
548