153846Spendry /*
263246Sbostic  * Copyright (c) 1992, 1993
363246Sbostic  *	The Regents of the University of California.  All rights reserved.
453846Spendry  * All rights reserved.
553846Spendry  *
653846Spendry  * This code is derived from software donated to Berkeley by
753846Spendry  * Jan-Simon Pendry.
853846Spendry  *
953846Spendry  * %sccs.include.redist.c%
1053846Spendry  *
11*65380Spendry  *	@(#)portal_vnops.c	8.2 (Berkeley) 01/04/94
1253846Spendry  *
1353846Spendry  * $Id: portal_vnops.c,v 1.4 1992/05/30 10:05:24 jsp Exp jsp $
1453846Spendry  */
1553846Spendry 
1653846Spendry /*
1753846Spendry  * Portal Filesystem
1853846Spendry  */
1953846Spendry 
2053846Spendry #include <sys/param.h>
2153846Spendry #include <sys/systm.h>
2253846Spendry #include <sys/kernel.h>
2353846Spendry #include <sys/types.h>
2453846Spendry #include <sys/time.h>
2553846Spendry #include <sys/proc.h>
2653846Spendry #include <sys/filedesc.h>
2753846Spendry #include <sys/vnode.h>
2853846Spendry #include <sys/file.h>
2953846Spendry #include <sys/stat.h>
3053846Spendry #include <sys/mount.h>
3153846Spendry #include <sys/malloc.h>
3253846Spendry #include <sys/namei.h>
3353846Spendry #include <sys/mbuf.h>
3453846Spendry #include <sys/socket.h>
3553846Spendry #include <sys/socketvar.h>
3653846Spendry #include <sys/un.h>
3753846Spendry #include <sys/unpcb.h>
3855027Smckusick #include <miscfs/portal/portal.h>
3953846Spendry 
4053846Spendry static int portal_fileid = PORTAL_ROOTFILEID+1;
4153846Spendry 
4253846Spendry static void
4353846Spendry portal_closefd(p, fd)
4453846Spendry 	struct proc *p;
4553846Spendry 	int fd;
4653846Spendry {
4753846Spendry 	int error;
4853846Spendry 	struct {
4953846Spendry 		int fd;
5053846Spendry 	} ua;
5153846Spendry 	int rc;
5253846Spendry 
5353846Spendry 	ua.fd = fd;
5453846Spendry 	error = close(p, &ua, &rc);
5553846Spendry 	/*
5653846Spendry 	 * We should never get an error, and there isn't anything
5753846Spendry 	 * we could do if we got one, so just print a message.
5853846Spendry 	 */
5953846Spendry 	if (error)
6053846Spendry 		printf("portal_closefd: error = %d\n", error);
6153846Spendry }
6253846Spendry 
6353846Spendry /*
6453846Spendry  * vp is the current namei directory
6553846Spendry  * cnp is the name to locate in that directory...
6653846Spendry  */
6755027Smckusick portal_lookup(ap)
6855027Smckusick 	struct vop_lookup_args /* {
6955027Smckusick 		struct vnode * a_dvp;
7055027Smckusick 		struct vnode ** a_vpp;
7155027Smckusick 		struct componentname * a_cnp;
7255027Smckusick 	} */ *ap;
7353846Spendry {
7453846Spendry 	char *pname = ap->a_cnp->cn_nameptr;
7553846Spendry 	struct portalnode *pt;
7653846Spendry 	int error;
7753846Spendry 	struct vnode *fvp = 0;
7853846Spendry 	char *path;
7953846Spendry 	int size;
8053846Spendry 
8153846Spendry #ifdef PORTAL_DIAGNOSTIC
8253846Spendry 	printf("portal_lookup(%s)\n", pname);
8353846Spendry #endif
8453846Spendry 	if (ap->a_cnp->cn_namelen == 1 && *pname == '.') {
8553846Spendry 		*ap->a_vpp = ap->a_dvp;
8653846Spendry 		VREF(ap->a_dvp);
8753846Spendry 		/*VOP_LOCK(ap->a_dvp);*/
8853846Spendry 		return (0);
8953846Spendry 	}
9053846Spendry 
9153846Spendry 
9253846Spendry #ifdef PORTAL_DIAGNOSTIC
9353846Spendry 	printf("portal_lookup: allocate new vnode\n");
9453846Spendry #endif
95*65380Spendry 	error = getnewvnode(VT_PORTAL, ap->a_dvp->v_mount, portal_vnodeop_p, &fvp);
9653846Spendry 	if (error)
9753846Spendry 		goto bad;
9853846Spendry 	fvp->v_type = VREG;
9953846Spendry 	MALLOC(fvp->v_data, void *, sizeof(struct portalnode),
10053846Spendry 		M_TEMP, M_WAITOK);
10153846Spendry 
10253846Spendry 	pt = VTOPORTAL(fvp);
10353846Spendry 	/*
10453846Spendry 	 * Save all of the remaining pathname and
10553846Spendry 	 * advance the namei next pointer to the end
10653846Spendry 	 * of the string.
10753846Spendry 	 */
10853846Spendry 	for (size = 0, path = pname; *path; path++)
10953846Spendry 		size++;
11054978Spendry 	ap->a_cnp->cn_consume = size - ap->a_cnp->cn_namelen;
11154978Spendry 
11253846Spendry 	pt->pt_arg = malloc(size+1, M_TEMP, M_WAITOK);
11353846Spendry 	pt->pt_size = size+1;
11453846Spendry 	bcopy(pname, pt->pt_arg, pt->pt_size);
11553846Spendry 	pt->pt_fileid = portal_fileid++;
11653846Spendry 
11753846Spendry 	*ap->a_vpp = fvp;
11853846Spendry 	/*VOP_LOCK(fvp);*/
11953846Spendry #ifdef PORTAL_DIAGNOSTIC
12053846Spendry 	printf("portal_lookup: newvp = %x\n", fvp);
12153846Spendry #endif
12253846Spendry 	return (0);
12353846Spendry 
12453846Spendry bad:;
12553846Spendry 	if (fvp) {
12653846Spendry #ifdef PORTAL_DIAGNOSTIC
12753846Spendry 		printf("portal_lookup: vrele(%x)\n", fvp);
12853846Spendry #endif
12953846Spendry 		vrele(fvp);
13053846Spendry 	}
13153846Spendry 	*ap->a_vpp = NULL;
13253846Spendry #ifdef PORTAL_DIAGNOSTIC
13353846Spendry 	printf("portal_lookup: error = %d\n", error);
13453846Spendry #endif
13553846Spendry 	return (error);
13653846Spendry }
13753846Spendry 
13853846Spendry static int
13953846Spendry portal_connect(so, so2)
14053846Spendry 	struct socket *so;
14153846Spendry 	struct socket *so2;
14253846Spendry {
14353846Spendry 	/* from unp_connect, bypassing the namei stuff... */
14453846Spendry 
14553846Spendry 	struct socket *so3;
14653846Spendry 	struct unpcb *unp2;
14753846Spendry 	struct unpcb *unp3;
14853846Spendry 
14953846Spendry #ifdef PORTAL_DIAGNOSTIC
15053846Spendry 	printf("portal_connect\n");
15153846Spendry #endif
15253846Spendry 
15353846Spendry 	if (so2 == 0)
15453846Spendry 		return (ECONNREFUSED);
15553846Spendry 
15653846Spendry 	if (so->so_type != so2->so_type)
15753846Spendry 		return (EPROTOTYPE);
15853846Spendry 
15953846Spendry 	if ((so2->so_options & SO_ACCEPTCONN) == 0)
16053846Spendry 		return (ECONNREFUSED);
16153846Spendry 
16253846Spendry #ifdef PORTAL_DIAGNOSTIC
16353846Spendry 	printf("portal_connect: calling sonewconn\n");
16453846Spendry #endif
16553846Spendry 
16653846Spendry 	if ((so3 = sonewconn(so2, 0)) == 0)
16753846Spendry 		return (ECONNREFUSED);
16853846Spendry 
16953846Spendry 	unp2 = sotounpcb(so2);
17053846Spendry 	unp3 = sotounpcb(so3);
17153846Spendry 	if (unp2->unp_addr)
17253846Spendry 		unp3->unp_addr = m_copy(unp2->unp_addr, 0, (int)M_COPYALL);
17353846Spendry 
17453846Spendry 	so2 = so3;
17553846Spendry 
17653846Spendry #ifdef PORTAL_DIAGNOSTIC
17753846Spendry 	printf("portal_connect: calling unp_connect2\n");
17853846Spendry #endif
17953846Spendry 
18053846Spendry 	return (unp_connect2(so, so2));
18153846Spendry }
18253846Spendry 
18355027Smckusick portal_open(ap)
18455027Smckusick 	struct vop_open_args /* {
18555027Smckusick 		struct vnode *a_vp;
18655027Smckusick 		int  a_mode;
18755027Smckusick 		struct ucred *a_cred;
18855027Smckusick 		struct proc *a_p;
18955027Smckusick 	} */ *ap;
19053846Spendry {
19153846Spendry 	struct socket *so = 0;
19253846Spendry 	struct portalnode *pt;
19355910Spendry 	struct proc *p = ap->a_p;
19455910Spendry 	struct vnode *vp = ap->a_vp;
19553846Spendry 	int s;
19653846Spendry 	struct uio auio;
19753846Spendry 	struct iovec aiov[2];
19853846Spendry 	int res;
19953846Spendry 	struct mbuf *cm = 0;
20053846Spendry 	struct cmsghdr *cmsg;
20153846Spendry 	int newfds;
20253846Spendry 	int *ip;
20353846Spendry 	int fd;
20453846Spendry 	int error;
20553846Spendry 	int len;
20653846Spendry 	struct portalmount *fmp;
20753846Spendry 	struct file *fp;
20853846Spendry 	struct portal_cred pcred;
20953846Spendry 
21053846Spendry 	/*
21153846Spendry 	 * Nothing to do when opening the root node.
21253846Spendry 	 */
21355910Spendry 	if (vp->v_flag & VROOT)
21453846Spendry 		return (0);
21553846Spendry 
21653846Spendry #ifdef PORTAL_DIAGNOSTIC
21755910Spendry 	printf("portal_open(%x)\n", vp);
21853846Spendry #endif
21953846Spendry 
22053846Spendry 	/*
22153846Spendry 	 * Can't be opened unless the caller is set up
22253846Spendry 	 * to deal with the side effects.  Check for this
22353846Spendry 	 * by testing whether the p_dupfd has been set.
22453846Spendry 	 */
22555910Spendry 	if (p->p_dupfd >= 0)
22653846Spendry 		return (ENODEV);
22753846Spendry 
22855910Spendry 	pt = VTOPORTAL(vp);
22955910Spendry 	fmp = VFSTOPORTAL(vp->v_mount);
23053846Spendry 
23153846Spendry 	/*
23253846Spendry 	 * Create a new socket.
23353846Spendry 	 */
23453846Spendry 	error = socreate(AF_UNIX, &so, SOCK_STREAM, 0);
23553846Spendry 	if (error)
23653846Spendry 		goto bad;
23753846Spendry 
23853846Spendry 	/*
23953846Spendry 	 * Reserve some buffer space
24053846Spendry 	 */
24153846Spendry #ifdef PORTAL_DIAGNOSTIC
24253846Spendry 	printf("portal_open: calling soreserve\n");
24353846Spendry #endif
24454978Spendry 	res = pt->pt_size + sizeof(pcred) + 512;	/* XXX */
24553846Spendry 	error = soreserve(so, res, res);
24653846Spendry 	if (error)
24753846Spendry 		goto bad;
24853846Spendry 
24953846Spendry 	/*
25053846Spendry 	 * Kick off connection
25153846Spendry 	 */
25253846Spendry #ifdef PORTAL_DIAGNOSTIC
25353846Spendry 	printf("portal_open: calling portal_connect\n");
25453846Spendry #endif
25553846Spendry 	error = portal_connect(so, (struct socket *)fmp->pm_server->f_data);
25653846Spendry 	if (error)
25753846Spendry 		goto bad;
25853846Spendry 
25953846Spendry 	/*
26053846Spendry 	 * Wait for connection to complete
26153846Spendry 	 */
26253846Spendry #ifdef PORTAL_DIAGNOSTIC
26353846Spendry 	printf("portal_open: waiting for connect\n");
26453846Spendry #endif
26553846Spendry 	/*
26653846Spendry 	 * XXX: Since the mount point is holding a reference on the
26753846Spendry 	 * underlying server socket, it is not easy to find out whether
26853846Spendry 	 * the server process is still running.  To handle this problem
26953846Spendry 	 * we loop waiting for the new socket to be connected (something
27053846Spendry 	 * which will only happen if the server is still running) or for
27153846Spendry 	 * the reference count on the server socket to drop to 1, which
27253846Spendry 	 * will happen if the server dies.  Sleep for 5 second intervals
27353846Spendry 	 * and keep polling the reference count.   XXX.
27453846Spendry 	 */
27553846Spendry 	s = splnet();
27653846Spendry 	while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
27753846Spendry 		if (fmp->pm_server->f_count == 1) {
27853846Spendry 			error = ECONNREFUSED;
27953846Spendry 			splx(s);
28053846Spendry #ifdef PORTAL_DIAGNOSTIC
28153846Spendry 			printf("portal_open: server process has gone away\n");
28253846Spendry #endif
28353846Spendry 			goto bad;
28453846Spendry 		}
28553846Spendry 		(void) tsleep((caddr_t) &so->so_timeo, PSOCK, "portalcon", 5 * hz);
28653846Spendry 	}
28753846Spendry 	splx(s);
28853846Spendry 
28953846Spendry 	if (so->so_error) {
29053846Spendry 		error = so->so_error;
29153846Spendry 		goto bad;
29253846Spendry 	}
29353846Spendry 
29453846Spendry 	/*
29553846Spendry 	 * Set miscellaneous flags
29653846Spendry 	 */
29753846Spendry 	so->so_rcv.sb_timeo = 0;
29853846Spendry 	so->so_snd.sb_timeo = 0;
29953846Spendry 	so->so_rcv.sb_flags |= SB_NOINTR;
30053846Spendry 	so->so_snd.sb_flags |= SB_NOINTR;
30153846Spendry 
30253846Spendry #ifdef PORTAL_DIAGNOSTIC
30353846Spendry 	printf("portal_open: constructing data uio\n");
30453846Spendry #endif
30553846Spendry 
30654978Spendry 	pcred.pcr_flag = ap->a_mode;
30753846Spendry 	pcred.pcr_uid = ap->a_cred->cr_uid;
30854978Spendry 	pcred.pcr_ngroups = ap->a_cred->cr_ngroups;
30954978Spendry 	bcopy(ap->a_cred->cr_groups, pcred.pcr_groups, NGROUPS * sizeof(gid_t));
31053846Spendry 	aiov[0].iov_base = (caddr_t) &pcred;
31153846Spendry 	aiov[0].iov_len = sizeof(pcred);
31253846Spendry 	aiov[1].iov_base = pt->pt_arg;
31353846Spendry 	aiov[1].iov_len = pt->pt_size;
31453846Spendry 	auio.uio_iov = aiov;
31553846Spendry 	auio.uio_iovcnt = 2;
31653846Spendry 	auio.uio_rw = UIO_WRITE;
31753846Spendry 	auio.uio_segflg = UIO_SYSSPACE;
31855910Spendry 	auio.uio_procp = p;
31953846Spendry 	auio.uio_offset = 0;
32053846Spendry 	auio.uio_resid = aiov[0].iov_len + aiov[1].iov_len;
32153846Spendry 
32253846Spendry #ifdef PORTAL_DIAGNOSTIC
32353846Spendry 	printf("portal_open: sending data to server\n");
32453846Spendry #endif
32553846Spendry 	error = sosend(so, (struct sockaddr *) 0, &auio,
32653846Spendry 			(struct mbuf *) 0, (struct mbuf *) 0, 0);
32753846Spendry 	if (error)
32853846Spendry 		goto bad;
32953846Spendry 
33053846Spendry 	len = auio.uio_resid = sizeof(int);
33153846Spendry 	do {
33253846Spendry 		struct mbuf *m = 0;
33353846Spendry 		int flags = MSG_WAITALL;
33453846Spendry #ifdef PORTAL_DIAGNOSTIC
33553846Spendry 		printf("portal_open: receiving data from server\n");
33653846Spendry 		printf("portal_open: so = %x, cm = %x, resid = %d\n",
33753846Spendry 				so, cm, auio.uio_resid);
33853846Spendry 		printf("portal_open, uio=%x, mp0=%x, controlp=%x\n", &auio, &cm);
33953846Spendry #endif
34053846Spendry 		error = soreceive(so, (struct mbuf **) 0, &auio,
34153846Spendry 					&m, &cm, &flags);
34253846Spendry #ifdef PORTAL_DIAGNOSTIC
34353846Spendry 		printf("portal_open: after receiving data\n");
34453846Spendry 		printf("portal_open: so = %x, cm = %x, resid = %d\n",
34553846Spendry 				so, cm, auio.uio_resid);
34653846Spendry #endif
34753846Spendry 		if (error)
34853846Spendry 			goto bad;
34953846Spendry 
35053846Spendry 		/*
35153846Spendry 		 * Grab an error code from the mbuf.
35253846Spendry 		 */
35353846Spendry 		if (m) {
35453846Spendry 			m = m_pullup(m, sizeof(int));	/* Needed? */
35553846Spendry 			if (m) {
35653846Spendry 				error = *(mtod(m, int *));
35753846Spendry 				m_freem(m);
35853846Spendry 			} else {
35953846Spendry 				error = EINVAL;
36053846Spendry 			}
36153846Spendry #ifdef PORTAL_DIAGNOSTIC
36253846Spendry 			printf("portal_open: error returned is %d\n", error);
36353846Spendry #endif
36453846Spendry 		} else {
36553846Spendry 			if (cm == 0) {
36653846Spendry #ifdef PORTAL_DIAGNOSTIC
36753846Spendry 				printf("portal_open: no rights received\n");
36853846Spendry #endif
36953846Spendry 				error = ECONNRESET;	 /* XXX */
37053846Spendry #ifdef notdef
37153846Spendry 				break;
37253846Spendry #endif
37353846Spendry 			}
37453846Spendry 		}
37553846Spendry 	} while (cm == 0 && auio.uio_resid == len && !error);
37653846Spendry 
37753846Spendry 	if (cm == 0)
37853846Spendry 		goto bad;
37953846Spendry 
38053846Spendry 	if (auio.uio_resid) {
38153846Spendry #ifdef PORTAL_DIAGNOSTIC
38253846Spendry 		printf("portal_open: still need another %d bytes\n", auio.uio_resid);
38353846Spendry #endif
38453846Spendry 		error = 0;
38553846Spendry #ifdef notdef
38653846Spendry 		error = EMSGSIZE;
38753846Spendry 		goto bad;
38853846Spendry #endif
38953846Spendry 	}
39053846Spendry 
39153846Spendry 	/*
39253846Spendry 	 * XXX: Break apart the control message, and retrieve the
39353846Spendry 	 * received file descriptor.  Note that more than one descriptor
39453846Spendry 	 * may have been received, or that the rights chain may have more
39553846Spendry 	 * than a single mbuf in it.  What to do?
39653846Spendry 	 */
39753846Spendry #ifdef PORTAL_DIAGNOSTIC
39853846Spendry 	printf("portal_open: about to break apart control message\n");
39953846Spendry #endif
40053846Spendry 	cmsg = mtod(cm, struct cmsghdr *);
40153846Spendry 	newfds = (cmsg->cmsg_len - sizeof(*cmsg)) / sizeof (int);
40253846Spendry 	if (newfds == 0) {
40353846Spendry #ifdef PORTAL_DIAGNOSTIC
40453846Spendry 		printf("portal_open: received no fds\n");
40553846Spendry #endif
40653846Spendry 		error = ECONNREFUSED;
40753846Spendry 		goto bad;
40853846Spendry 	}
40953846Spendry 	/*
41053846Spendry 	 * At this point the rights message consists of a control message
41153846Spendry 	 * header, followed by a data region containing a vector of
41253846Spendry 	 * integer file descriptors.  The fds were allocated by the action
41353846Spendry 	 * of receiving the control message.
41453846Spendry 	 */
41553846Spendry 	ip = (int *) (cmsg + 1);
41653846Spendry 	fd = *ip++;
41753846Spendry 	if (newfds > 1) {
41853846Spendry 		/*
41953846Spendry 		 * Close extra fds.
42053846Spendry 		 */
42153846Spendry 		int i;
42253846Spendry 		printf("portal_open: %d extra fds\n", newfds - 1);
42353846Spendry 		for (i = 1; i < newfds; i++) {
42455910Spendry 			portal_closefd(p, *ip);
42553846Spendry 			ip++;
42653846Spendry 		}
42753846Spendry 	}
42853846Spendry 
42953846Spendry 	/*
43055910Spendry 	 * Check that the mode the file is being opened for is a subset
43155910Spendry 	 * of the mode of the existing descriptor.
43253846Spendry 	 */
43353846Spendry #ifdef PORTAL_DIAGNOSTIC
43453846Spendry 	printf("portal_open: checking file flags, fd = %d\n", fd);
43553846Spendry #endif
43655910Spendry  	fp = p->p_fd->fd_ofiles[fd];
43753846Spendry 	if (((ap->a_mode & (FREAD|FWRITE)) | fp->f_flag) != fp->f_flag) {
43855910Spendry 		portal_closefd(p, fd);
43953846Spendry 		error = EACCES;
44053846Spendry 		goto bad;
44153846Spendry 	}
44253846Spendry 
44353846Spendry #ifdef PORTAL_DIAGNOSTIC
44453846Spendry 	printf("portal_open: got fd = %d\n", fd);
44553846Spendry #endif
44653846Spendry 	/*
44753846Spendry 	 * Save the dup fd in the proc structure then return the
44853846Spendry 	 * special error code (ENXIO) which causes magic things to
44953846Spendry 	 * happen in vn_open.  The whole concept is, well, hmmm.
45053846Spendry 	 */
45155910Spendry 	p->p_dupfd = fd;
45253846Spendry 	error = ENXIO;
45353846Spendry 
45453846Spendry bad:;
45553846Spendry 	/*
45653846Spendry 	 * And discard the control message.
45753846Spendry 	 */
45853846Spendry 	if (cm) {
45953846Spendry #ifdef PORTAL_DIAGNOSTIC
46053846Spendry 		printf("portal_open: free'ing control message\n");
46153846Spendry #endif
46253846Spendry 		m_freem(cm);
46353846Spendry 	}
46453846Spendry 
46553846Spendry 	if (so) {
46653846Spendry #ifdef PORTAL_DIAGNOSTIC
46753846Spendry 		printf("portal_open: calling soshutdown\n");
46853846Spendry #endif
46953846Spendry 		soshutdown(so, 2);
47053846Spendry #ifdef PORTAL_DIAGNOSTIC
47153846Spendry 		printf("portal_open: calling soclose\n");
47253846Spendry #endif
47353846Spendry 		soclose(so);
47453846Spendry 	}
47553846Spendry #ifdef PORTAL_DIAGNOSTIC
47653846Spendry 	if (error != ENODEV)
47753846Spendry 		printf("portal_open: error = %d\n", error);
47853846Spendry #endif
47953846Spendry 	return (error);
48053846Spendry }
48153846Spendry 
48255027Smckusick portal_getattr(ap)
48355027Smckusick 	struct vop_getattr_args /* {
48455027Smckusick 		struct vnode *a_vp;
48555027Smckusick 		struct vattr *a_vap;
48655027Smckusick 		struct ucred *a_cred;
48755027Smckusick 		struct proc *a_p;
48855027Smckusick 	} */ *ap;
48953846Spendry {
49055910Spendry 	struct vnode *vp = ap->a_vp;
49155910Spendry 	struct vattr *vap = ap->a_vap;
49253846Spendry 	unsigned fd;
49353846Spendry 	int error;
49453846Spendry 
49555910Spendry 	bzero((caddr_t) vap, sizeof(*vap));
49655910Spendry 	vattr_null(vap);
49755910Spendry 	vap->va_uid = 0;
49855910Spendry 	vap->va_gid = 0;
49955910Spendry 	vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
50055910Spendry 	vap->va_size = DEV_BSIZE;
50155910Spendry 	vap->va_blocksize = DEV_BSIZE;
50255910Spendry 	microtime(&vap->va_atime);
50355910Spendry 	vap->va_mtime = vap->va_atime;
50455910Spendry 	vap->va_ctime = vap->va_ctime;
50555910Spendry 	vap->va_gen = 0;
50655910Spendry 	vap->va_flags = 0;
50755910Spendry 	vap->va_rdev = 0;
50855910Spendry 	/* vap->va_qbytes = 0; */
50955910Spendry 	vap->va_bytes = 0;
51055910Spendry 	/* vap->va_qsize = 0; */
51155910Spendry 	if (vp->v_flag & VROOT) {
51253846Spendry #ifdef PORTAL_DIAGNOSTIC
51353846Spendry 		printf("portal_getattr: stat rootdir\n");
51453846Spendry #endif
51555910Spendry 		vap->va_type = VDIR;
51655910Spendry 		vap->va_mode = S_IRUSR|S_IWUSR|S_IXUSR|
51753846Spendry 				S_IRGRP|S_IWGRP|S_IXGRP|
51853846Spendry 				S_IROTH|S_IWOTH|S_IXOTH;
51955910Spendry 		vap->va_nlink = 2;
52055910Spendry 		vap->va_fileid = 2;
52153846Spendry 	} else {
52253846Spendry #ifdef PORTAL_DIAGNOSTIC
52353846Spendry 		printf("portal_getattr: stat portal\n");
52453846Spendry #endif
52555910Spendry 		vap->va_type = VREG;
52655910Spendry 		vap->va_mode = S_IRUSR|S_IWUSR|
52753846Spendry 				S_IRGRP|S_IWGRP|
52853846Spendry 				S_IROTH|S_IWOTH;
52955910Spendry 		vap->va_nlink = 1;
53055910Spendry 		vap->va_fileid = VTOPORTAL(vp)->pt_fileid;
53153846Spendry 	}
53253846Spendry 	return (0);
53353846Spendry }
53453846Spendry 
53555027Smckusick portal_setattr(ap)
53655027Smckusick 	struct vop_setattr_args /* {
53755027Smckusick 		struct vnode *a_vp;
53855027Smckusick 		struct vattr *a_vap;
53955027Smckusick 		struct ucred *a_cred;
54055027Smckusick 		struct proc *a_p;
54155027Smckusick 	} */ *ap;
54253846Spendry {
54353846Spendry 	/*
54453846Spendry 	 * Can't mess with the root vnode
54553846Spendry 	 */
54653846Spendry 	if (ap->a_vp->v_flag & VROOT)
54753846Spendry 		return (EACCES);
54853846Spendry 
54953846Spendry 	return (0);
55053846Spendry }
55153846Spendry 
55253846Spendry /*
55353846Spendry  * Fake readdir, just return empty directory.
55453846Spendry  * It is hard to deal with '.' and '..' so don't bother.
55553846Spendry  */
55655027Smckusick portal_readdir(ap)
55755027Smckusick 	struct vop_readdir_args /* {
55855027Smckusick 		struct vnode *a_vp;
55955027Smckusick 		struct uio *a_uio;
56055027Smckusick 		struct ucred *a_cred;
56155027Smckusick 	} */ *ap;
56253846Spendry {
56354978Spendry 	/* *ap->a_eofflagp = 1; */
56453846Spendry 	return (0);
56553846Spendry }
56653846Spendry 
56755027Smckusick portal_inactive(ap)
56855027Smckusick 	struct vop_inactive_args /* {
56955027Smckusick 		struct vnode *a_vp;
57055027Smckusick 	} */ *ap;
57153846Spendry {
57253846Spendry #ifdef PORTAL_DIAGNOSTIC
57353846Spendry 	if (VTOPORTAL(ap->a_vp)->pt_arg)
57453846Spendry 		printf("portal_inactive(%x, %s)\n", ap->a_vp, VTOPORTAL(ap->a_vp)->pt_arg);
57553846Spendry 	else
57653846Spendry 		printf("portal_inactive(%x)\n", ap->a_vp);
57753846Spendry #endif
57853846Spendry 	/*vgone(ap->a_vp);*/
57953846Spendry 	return (0);
58053846Spendry }
58153846Spendry 
58255027Smckusick portal_reclaim(ap)
58355027Smckusick 	struct vop_reclaim_args /* {
58455027Smckusick 		struct vnode *a_vp;
58555027Smckusick 	} */ *ap;
58653846Spendry {
58753846Spendry 	struct portalnode *pt = VTOPORTAL(ap->a_vp);
58853846Spendry #ifdef PORTAL_DIAGOISTIC
58953846Spendry 	printf("portal_reclaim(%x)\n", ap->a_vp);
59053846Spendry #endif
59153846Spendry 	if (pt->pt_arg) {
59253846Spendry 		free((caddr_t) pt->pt_arg, M_TEMP);
59353846Spendry 		pt->pt_arg = 0;
59453846Spendry 	}
59553846Spendry 	FREE(pt, M_TEMP);
59653846Spendry 	return (0);
59753846Spendry }
59853846Spendry 
59953846Spendry /*
60053846Spendry  * Print out the contents of a Portal vnode.
60153846Spendry  */
60253846Spendry /* ARGSUSED */
60355027Smckusick portal_print(ap)
60455027Smckusick 	struct vop_print_args /* {
60555027Smckusick 		struct vnode *a_vp;
60655027Smckusick 	} */ *ap;
60753846Spendry {
60855027Smckusick 
60953846Spendry 	printf("tag VT_PORTAL, portal vnode\n");
61055027Smckusick 	return (0);
61153846Spendry }
61253846Spendry 
61353846Spendry /*void*/
61455027Smckusick portal_vfree(ap)
61555027Smckusick 	struct vop_vfree_args /* {
61655027Smckusick 		struct vnode *a_pvp;
61755027Smckusick 		ino_t a_ino;
61855027Smckusick 		int a_mode;
61955027Smckusick 	} */ *ap;
62053846Spendry {
62155027Smckusick 
62255027Smckusick 	return (0);
62353846Spendry }
62453846Spendry 
62553846Spendry 
62653846Spendry /*
62753846Spendry  * Portal vnode unsupported operation
62853846Spendry  */
62953846Spendry portal_enotsupp()
63053846Spendry {
63155027Smckusick 
63253846Spendry 	return (EOPNOTSUPP);
63353846Spendry }
63453846Spendry 
63553846Spendry /*
63653846Spendry  * Portal "should never get here" operation
63753846Spendry  */
63853846Spendry portal_badop()
63953846Spendry {
64055027Smckusick 
64153846Spendry 	panic("portal: bad op");
64253846Spendry 	/* NOTREACHED */
64353846Spendry }
64453846Spendry 
64553846Spendry /*
64653846Spendry  * Portal vnode null operation
64753846Spendry  */
64853846Spendry portal_nullop()
64953846Spendry {
65055027Smckusick 
65153846Spendry 	return (0);
65253846Spendry }
65353846Spendry 
65455027Smckusick #define portal_create ((int (*) __P((struct vop_create_args *)))portal_enotsupp)
65553846Spendry #define portal_mknod ((int (*) __P((struct  vop_mknod_args *)))portal_enotsupp)
65653846Spendry #define portal_close ((int (*) __P((struct  vop_close_args *)))nullop)
65753846Spendry #define portal_access ((int (*) __P((struct  vop_access_args *)))nullop)
65853846Spendry #define portal_read ((int (*) __P((struct  vop_read_args *)))portal_enotsupp)
65953846Spendry #define portal_write ((int (*) __P((struct  vop_write_args *)))portal_enotsupp)
66053846Spendry #define portal_ioctl ((int (*) __P((struct  vop_ioctl_args *)))portal_enotsupp)
66155027Smckusick #define portal_select ((int (*) __P((struct vop_select_args *)))portal_enotsupp)
66253846Spendry #define portal_mmap ((int (*) __P((struct  vop_mmap_args *)))portal_enotsupp)
66353846Spendry #define portal_fsync ((int (*) __P((struct  vop_fsync_args *)))nullop)
66453846Spendry #define portal_seek ((int (*) __P((struct  vop_seek_args *)))nullop)
66555027Smckusick #define portal_remove ((int (*) __P((struct vop_remove_args *)))portal_enotsupp)
66653846Spendry #define portal_link ((int (*) __P((struct  vop_link_args *)))portal_enotsupp)
66755027Smckusick #define portal_rename ((int (*) __P((struct vop_rename_args *)))portal_enotsupp)
66853846Spendry #define portal_mkdir ((int (*) __P((struct  vop_mkdir_args *)))portal_enotsupp)
66953846Spendry #define portal_rmdir ((int (*) __P((struct  vop_rmdir_args *)))portal_enotsupp)
67055171Spendry #define portal_symlink \
67155027Smckusick 	((int (*) __P((struct  vop_symlink_args *)))portal_enotsupp)
67255171Spendry #define portal_readlink \
67355027Smckusick 	((int (*) __P((struct  vop_readlink_args *)))portal_enotsupp)
67453846Spendry #define portal_abortop ((int (*) __P((struct  vop_abortop_args *)))nullop)
67553846Spendry #define portal_lock ((int (*) __P((struct  vop_lock_args *)))nullop)
67653846Spendry #define portal_unlock ((int (*) __P((struct  vop_unlock_args *)))nullop)
67753846Spendry #define portal_bmap ((int (*) __P((struct  vop_bmap_args *)))portal_badop)
67855171Spendry #define portal_strategy \
67955027Smckusick 	((int (*) __P((struct  vop_strategy_args *)))portal_badop)
68053846Spendry #define portal_islocked ((int (*) __P((struct  vop_islocked_args *)))nullop)
68155171Spendry #define portal_advlock \
68255027Smckusick 	((int (*) __P((struct  vop_advlock_args *)))portal_enotsupp)
68355171Spendry #define portal_blkatoff \
68455027Smckusick 	((int (*) __P((struct  vop_blkatoff_args *)))portal_enotsupp)
68553846Spendry #define portal_valloc ((int(*) __P(( \
68653846Spendry 		struct vnode *pvp, \
68753846Spendry 		int mode, \
68853846Spendry 		struct ucred *cred, \
68953846Spendry 		struct vnode **vpp))) portal_enotsupp)
69055171Spendry #define portal_truncate \
69155027Smckusick 	((int (*) __P((struct  vop_truncate_args *)))portal_enotsupp)
69255027Smckusick #define portal_update ((int (*) __P((struct vop_update_args *)))portal_enotsupp)
69355027Smckusick #define portal_bwrite ((int (*) __P((struct vop_bwrite_args *)))portal_enotsupp)
69453846Spendry 
69553846Spendry int (**portal_vnodeop_p)();
69653846Spendry struct vnodeopv_entry_desc portal_vnodeop_entries[] = {
69753846Spendry 	{ &vop_default_desc, vn_default_error },
69853846Spendry 	{ &vop_lookup_desc, portal_lookup },		/* lookup */
69953846Spendry 	{ &vop_create_desc, portal_create },		/* create */
70053846Spendry 	{ &vop_mknod_desc, portal_mknod },		/* mknod */
70153846Spendry 	{ &vop_open_desc, portal_open },		/* open */
70253846Spendry 	{ &vop_close_desc, portal_close },		/* close */
70353846Spendry 	{ &vop_access_desc, portal_access },		/* access */
70453846Spendry 	{ &vop_getattr_desc, portal_getattr },		/* getattr */
70553846Spendry 	{ &vop_setattr_desc, portal_setattr },		/* setattr */
70653846Spendry 	{ &vop_read_desc, portal_read },		/* read */
70753846Spendry 	{ &vop_write_desc, portal_write },		/* write */
70853846Spendry 	{ &vop_ioctl_desc, portal_ioctl },		/* ioctl */
70953846Spendry 	{ &vop_select_desc, portal_select },		/* select */
71053846Spendry 	{ &vop_mmap_desc, portal_mmap },		/* mmap */
71153846Spendry 	{ &vop_fsync_desc, portal_fsync },		/* fsync */
71253846Spendry 	{ &vop_seek_desc, portal_seek },		/* seek */
71353846Spendry 	{ &vop_remove_desc, portal_remove },		/* remove */
71453846Spendry 	{ &vop_link_desc, portal_link },		/* link */
71553846Spendry 	{ &vop_rename_desc, portal_rename },		/* rename */
71653846Spendry 	{ &vop_mkdir_desc, portal_mkdir },		/* mkdir */
71753846Spendry 	{ &vop_rmdir_desc, portal_rmdir },		/* rmdir */
71853846Spendry 	{ &vop_symlink_desc, portal_symlink },		/* symlink */
71953846Spendry 	{ &vop_readdir_desc, portal_readdir },		/* readdir */
72053846Spendry 	{ &vop_readlink_desc, portal_readlink },	/* readlink */
72153846Spendry 	{ &vop_abortop_desc, portal_abortop },		/* abortop */
72253846Spendry 	{ &vop_inactive_desc, portal_inactive },	/* inactive */
72353846Spendry 	{ &vop_reclaim_desc, portal_reclaim },		/* reclaim */
72453846Spendry 	{ &vop_lock_desc, portal_lock },		/* lock */
72553846Spendry 	{ &vop_unlock_desc, portal_unlock },		/* unlock */
72653846Spendry 	{ &vop_bmap_desc, portal_bmap },		/* bmap */
72753846Spendry 	{ &vop_strategy_desc, portal_strategy },	/* strategy */
72853846Spendry 	{ &vop_print_desc, portal_print },		/* print */
72953846Spendry 	{ &vop_islocked_desc, portal_islocked },	/* islocked */
73053846Spendry 	{ &vop_advlock_desc, portal_advlock },		/* advlock */
73153846Spendry 	{ &vop_blkatoff_desc, portal_blkatoff },	/* blkatoff */
73253846Spendry 	{ &vop_valloc_desc, portal_valloc },		/* valloc */
73353846Spendry 	{ &vop_vfree_desc, portal_vfree },		/* vfree */
73453846Spendry 	{ &vop_truncate_desc, portal_truncate },	/* truncate */
73553846Spendry 	{ &vop_update_desc, portal_update },		/* update */
73653846Spendry 	{ &vop_bwrite_desc, portal_bwrite },		/* bwrite */
73753846Spendry 	{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
73853846Spendry };
73953846Spendry struct vnodeopv_desc portal_vnodeop_opv_desc =
74053846Spendry 	{ &portal_vnodeop_p, portal_vnodeop_entries };
741