14dcf3933Spendry /*
2c94d2e19Sbostic  * Copyright (c) 1992, 1993
3c94d2e19Sbostic  *	The Regents of the University of California.  All rights reserved.
44dcf3933Spendry  *
54dcf3933Spendry  * This code is derived from software donated to Berkeley by
64dcf3933Spendry  * Jan-Simon Pendry.
74dcf3933Spendry  *
84dcf3933Spendry  * %sccs.include.redist.c%
94dcf3933Spendry  *
10*81751356Smckusick  *	@(#)portal_vnops.c	8.14 (Berkeley) 05/21/95
114dcf3933Spendry  *
124dcf3933Spendry  * $Id: portal_vnops.c,v 1.4 1992/05/30 10:05:24 jsp Exp jsp $
134dcf3933Spendry  */
144dcf3933Spendry 
154dcf3933Spendry /*
164dcf3933Spendry  * Portal Filesystem
174dcf3933Spendry  */
184dcf3933Spendry 
194dcf3933Spendry #include <sys/param.h>
204dcf3933Spendry #include <sys/systm.h>
214dcf3933Spendry #include <sys/kernel.h>
224dcf3933Spendry #include <sys/types.h>
234dcf3933Spendry #include <sys/time.h>
244dcf3933Spendry #include <sys/proc.h>
254dcf3933Spendry #include <sys/filedesc.h>
264dcf3933Spendry #include <sys/vnode.h>
274dcf3933Spendry #include <sys/file.h>
284dcf3933Spendry #include <sys/stat.h>
294dcf3933Spendry #include <sys/mount.h>
304dcf3933Spendry #include <sys/malloc.h>
314dcf3933Spendry #include <sys/namei.h>
324dcf3933Spendry #include <sys/mbuf.h>
334dcf3933Spendry #include <sys/socket.h>
344dcf3933Spendry #include <sys/socketvar.h>
354dcf3933Spendry #include <sys/un.h>
364dcf3933Spendry #include <sys/unpcb.h>
37ef4a722fSmckusick #include <miscfs/portal/portal.h>
384dcf3933Spendry 
394dcf3933Spendry static int portal_fileid = PORTAL_ROOTFILEID+1;
404dcf3933Spendry 
414dcf3933Spendry static void
portal_closefd(p,fd)424dcf3933Spendry portal_closefd(p, fd)
434dcf3933Spendry 	struct proc *p;
444dcf3933Spendry 	int fd;
454dcf3933Spendry {
464dcf3933Spendry 	int error;
474dcf3933Spendry 	struct {
484dcf3933Spendry 		int fd;
494dcf3933Spendry 	} ua;
504dcf3933Spendry 	int rc;
514dcf3933Spendry 
524dcf3933Spendry 	ua.fd = fd;
534dcf3933Spendry 	error = close(p, &ua, &rc);
544dcf3933Spendry 	/*
554dcf3933Spendry 	 * We should never get an error, and there isn't anything
564dcf3933Spendry 	 * we could do if we got one, so just print a message.
574dcf3933Spendry 	 */
584dcf3933Spendry 	if (error)
594dcf3933Spendry 		printf("portal_closefd: error = %d\n", error);
604dcf3933Spendry }
614dcf3933Spendry 
624dcf3933Spendry /*
634dcf3933Spendry  * vp is the current namei directory
644dcf3933Spendry  * cnp is the name to locate in that directory...
654dcf3933Spendry  */
66efcf6daaSpendry int
portal_lookup(ap)674dcf3933Spendry portal_lookup(ap)
68ef4a722fSmckusick 	struct vop_lookup_args /* {
69ef4a722fSmckusick 		struct vnode * a_dvp;
70ef4a722fSmckusick 		struct vnode ** a_vpp;
71ef4a722fSmckusick 		struct componentname * a_cnp;
72ef4a722fSmckusick 	} */ *ap;
734dcf3933Spendry {
74793ca337Smckusick 	struct componentname *cnp = ap->a_cnp;
75793ca337Smckusick 	struct vnode **vpp = ap->a_vpp;
76793ca337Smckusick 	struct vnode *dvp = ap->a_dvp;
77793ca337Smckusick 	char *pname = cnp->cn_nameptr;
784dcf3933Spendry 	struct portalnode *pt;
794dcf3933Spendry 	int error;
804dcf3933Spendry 	struct vnode *fvp = 0;
814dcf3933Spendry 	char *path;
824dcf3933Spendry 	int size;
834dcf3933Spendry 
84793ca337Smckusick 	*vpp = NULLVP;
85793ca337Smckusick 
86793ca337Smckusick 	if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)
87793ca337Smckusick 		return (EROFS);
88793ca337Smckusick 
89793ca337Smckusick 	if (cnp->cn_namelen == 1 && *pname == '.') {
90793ca337Smckusick 		*vpp = dvp;
91793ca337Smckusick 		VREF(dvp);
92793ca337Smckusick 		/*VOP_LOCK(dvp);*/
934dcf3933Spendry 		return (0);
944dcf3933Spendry 	}
954dcf3933Spendry 
96793ca337Smckusick 	error = getnewvnode(VT_PORTAL, dvp->v_mount, portal_vnodeop_p, &fvp);
974dcf3933Spendry 	if (error)
984dcf3933Spendry 		goto bad;
994dcf3933Spendry 	fvp->v_type = VREG;
100793ca337Smckusick 	MALLOC(fvp->v_data, void *, sizeof(struct portalnode), M_TEMP,
101793ca337Smckusick 	    M_WAITOK);
1024dcf3933Spendry 
1034dcf3933Spendry 	pt = VTOPORTAL(fvp);
1044dcf3933Spendry 	/*
1054dcf3933Spendry 	 * Save all of the remaining pathname and
1064dcf3933Spendry 	 * advance the namei next pointer to the end
1074dcf3933Spendry 	 * of the string.
1084dcf3933Spendry 	 */
1094dcf3933Spendry 	for (size = 0, path = pname; *path; path++)
1104dcf3933Spendry 		size++;
111793ca337Smckusick 	cnp->cn_consume = size - cnp->cn_namelen;
11214853c4cSpendry 
1134dcf3933Spendry 	pt->pt_arg = malloc(size+1, M_TEMP, M_WAITOK);
1144dcf3933Spendry 	pt->pt_size = size+1;
1154dcf3933Spendry 	bcopy(pname, pt->pt_arg, pt->pt_size);
1164dcf3933Spendry 	pt->pt_fileid = portal_fileid++;
1174dcf3933Spendry 
118793ca337Smckusick 	*vpp = fvp;
1194dcf3933Spendry 	/*VOP_LOCK(fvp);*/
1204dcf3933Spendry 	return (0);
1214dcf3933Spendry 
1224dcf3933Spendry bad:;
123793ca337Smckusick 	if (fvp)
1244dcf3933Spendry 		vrele(fvp);
1254dcf3933Spendry 	return (error);
1264dcf3933Spendry }
1274dcf3933Spendry 
1284dcf3933Spendry static int
portal_connect(so,so2)1294dcf3933Spendry portal_connect(so, so2)
1304dcf3933Spendry 	struct socket *so;
1314dcf3933Spendry 	struct socket *so2;
1324dcf3933Spendry {
1334dcf3933Spendry 	/* from unp_connect, bypassing the namei stuff... */
1344dcf3933Spendry 	struct socket *so3;
1354dcf3933Spendry 	struct unpcb *unp2;
1364dcf3933Spendry 	struct unpcb *unp3;
1374dcf3933Spendry 
1384dcf3933Spendry 	if (so2 == 0)
1394dcf3933Spendry 		return (ECONNREFUSED);
1404dcf3933Spendry 
1414dcf3933Spendry 	if (so->so_type != so2->so_type)
1424dcf3933Spendry 		return (EPROTOTYPE);
1434dcf3933Spendry 
1444dcf3933Spendry 	if ((so2->so_options & SO_ACCEPTCONN) == 0)
1454dcf3933Spendry 		return (ECONNREFUSED);
1464dcf3933Spendry 
1474dcf3933Spendry 	if ((so3 = sonewconn(so2, 0)) == 0)
1484dcf3933Spendry 		return (ECONNREFUSED);
1494dcf3933Spendry 
1504dcf3933Spendry 	unp2 = sotounpcb(so2);
1514dcf3933Spendry 	unp3 = sotounpcb(so3);
1524dcf3933Spendry 	if (unp2->unp_addr)
1534dcf3933Spendry 		unp3->unp_addr = m_copy(unp2->unp_addr, 0, (int)M_COPYALL);
1544dcf3933Spendry 
1554dcf3933Spendry 	so2 = so3;
1564dcf3933Spendry 
1574dcf3933Spendry 
1584dcf3933Spendry 	return (unp_connect2(so, so2));
1594dcf3933Spendry }
1604dcf3933Spendry 
161efcf6daaSpendry int
portal_open(ap)1624dcf3933Spendry portal_open(ap)
163ef4a722fSmckusick 	struct vop_open_args /* {
164ef4a722fSmckusick 		struct vnode *a_vp;
165ef4a722fSmckusick 		int  a_mode;
166ef4a722fSmckusick 		struct ucred *a_cred;
167ef4a722fSmckusick 		struct proc *a_p;
168ef4a722fSmckusick 	} */ *ap;
1694dcf3933Spendry {
1704dcf3933Spendry 	struct socket *so = 0;
1714dcf3933Spendry 	struct portalnode *pt;
17270d12e74Spendry 	struct proc *p = ap->a_p;
17370d12e74Spendry 	struct vnode *vp = ap->a_vp;
1744dcf3933Spendry 	int s;
1754dcf3933Spendry 	struct uio auio;
1764dcf3933Spendry 	struct iovec aiov[2];
1774dcf3933Spendry 	int res;
1784dcf3933Spendry 	struct mbuf *cm = 0;
1794dcf3933Spendry 	struct cmsghdr *cmsg;
1804dcf3933Spendry 	int newfds;
1814dcf3933Spendry 	int *ip;
1824dcf3933Spendry 	int fd;
1834dcf3933Spendry 	int error;
1844dcf3933Spendry 	int len;
1854dcf3933Spendry 	struct portalmount *fmp;
1864dcf3933Spendry 	struct file *fp;
1874dcf3933Spendry 	struct portal_cred pcred;
1884dcf3933Spendry 
1894dcf3933Spendry 	/*
1904dcf3933Spendry 	 * Nothing to do when opening the root node.
1914dcf3933Spendry 	 */
19270d12e74Spendry 	if (vp->v_flag & VROOT)
1934dcf3933Spendry 		return (0);
1944dcf3933Spendry 
1954dcf3933Spendry 	/*
1964dcf3933Spendry 	 * Can't be opened unless the caller is set up
1974dcf3933Spendry 	 * to deal with the side effects.  Check for this
1984dcf3933Spendry 	 * by testing whether the p_dupfd has been set.
1994dcf3933Spendry 	 */
20070d12e74Spendry 	if (p->p_dupfd >= 0)
2014dcf3933Spendry 		return (ENODEV);
2024dcf3933Spendry 
20370d12e74Spendry 	pt = VTOPORTAL(vp);
20470d12e74Spendry 	fmp = VFSTOPORTAL(vp->v_mount);
2054dcf3933Spendry 
2064dcf3933Spendry 	/*
2074dcf3933Spendry 	 * Create a new socket.
2084dcf3933Spendry 	 */
2094dcf3933Spendry 	error = socreate(AF_UNIX, &so, SOCK_STREAM, 0);
2104dcf3933Spendry 	if (error)
2114dcf3933Spendry 		goto bad;
2124dcf3933Spendry 
2134dcf3933Spendry 	/*
2144dcf3933Spendry 	 * Reserve some buffer space
2154dcf3933Spendry 	 */
21614853c4cSpendry 	res = pt->pt_size + sizeof(pcred) + 512;	/* XXX */
2174dcf3933Spendry 	error = soreserve(so, res, res);
2184dcf3933Spendry 	if (error)
2194dcf3933Spendry 		goto bad;
2204dcf3933Spendry 
2214dcf3933Spendry 	/*
2224dcf3933Spendry 	 * Kick off connection
2234dcf3933Spendry 	 */
2244dcf3933Spendry 	error = portal_connect(so, (struct socket *)fmp->pm_server->f_data);
2254dcf3933Spendry 	if (error)
2264dcf3933Spendry 		goto bad;
2274dcf3933Spendry 
2284dcf3933Spendry 	/*
2294dcf3933Spendry 	 * Wait for connection to complete
2304dcf3933Spendry 	 */
2314dcf3933Spendry 	/*
2324dcf3933Spendry 	 * XXX: Since the mount point is holding a reference on the
2334dcf3933Spendry 	 * underlying server socket, it is not easy to find out whether
2344dcf3933Spendry 	 * the server process is still running.  To handle this problem
2354dcf3933Spendry 	 * we loop waiting for the new socket to be connected (something
2364dcf3933Spendry 	 * which will only happen if the server is still running) or for
2374dcf3933Spendry 	 * the reference count on the server socket to drop to 1, which
2384dcf3933Spendry 	 * will happen if the server dies.  Sleep for 5 second intervals
2394dcf3933Spendry 	 * and keep polling the reference count.   XXX.
2404dcf3933Spendry 	 */
2414dcf3933Spendry 	s = splnet();
2424dcf3933Spendry 	while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
2434dcf3933Spendry 		if (fmp->pm_server->f_count == 1) {
2444dcf3933Spendry 			error = ECONNREFUSED;
2454dcf3933Spendry 			splx(s);
2464dcf3933Spendry 			goto bad;
2474dcf3933Spendry 		}
2484dcf3933Spendry 		(void) tsleep((caddr_t) &so->so_timeo, PSOCK, "portalcon", 5 * hz);
2494dcf3933Spendry 	}
2504dcf3933Spendry 	splx(s);
2514dcf3933Spendry 
2524dcf3933Spendry 	if (so->so_error) {
2534dcf3933Spendry 		error = so->so_error;
2544dcf3933Spendry 		goto bad;
2554dcf3933Spendry 	}
2564dcf3933Spendry 
2574dcf3933Spendry 	/*
2584dcf3933Spendry 	 * Set miscellaneous flags
2594dcf3933Spendry 	 */
2604dcf3933Spendry 	so->so_rcv.sb_timeo = 0;
2614dcf3933Spendry 	so->so_snd.sb_timeo = 0;
2624dcf3933Spendry 	so->so_rcv.sb_flags |= SB_NOINTR;
2634dcf3933Spendry 	so->so_snd.sb_flags |= SB_NOINTR;
2644dcf3933Spendry 
2654dcf3933Spendry 
26614853c4cSpendry 	pcred.pcr_flag = ap->a_mode;
2674dcf3933Spendry 	pcred.pcr_uid = ap->a_cred->cr_uid;
26814853c4cSpendry 	pcred.pcr_ngroups = ap->a_cred->cr_ngroups;
26914853c4cSpendry 	bcopy(ap->a_cred->cr_groups, pcred.pcr_groups, NGROUPS * sizeof(gid_t));
2704dcf3933Spendry 	aiov[0].iov_base = (caddr_t) &pcred;
2714dcf3933Spendry 	aiov[0].iov_len = sizeof(pcred);
2724dcf3933Spendry 	aiov[1].iov_base = pt->pt_arg;
2734dcf3933Spendry 	aiov[1].iov_len = pt->pt_size;
2744dcf3933Spendry 	auio.uio_iov = aiov;
2754dcf3933Spendry 	auio.uio_iovcnt = 2;
2764dcf3933Spendry 	auio.uio_rw = UIO_WRITE;
2774dcf3933Spendry 	auio.uio_segflg = UIO_SYSSPACE;
27870d12e74Spendry 	auio.uio_procp = p;
2794dcf3933Spendry 	auio.uio_offset = 0;
2804dcf3933Spendry 	auio.uio_resid = aiov[0].iov_len + aiov[1].iov_len;
2814dcf3933Spendry 
28241623317Spendry 	error = sosend(so, (struct mbuf *) 0, &auio,
2834dcf3933Spendry 			(struct mbuf *) 0, (struct mbuf *) 0, 0);
2844dcf3933Spendry 	if (error)
2854dcf3933Spendry 		goto bad;
2864dcf3933Spendry 
2874dcf3933Spendry 	len = auio.uio_resid = sizeof(int);
2884dcf3933Spendry 	do {
2894dcf3933Spendry 		struct mbuf *m = 0;
2904dcf3933Spendry 		int flags = MSG_WAITALL;
2914dcf3933Spendry 		error = soreceive(so, (struct mbuf **) 0, &auio,
2924dcf3933Spendry 					&m, &cm, &flags);
2934dcf3933Spendry 		if (error)
2944dcf3933Spendry 			goto bad;
2954dcf3933Spendry 
2964dcf3933Spendry 		/*
2974dcf3933Spendry 		 * Grab an error code from the mbuf.
2984dcf3933Spendry 		 */
2994dcf3933Spendry 		if (m) {
3004dcf3933Spendry 			m = m_pullup(m, sizeof(int));	/* Needed? */
3014dcf3933Spendry 			if (m) {
3024dcf3933Spendry 				error = *(mtod(m, int *));
3034dcf3933Spendry 				m_freem(m);
3044dcf3933Spendry 			} else {
3054dcf3933Spendry 				error = EINVAL;
3064dcf3933Spendry 			}
3074dcf3933Spendry 		} else {
3084dcf3933Spendry 			if (cm == 0) {
3094dcf3933Spendry 				error = ECONNRESET;	 /* XXX */
3104dcf3933Spendry #ifdef notdef
3114dcf3933Spendry 				break;
3124dcf3933Spendry #endif
3134dcf3933Spendry 			}
3144dcf3933Spendry 		}
3154dcf3933Spendry 	} while (cm == 0 && auio.uio_resid == len && !error);
3164dcf3933Spendry 
3174dcf3933Spendry 	if (cm == 0)
3184dcf3933Spendry 		goto bad;
3194dcf3933Spendry 
3204dcf3933Spendry 	if (auio.uio_resid) {
3214dcf3933Spendry 		error = 0;
3224dcf3933Spendry #ifdef notdef
3234dcf3933Spendry 		error = EMSGSIZE;
3244dcf3933Spendry 		goto bad;
3254dcf3933Spendry #endif
3264dcf3933Spendry 	}
3274dcf3933Spendry 
3284dcf3933Spendry 	/*
3294dcf3933Spendry 	 * XXX: Break apart the control message, and retrieve the
3304dcf3933Spendry 	 * received file descriptor.  Note that more than one descriptor
3314dcf3933Spendry 	 * may have been received, or that the rights chain may have more
3324dcf3933Spendry 	 * than a single mbuf in it.  What to do?
3334dcf3933Spendry 	 */
3344dcf3933Spendry 	cmsg = mtod(cm, struct cmsghdr *);
3354dcf3933Spendry 	newfds = (cmsg->cmsg_len - sizeof(*cmsg)) / sizeof (int);
3364dcf3933Spendry 	if (newfds == 0) {
3374dcf3933Spendry 		error = ECONNREFUSED;
3384dcf3933Spendry 		goto bad;
3394dcf3933Spendry 	}
3404dcf3933Spendry 	/*
3414dcf3933Spendry 	 * At this point the rights message consists of a control message
3424dcf3933Spendry 	 * header, followed by a data region containing a vector of
3434dcf3933Spendry 	 * integer file descriptors.  The fds were allocated by the action
3444dcf3933Spendry 	 * of receiving the control message.
3454dcf3933Spendry 	 */
3464dcf3933Spendry 	ip = (int *) (cmsg + 1);
3474dcf3933Spendry 	fd = *ip++;
3484dcf3933Spendry 	if (newfds > 1) {
3494dcf3933Spendry 		/*
3504dcf3933Spendry 		 * Close extra fds.
3514dcf3933Spendry 		 */
3524dcf3933Spendry 		int i;
3534dcf3933Spendry 		printf("portal_open: %d extra fds\n", newfds - 1);
3544dcf3933Spendry 		for (i = 1; i < newfds; i++) {
35570d12e74Spendry 			portal_closefd(p, *ip);
3564dcf3933Spendry 			ip++;
3574dcf3933Spendry 		}
3584dcf3933Spendry 	}
3594dcf3933Spendry 
3604dcf3933Spendry 	/*
36170d12e74Spendry 	 * Check that the mode the file is being opened for is a subset
36270d12e74Spendry 	 * of the mode of the existing descriptor.
3634dcf3933Spendry 	 */
36470d12e74Spendry  	fp = p->p_fd->fd_ofiles[fd];
3654dcf3933Spendry 	if (((ap->a_mode & (FREAD|FWRITE)) | fp->f_flag) != fp->f_flag) {
36670d12e74Spendry 		portal_closefd(p, fd);
3674dcf3933Spendry 		error = EACCES;
3684dcf3933Spendry 		goto bad;
3694dcf3933Spendry 	}
3704dcf3933Spendry 
3714dcf3933Spendry 	/*
3724dcf3933Spendry 	 * Save the dup fd in the proc structure then return the
3734dcf3933Spendry 	 * special error code (ENXIO) which causes magic things to
3744dcf3933Spendry 	 * happen in vn_open.  The whole concept is, well, hmmm.
3754dcf3933Spendry 	 */
37670d12e74Spendry 	p->p_dupfd = fd;
3774dcf3933Spendry 	error = ENXIO;
3784dcf3933Spendry 
3794dcf3933Spendry bad:;
3804dcf3933Spendry 	/*
3814dcf3933Spendry 	 * And discard the control message.
3824dcf3933Spendry 	 */
3834dcf3933Spendry 	if (cm) {
3844dcf3933Spendry 		m_freem(cm);
3854dcf3933Spendry 	}
3864dcf3933Spendry 
3874dcf3933Spendry 	if (so) {
3884dcf3933Spendry 		soshutdown(so, 2);
3894dcf3933Spendry 		soclose(so);
3904dcf3933Spendry 	}
3914dcf3933Spendry 	return (error);
3924dcf3933Spendry }
3934dcf3933Spendry 
394efcf6daaSpendry int
portal_getattr(ap)3954dcf3933Spendry portal_getattr(ap)
396ef4a722fSmckusick 	struct vop_getattr_args /* {
397ef4a722fSmckusick 		struct vnode *a_vp;
398ef4a722fSmckusick 		struct vattr *a_vap;
399ef4a722fSmckusick 		struct ucred *a_cred;
400ef4a722fSmckusick 		struct proc *a_p;
401ef4a722fSmckusick 	} */ *ap;
4024dcf3933Spendry {
40370d12e74Spendry 	struct vnode *vp = ap->a_vp;
40470d12e74Spendry 	struct vattr *vap = ap->a_vap;
405679606e1Scgd 	struct timeval tv;
4064dcf3933Spendry 
407220a7d41Sbostic 	bzero(vap, sizeof(*vap));
40870d12e74Spendry 	vattr_null(vap);
40970d12e74Spendry 	vap->va_uid = 0;
41070d12e74Spendry 	vap->va_gid = 0;
41170d12e74Spendry 	vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
41270d12e74Spendry 	vap->va_size = DEV_BSIZE;
41370d12e74Spendry 	vap->va_blocksize = DEV_BSIZE;
414679606e1Scgd 	microtime(&tv);
415679606e1Scgd 	TIMEVAL_TO_TIMESPEC(&tv, &vap->va_atime);
41670d12e74Spendry 	vap->va_mtime = vap->va_atime;
41770d12e74Spendry 	vap->va_ctime = vap->va_ctime;
41870d12e74Spendry 	vap->va_gen = 0;
41970d12e74Spendry 	vap->va_flags = 0;
42070d12e74Spendry 	vap->va_rdev = 0;
42170d12e74Spendry 	/* vap->va_qbytes = 0; */
42270d12e74Spendry 	vap->va_bytes = 0;
42370d12e74Spendry 	/* vap->va_qsize = 0; */
42470d12e74Spendry 	if (vp->v_flag & VROOT) {
42570d12e74Spendry 		vap->va_type = VDIR;
42670d12e74Spendry 		vap->va_mode = S_IRUSR|S_IWUSR|S_IXUSR|
4274dcf3933Spendry 				S_IRGRP|S_IWGRP|S_IXGRP|
4284dcf3933Spendry 				S_IROTH|S_IWOTH|S_IXOTH;
42970d12e74Spendry 		vap->va_nlink = 2;
43070d12e74Spendry 		vap->va_fileid = 2;
4314dcf3933Spendry 	} else {
43270d12e74Spendry 		vap->va_type = VREG;
43370d12e74Spendry 		vap->va_mode = S_IRUSR|S_IWUSR|
4344dcf3933Spendry 				S_IRGRP|S_IWGRP|
4354dcf3933Spendry 				S_IROTH|S_IWOTH;
43670d12e74Spendry 		vap->va_nlink = 1;
43770d12e74Spendry 		vap->va_fileid = VTOPORTAL(vp)->pt_fileid;
4384dcf3933Spendry 	}
4394dcf3933Spendry 	return (0);
4404dcf3933Spendry }
4414dcf3933Spendry 
442efcf6daaSpendry int
portal_setattr(ap)4434dcf3933Spendry portal_setattr(ap)
444ef4a722fSmckusick 	struct vop_setattr_args /* {
445ef4a722fSmckusick 		struct vnode *a_vp;
446ef4a722fSmckusick 		struct vattr *a_vap;
447ef4a722fSmckusick 		struct ucred *a_cred;
448ef4a722fSmckusick 		struct proc *a_p;
449ef4a722fSmckusick 	} */ *ap;
4504dcf3933Spendry {
451efcf6daaSpendry 
4524dcf3933Spendry 	/*
4534dcf3933Spendry 	 * Can't mess with the root vnode
4544dcf3933Spendry 	 */
4554dcf3933Spendry 	if (ap->a_vp->v_flag & VROOT)
4564dcf3933Spendry 		return (EACCES);
4574dcf3933Spendry 
4584dcf3933Spendry 	return (0);
4594dcf3933Spendry }
4604dcf3933Spendry 
4614dcf3933Spendry /*
4624dcf3933Spendry  * Fake readdir, just return empty directory.
4634dcf3933Spendry  * It is hard to deal with '.' and '..' so don't bother.
4644dcf3933Spendry  */
465efcf6daaSpendry int
portal_readdir(ap)4664dcf3933Spendry portal_readdir(ap)
467ef4a722fSmckusick 	struct vop_readdir_args /* {
468ef4a722fSmckusick 		struct vnode *a_vp;
469ef4a722fSmckusick 		struct uio *a_uio;
470ef4a722fSmckusick 		struct ucred *a_cred;
4714d5f9013Smckusick 		int *a_eofflag;
4724d5f9013Smckusick 		u_long *a_cookies;
4734d5f9013Smckusick 		int a_ncookies;
474ef4a722fSmckusick 	} */ *ap;
4754dcf3933Spendry {
476efcf6daaSpendry 
4774d5f9013Smckusick 	/*
4784d5f9013Smckusick 	 * We don't allow exporting portal mounts, and currently local
4794d5f9013Smckusick 	 * requests do not need cookies.
4804d5f9013Smckusick 	 */
4814d5f9013Smckusick 	if (ap->a_ncookies)
4824d5f9013Smckusick 		panic("portal_readdir: not hungry");
4834d5f9013Smckusick 
4844dcf3933Spendry 	return (0);
4854dcf3933Spendry }
4864dcf3933Spendry 
487efcf6daaSpendry int
portal_inactive(ap)4884dcf3933Spendry portal_inactive(ap)
489ef4a722fSmckusick 	struct vop_inactive_args /* {
490ef4a722fSmckusick 		struct vnode *a_vp;
491*81751356Smckusick 		struct proc *a_p;
492ef4a722fSmckusick 	} */ *ap;
4934dcf3933Spendry {
494efcf6daaSpendry 
495*81751356Smckusick 	VOP_UNLOCK(ap->a_vp, 0, ap->a_p);
4964dcf3933Spendry 	return (0);
4974dcf3933Spendry }
4984dcf3933Spendry 
499efcf6daaSpendry int
portal_reclaim(ap)5004dcf3933Spendry portal_reclaim(ap)
501ef4a722fSmckusick 	struct vop_reclaim_args /* {
502ef4a722fSmckusick 		struct vnode *a_vp;
503ef4a722fSmckusick 	} */ *ap;
5044dcf3933Spendry {
5054dcf3933Spendry 	struct portalnode *pt = VTOPORTAL(ap->a_vp);
506efcf6daaSpendry 
5074dcf3933Spendry 	if (pt->pt_arg) {
5084dcf3933Spendry 		free((caddr_t) pt->pt_arg, M_TEMP);
5094dcf3933Spendry 		pt->pt_arg = 0;
5104dcf3933Spendry 	}
511c3ea2a5eSpendry 	FREE(ap->a_vp->v_data, M_TEMP);
512c3ea2a5eSpendry 	ap->a_vp->v_data = 0;
513efcf6daaSpendry 
5144dcf3933Spendry 	return (0);
5154dcf3933Spendry }
5164dcf3933Spendry 
5174dcf3933Spendry /*
5182c0d99fbSpendry  * Return POSIX pathconf information applicable to special devices.
5192c0d99fbSpendry  */
5202c0d99fbSpendry portal_pathconf(ap)
5212c0d99fbSpendry 	struct vop_pathconf_args /* {
5222c0d99fbSpendry 		struct vnode *a_vp;
5232c0d99fbSpendry 		int a_name;
5242c0d99fbSpendry 		int *a_retval;
5252c0d99fbSpendry 	} */ *ap;
5262c0d99fbSpendry {
5272c0d99fbSpendry 
5282c0d99fbSpendry 	switch (ap->a_name) {
5292c0d99fbSpendry 	case _PC_LINK_MAX:
5302c0d99fbSpendry 		*ap->a_retval = LINK_MAX;
5312c0d99fbSpendry 		return (0);
5322c0d99fbSpendry 	case _PC_MAX_CANON:
5332c0d99fbSpendry 		*ap->a_retval = MAX_CANON;
5342c0d99fbSpendry 		return (0);
5352c0d99fbSpendry 	case _PC_MAX_INPUT:
5362c0d99fbSpendry 		*ap->a_retval = MAX_INPUT;
5372c0d99fbSpendry 		return (0);
5382c0d99fbSpendry 	case _PC_PIPE_BUF:
5392c0d99fbSpendry 		*ap->a_retval = PIPE_BUF;
5402c0d99fbSpendry 		return (0);
5412c0d99fbSpendry 	case _PC_CHOWN_RESTRICTED:
5422c0d99fbSpendry 		*ap->a_retval = 1;
5432c0d99fbSpendry 		return (0);
5442c0d99fbSpendry 	case _PC_VDISABLE:
5452c0d99fbSpendry 		*ap->a_retval = _POSIX_VDISABLE;
5462c0d99fbSpendry 		return (0);
5472c0d99fbSpendry 	default:
5482c0d99fbSpendry 		return (EINVAL);
5492c0d99fbSpendry 	}
5502c0d99fbSpendry 	/* NOTREACHED */
5512c0d99fbSpendry }
5522c0d99fbSpendry 
5532c0d99fbSpendry /*
5544dcf3933Spendry  * Print out the contents of a Portal vnode.
5554dcf3933Spendry  */
5564dcf3933Spendry /* ARGSUSED */
557efcf6daaSpendry int
portal_print(ap)5584dcf3933Spendry portal_print(ap)
559ef4a722fSmckusick 	struct vop_print_args /* {
560ef4a722fSmckusick 		struct vnode *a_vp;
561ef4a722fSmckusick 	} */ *ap;
5624dcf3933Spendry {
563ef4a722fSmckusick 
5644dcf3933Spendry 	printf("tag VT_PORTAL, portal vnode\n");
565ef4a722fSmckusick 	return (0);
5664dcf3933Spendry }
5674dcf3933Spendry 
5684dcf3933Spendry /*void*/
569efcf6daaSpendry int
portal_vfree(ap)5704dcf3933Spendry portal_vfree(ap)
571ef4a722fSmckusick 	struct vop_vfree_args /* {
572ef4a722fSmckusick 		struct vnode *a_pvp;
573ef4a722fSmckusick 		ino_t a_ino;
574ef4a722fSmckusick 		int a_mode;
575ef4a722fSmckusick 	} */ *ap;
5764dcf3933Spendry {
577ef4a722fSmckusick 
578ef4a722fSmckusick 	return (0);
5794dcf3933Spendry }
5804dcf3933Spendry 
5814dcf3933Spendry 
5824dcf3933Spendry /*
5834dcf3933Spendry  * Portal vnode unsupported operation
5844dcf3933Spendry  */
585efcf6daaSpendry int
portal_enotsupp()5864dcf3933Spendry portal_enotsupp()
5874dcf3933Spendry {
588ef4a722fSmckusick 
5894dcf3933Spendry 	return (EOPNOTSUPP);
5904dcf3933Spendry }
5914dcf3933Spendry 
5924dcf3933Spendry /*
5934dcf3933Spendry  * Portal "should never get here" operation
5944dcf3933Spendry  */
595efcf6daaSpendry int
portal_badop()5964dcf3933Spendry portal_badop()
5974dcf3933Spendry {
598ef4a722fSmckusick 
5994dcf3933Spendry 	panic("portal: bad op");
6004dcf3933Spendry 	/* NOTREACHED */
6014dcf3933Spendry }
6024dcf3933Spendry 
6034dcf3933Spendry /*
6044dcf3933Spendry  * Portal vnode null operation
6054dcf3933Spendry  */
606efcf6daaSpendry int
portal_nullop()6074dcf3933Spendry portal_nullop()
6084dcf3933Spendry {
609ef4a722fSmckusick 
6104dcf3933Spendry 	return (0);
6114dcf3933Spendry }
6124dcf3933Spendry 
6134dcf3933Spendry #define portal_create ((int (*) __P((struct vop_create_args *)))portal_enotsupp)
6144dcf3933Spendry #define portal_mknod ((int (*) __P((struct  vop_mknod_args *)))portal_enotsupp)
6154dcf3933Spendry #define portal_close ((int (*) __P((struct  vop_close_args *)))nullop)
6164dcf3933Spendry #define portal_access ((int (*) __P((struct  vop_access_args *)))nullop)
6174dcf3933Spendry #define portal_read ((int (*) __P((struct  vop_read_args *)))portal_enotsupp)
6184dcf3933Spendry #define portal_write ((int (*) __P((struct  vop_write_args *)))portal_enotsupp)
6194dcf3933Spendry #define portal_ioctl ((int (*) __P((struct  vop_ioctl_args *)))portal_enotsupp)
6204dcf3933Spendry #define portal_select ((int (*) __P((struct vop_select_args *)))portal_enotsupp)
6214dcf3933Spendry #define portal_mmap ((int (*) __P((struct  vop_mmap_args *)))portal_enotsupp)
622908a2e9bSmckusick #define	portal_revoke vop_revoke
6234dcf3933Spendry #define portal_fsync ((int (*) __P((struct  vop_fsync_args *)))nullop)
6244dcf3933Spendry #define portal_seek ((int (*) __P((struct  vop_seek_args *)))nullop)
6254dcf3933Spendry #define portal_remove ((int (*) __P((struct vop_remove_args *)))portal_enotsupp)
6264dcf3933Spendry #define portal_link ((int (*) __P((struct  vop_link_args *)))portal_enotsupp)
6274dcf3933Spendry #define portal_rename ((int (*) __P((struct vop_rename_args *)))portal_enotsupp)
6284dcf3933Spendry #define portal_mkdir ((int (*) __P((struct  vop_mkdir_args *)))portal_enotsupp)
6294dcf3933Spendry #define portal_rmdir ((int (*) __P((struct  vop_rmdir_args *)))portal_enotsupp)
6305efcc598Spendry #define portal_symlink \
631ef4a722fSmckusick 	((int (*) __P((struct  vop_symlink_args *)))portal_enotsupp)
6325efcc598Spendry #define portal_readlink \
633ef4a722fSmckusick 	((int (*) __P((struct  vop_readlink_args *)))portal_enotsupp)
6344dcf3933Spendry #define portal_abortop ((int (*) __P((struct  vop_abortop_args *)))nullop)
635d13f9505Smckusick #define portal_lock ((int (*) __P((struct  vop_lock_args *)))vop_nolock)
636d13f9505Smckusick #define portal_unlock ((int (*) __P((struct  vop_unlock_args *)))vop_nounlock)
6374dcf3933Spendry #define portal_bmap ((int (*) __P((struct  vop_bmap_args *)))portal_badop)
6385efcc598Spendry #define portal_strategy \
639ef4a722fSmckusick 	((int (*) __P((struct  vop_strategy_args *)))portal_badop)
640d13f9505Smckusick #define portal_islocked \
641d13f9505Smckusick 	((int (*) __P((struct vop_islocked_args *)))vop_noislocked)
642d13f9505Smckusick #define fifo_islocked ((int(*) __P((struct vop_islocked_args *)))vop_noislocked)
6435efcc598Spendry #define portal_advlock \
644ef4a722fSmckusick 	((int (*) __P((struct  vop_advlock_args *)))portal_enotsupp)
6455efcc598Spendry #define portal_blkatoff \
646ef4a722fSmckusick 	((int (*) __P((struct  vop_blkatoff_args *)))portal_enotsupp)
6474dcf3933Spendry #define portal_valloc ((int(*) __P(( \
6484dcf3933Spendry 		struct vnode *pvp, \
6494dcf3933Spendry 		int mode, \
6504dcf3933Spendry 		struct ucred *cred, \
6514dcf3933Spendry 		struct vnode **vpp))) portal_enotsupp)
6525efcc598Spendry #define portal_truncate \
653ef4a722fSmckusick 	((int (*) __P((struct  vop_truncate_args *)))portal_enotsupp)
6544dcf3933Spendry #define portal_update ((int (*) __P((struct vop_update_args *)))portal_enotsupp)
6554dcf3933Spendry #define portal_bwrite ((int (*) __P((struct vop_bwrite_args *)))portal_enotsupp)
6564dcf3933Spendry 
6574dcf3933Spendry int (**portal_vnodeop_p)();
6584dcf3933Spendry struct vnodeopv_entry_desc portal_vnodeop_entries[] = {
6594dcf3933Spendry 	{ &vop_default_desc, vn_default_error },
6604dcf3933Spendry 	{ &vop_lookup_desc, portal_lookup },		/* lookup */
6614dcf3933Spendry 	{ &vop_create_desc, portal_create },		/* create */
6624dcf3933Spendry 	{ &vop_mknod_desc, portal_mknod },		/* mknod */
6634dcf3933Spendry 	{ &vop_open_desc, portal_open },		/* open */
6644dcf3933Spendry 	{ &vop_close_desc, portal_close },		/* close */
6654dcf3933Spendry 	{ &vop_access_desc, portal_access },		/* access */
6664dcf3933Spendry 	{ &vop_getattr_desc, portal_getattr },		/* getattr */
6674dcf3933Spendry 	{ &vop_setattr_desc, portal_setattr },		/* setattr */
6684dcf3933Spendry 	{ &vop_read_desc, portal_read },		/* read */
6694dcf3933Spendry 	{ &vop_write_desc, portal_write },		/* write */
6704dcf3933Spendry 	{ &vop_ioctl_desc, portal_ioctl },		/* ioctl */
6714dcf3933Spendry 	{ &vop_select_desc, portal_select },		/* select */
6724dcf3933Spendry 	{ &vop_mmap_desc, portal_mmap },		/* mmap */
673908a2e9bSmckusick 	{ &vop_revoke_desc, portal_revoke },		/* revoke */
6744dcf3933Spendry 	{ &vop_fsync_desc, portal_fsync },		/* fsync */
6754dcf3933Spendry 	{ &vop_seek_desc, portal_seek },		/* seek */
6764dcf3933Spendry 	{ &vop_remove_desc, portal_remove },		/* remove */
6774dcf3933Spendry 	{ &vop_link_desc, portal_link },		/* link */
6784dcf3933Spendry 	{ &vop_rename_desc, portal_rename },		/* rename */
6794dcf3933Spendry 	{ &vop_mkdir_desc, portal_mkdir },		/* mkdir */
6804dcf3933Spendry 	{ &vop_rmdir_desc, portal_rmdir },		/* rmdir */
6814dcf3933Spendry 	{ &vop_symlink_desc, portal_symlink },		/* symlink */
6824dcf3933Spendry 	{ &vop_readdir_desc, portal_readdir },		/* readdir */
6834dcf3933Spendry 	{ &vop_readlink_desc, portal_readlink },	/* readlink */
6844dcf3933Spendry 	{ &vop_abortop_desc, portal_abortop },		/* abortop */
6854dcf3933Spendry 	{ &vop_inactive_desc, portal_inactive },	/* inactive */
6864dcf3933Spendry 	{ &vop_reclaim_desc, portal_reclaim },		/* reclaim */
6874dcf3933Spendry 	{ &vop_lock_desc, portal_lock },		/* lock */
6884dcf3933Spendry 	{ &vop_unlock_desc, portal_unlock },		/* unlock */
6894dcf3933Spendry 	{ &vop_bmap_desc, portal_bmap },		/* bmap */
6904dcf3933Spendry 	{ &vop_strategy_desc, portal_strategy },	/* strategy */
6914dcf3933Spendry 	{ &vop_print_desc, portal_print },		/* print */
6924dcf3933Spendry 	{ &vop_islocked_desc, portal_islocked },	/* islocked */
6932c0d99fbSpendry 	{ &vop_pathconf_desc, portal_pathconf },	/* pathconf */
6944dcf3933Spendry 	{ &vop_advlock_desc, portal_advlock },		/* advlock */
6954dcf3933Spendry 	{ &vop_blkatoff_desc, portal_blkatoff },	/* blkatoff */
6964dcf3933Spendry 	{ &vop_valloc_desc, portal_valloc },		/* valloc */
6974dcf3933Spendry 	{ &vop_vfree_desc, portal_vfree },		/* vfree */
6984dcf3933Spendry 	{ &vop_truncate_desc, portal_truncate },	/* truncate */
6994dcf3933Spendry 	{ &vop_update_desc, portal_update },		/* update */
7004dcf3933Spendry 	{ &vop_bwrite_desc, portal_bwrite },		/* bwrite */
7014dcf3933Spendry 	{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
7024dcf3933Spendry };
7034dcf3933Spendry struct vnodeopv_desc portal_vnodeop_opv_desc =
7044dcf3933Spendry 	{ &portal_vnodeop_p, portal_vnodeop_entries };
705