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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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