xref: /netbsd-src/sys/coda/coda_psdev.c (revision 4ea2e44bb61ff86f86e3be96ca8b9926e20b512f)
1*4ea2e44bSthorpej /*	$NetBSD: coda_psdev.c,v 1.65 2024/05/17 23:57:46 thorpej Exp $	*/
2a00eb709Srvb 
32eec68d7Srvb /*
4a00eb709Srvb  *
5a00eb709Srvb  *             Coda: an Experimental Distributed File System
6a00eb709Srvb  *                              Release 3.1
7a00eb709Srvb  *
8a00eb709Srvb  *           Copyright (c) 1987-1998 Carnegie Mellon University
9a00eb709Srvb  *                          All Rights Reserved
10a00eb709Srvb  *
11a00eb709Srvb  * Permission  to  use, copy, modify and distribute this software and its
12a00eb709Srvb  * documentation is hereby granted,  provided  that  both  the  copyright
13a00eb709Srvb  * notice  and  this  permission  notice  appear  in  all  copies  of the
14a00eb709Srvb  * software, derivative works or  modified  versions,  and  any  portions
15a00eb709Srvb  * thereof, and that both notices appear in supporting documentation, and
16a00eb709Srvb  * that credit is given to Carnegie Mellon University  in  all  documents
17a00eb709Srvb  * and publicity pertaining to direct or indirect use of this code or its
18a00eb709Srvb  * derivatives.
19a00eb709Srvb  *
20a00eb709Srvb  * CODA IS AN EXPERIMENTAL SOFTWARE SYSTEM AND IS  KNOWN  TO  HAVE  BUGS,
21a00eb709Srvb  * SOME  OF  WHICH MAY HAVE SERIOUS CONSEQUENCES.  CARNEGIE MELLON ALLOWS
22a00eb709Srvb  * FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION.   CARNEGIE  MELLON
23a00eb709Srvb  * DISCLAIMS  ANY  LIABILITY  OF  ANY  KIND  FOR  ANY  DAMAGES WHATSOEVER
24a00eb709Srvb  * RESULTING DIRECTLY OR INDIRECTLY FROM THE USE OF THIS SOFTWARE  OR  OF
25a00eb709Srvb  * ANY DERIVATIVE WORK.
26a00eb709Srvb  *
27a00eb709Srvb  * Carnegie  Mellon  encourages  users  of  this  software  to return any
28a00eb709Srvb  * improvements or extensions that  they  make,  and  to  grant  Carnegie
29a00eb709Srvb  * Mellon the rights to redistribute these changes without encumbrance.
30a00eb709Srvb  *
319187d280Srvb  * 	@(#) coda/coda_psdev.c,v 1.1.1.1 1998/08/29 21:26:45 rvb Exp $
322eec68d7Srvb  */
332eec68d7Srvb 
342eec68d7Srvb /*
352eec68d7Srvb  * Mach Operating System
362eec68d7Srvb  * Copyright (c) 1989 Carnegie-Mellon University
372eec68d7Srvb  * All rights reserved.  The CMU software License Agreement specifies
382eec68d7Srvb  * the terms and conditions for use and redistribution.
392eec68d7Srvb  */
402eec68d7Srvb 
412eec68d7Srvb /*
422eec68d7Srvb  * This code was written for the Coda file system at Carnegie Mellon
432eec68d7Srvb  * University.  Contributers include David Steere, James Kistler, and
442eec68d7Srvb  * M. Satyanarayanan.  */
452eec68d7Srvb 
4696125fbeSjdolecek /* These routines define the pseudo device for communication between
472eec68d7Srvb  * Coda's Venus and Minicache in Mach 2.6. They used to be in cfs_subr.c,
482eec68d7Srvb  * but I moved them to make it easier to port the Minicache without
492eec68d7Srvb  * porting coda. -- DCS 10/12/94
5096125fbeSjdolecek  *
5196125fbeSjdolecek  * Following code depends on file-system CODA.
522eec68d7Srvb  */
532eec68d7Srvb 
542eec68d7Srvb /* These routines are the device entry points for Venus. */
552eec68d7Srvb 
56a13b5687Slukem #include <sys/cdefs.h>
57*4ea2e44bSthorpej __KERNEL_RCSID(0, "$NetBSD: coda_psdev.c,v 1.65 2024/05/17 23:57:46 thorpej Exp $");
58a13b5687Slukem 
590aa47cd0Srvb extern int coda_nc_initialized;    /* Set if cache has been initialized */
602eec68d7Srvb 
612eec68d7Srvb #include <sys/param.h>
622eec68d7Srvb #include <sys/systm.h>
632eec68d7Srvb #include <sys/kernel.h>
642eec68d7Srvb #include <sys/proc.h>
652eec68d7Srvb #include <sys/mount.h>
662eec68d7Srvb #include <sys/file.h>
672eec68d7Srvb #include <sys/ioctl.h>
682eec68d7Srvb #include <sys/poll.h>
692eec68d7Srvb #include <sys/select.h>
7077a6b82bSgehenna #include <sys/conf.h>
7142d06267Sad #include <sys/atomic.h>
72704aca39Schristos #include <sys/module.h>
732eec68d7Srvb 
749187d280Srvb #include <coda/coda.h>
759187d280Srvb #include <coda/cnode.h>
769187d280Srvb #include <coda/coda_namecache.h>
779187d280Srvb #include <coda/coda_io.h>
782eec68d7Srvb 
79e7ae23fdSchristos #include "ioconf.h"
80e7ae23fdSchristos 
81a00eb709Srvb #define CTL_C
822eec68d7Srvb 
830aa47cd0Srvb int coda_psdev_print_entry = 0;
84e7f0c598Srvb static
85e7f0c598Srvb int outstanding_upcalls = 0;
86e7f0c598Srvb int coda_call_sleep = PZERO - 1;
87e7f0c598Srvb #ifdef	CTL_C
88e7f0c598Srvb int coda_pcatch = PCATCH;
89e7f0c598Srvb #else
90e7f0c598Srvb #endif
912eec68d7Srvb 
92704aca39Schristos int coda_kernel_version = CODA_KERNEL_VERSION;
93704aca39Schristos 
940b5814f1Sperry #define ENTRY if(coda_psdev_print_entry) myprintf(("Entered %s\n",__func__))
950aa47cd0Srvb 
9677a6b82bSgehenna dev_type_open(vc_nb_open);
9777a6b82bSgehenna dev_type_close(vc_nb_close);
9877a6b82bSgehenna dev_type_read(vc_nb_read);
9977a6b82bSgehenna dev_type_write(vc_nb_write);
10077a6b82bSgehenna dev_type_ioctl(vc_nb_ioctl);
10177a6b82bSgehenna dev_type_poll(vc_nb_poll);
102e0cc03a0Sjdolecek dev_type_kqfilter(vc_nb_kqfilter);
10377a6b82bSgehenna 
10477a6b82bSgehenna const struct cdevsw vcoda_cdevsw = {
105a68f9396Sdholland 	.d_open = vc_nb_open,
106a68f9396Sdholland 	.d_close = vc_nb_close,
107a68f9396Sdholland 	.d_read = vc_nb_read,
108a68f9396Sdholland 	.d_write = vc_nb_write,
109a68f9396Sdholland 	.d_ioctl = vc_nb_ioctl,
110a68f9396Sdholland 	.d_stop = nostop,
111a68f9396Sdholland 	.d_tty = notty,
112a68f9396Sdholland 	.d_poll = vc_nb_poll,
113a68f9396Sdholland 	.d_mmap = nommap,
114a68f9396Sdholland 	.d_kqfilter = vc_nb_kqfilter,
115f9228f42Sdholland 	.d_discard = nodiscard,
116a68f9396Sdholland 	.d_flag = D_OTHER,
11777a6b82bSgehenna };
11877a6b82bSgehenna 
1192eec68d7Srvb struct vmsg {
12072ac0bccSplunky     TAILQ_ENTRY(vmsg) vm_chain;
12153524e44Schristos     void *	 vm_data;
1222eec68d7Srvb     u_short	 vm_flags;
1232eec68d7Srvb     u_short      vm_inSize;	/* Size is at most 5000 bytes */
1242eec68d7Srvb     u_short	 vm_outSize;
1252eec68d7Srvb     u_short	 vm_opcode; 	/* copied from data to save ptr lookup */
1262eec68d7Srvb     int		 vm_unique;
12753524e44Schristos     void *	 vm_sleep;	/* Not used by Mach. */
1282eec68d7Srvb };
1292eec68d7Srvb 
130704aca39Schristos struct coda_mntinfo coda_mnttbl[NVCODA];
131704aca39Schristos 
1322eec68d7Srvb #define	VM_READ	    1
1332eec68d7Srvb #define	VM_WRITE    2
1342eec68d7Srvb #define	VM_INTR	    4
1352eec68d7Srvb 
1360aa47cd0Srvb /* vcodaattach: do nothing */
1372eec68d7Srvb void
vcodaattach(int n)138168cd830Schristos vcodaattach(int n)
1392eec68d7Srvb {
1402eec68d7Srvb }
1412eec68d7Srvb 
1422eec68d7Srvb /*
1432eec68d7Srvb  * These functions are written for NetBSD.
1442eec68d7Srvb  */
1452eec68d7Srvb int
vc_nb_open(dev_t dev,int flag,int mode,struct lwp * l)146168cd830Schristos vc_nb_open(dev_t dev, int flag, int mode,
147168cd830Schristos     struct lwp *l)
1482eec68d7Srvb {
149a82aeb55Saugustss     struct vcomm *vcp;
1502eec68d7Srvb 
1512eec68d7Srvb     ENTRY;
1522eec68d7Srvb 
153461a86f9Schristos     if (minor(dev) >= NVCODA)
1542eec68d7Srvb 	return(ENXIO);
1552eec68d7Srvb 
1560aa47cd0Srvb     if (!coda_nc_initialized)
1570aa47cd0Srvb 	coda_nc_init();
1582eec68d7Srvb 
1590aa47cd0Srvb     vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
1602eec68d7Srvb     if (VC_OPEN(vcp))
1612eec68d7Srvb 	return(EBUSY);
1622eec68d7Srvb 
163c6186facSrmind     selinit(&vcp->vc_selproc);
16472ac0bccSplunky     TAILQ_INIT(&vcp->vc_requests);
16572ac0bccSplunky     TAILQ_INIT(&vcp->vc_replies);
1662eec68d7Srvb     MARK_VC_OPEN(vcp);
1672eec68d7Srvb 
1680aa47cd0Srvb     coda_mnttbl[minor(dev)].mi_vfsp = NULL;
1690aa47cd0Srvb     coda_mnttbl[minor(dev)].mi_rootvp = NULL;
1702eec68d7Srvb 
1712eec68d7Srvb     return(0);
1722eec68d7Srvb }
1732eec68d7Srvb 
1742eec68d7Srvb int
vc_nb_close(dev_t dev,int flag,int mode,struct lwp * l)175168cd830Schristos vc_nb_close(dev_t dev, int flag, int mode, struct lwp *l)
1762eec68d7Srvb {
177a82aeb55Saugustss     struct vcomm *vcp;
17872ac0bccSplunky     struct vmsg *vmp;
1790aa47cd0Srvb     struct coda_mntinfo *mi;
1802eec68d7Srvb     int                 err;
1812eec68d7Srvb 
1822eec68d7Srvb     ENTRY;
1832eec68d7Srvb 
184461a86f9Schristos     if (minor(dev) >= NVCODA)
1852eec68d7Srvb 	return(ENXIO);
1862eec68d7Srvb 
1870aa47cd0Srvb     mi = &coda_mnttbl[minor(dev)];
1882eec68d7Srvb     vcp = &(mi->mi_vcomm);
1892eec68d7Srvb 
1902eec68d7Srvb     if (!VC_OPEN(vcp))
1912eec68d7Srvb 	panic("vcclose: not open");
1922eec68d7Srvb 
1932eec68d7Srvb     /* prevent future operations on this vfs from succeeding by auto-
1942eec68d7Srvb      * unmounting any vfs mounted via this device. This frees user or
1952eec68d7Srvb      * sysadm from having to remember where all mount points are located.
1962eec68d7Srvb      * Put this before WAKEUPs to avoid queuing new messages between
1972eec68d7Srvb      * the WAKEUP and the unmount (which can happen if we're unlucky)
1982eec68d7Srvb      */
199e7f0c598Srvb     if (!mi->mi_rootvp) {
200e7f0c598Srvb 	/* just a simple open/close w no mount */
201e7f0c598Srvb 	MARK_VC_CLOSED(vcp);
202e7f0c598Srvb 	return 0;
203e7f0c598Srvb     }
204e7f0c598Srvb 
2052eec68d7Srvb     /* Let unmount know this is for real */
2062eec68d7Srvb     VTOC(mi->mi_rootvp)->c_flags |= C_UNMOUNTING;
2070aa47cd0Srvb     coda_unmounting(mi->mi_vfsp);
2082eec68d7Srvb 
2092eec68d7Srvb     /* Wakeup clients so they can return. */
21072ac0bccSplunky     while ((vmp = TAILQ_FIRST(&vcp->vc_requests)) != NULL) {
21172ac0bccSplunky 	TAILQ_REMOVE(&vcp->vc_requests, vmp, vm_chain);
21272ac0bccSplunky 
2132eec68d7Srvb 	/* Free signal request messages and don't wakeup cause
2142eec68d7Srvb 	   no one is waiting. */
2150aa47cd0Srvb 	if (vmp->vm_opcode == CODA_SIGNAL) {
2166e030479Splunky 	    CODA_FREE(vmp->vm_data, VC_IN_NO_DATA);
2176e030479Splunky 	    CODA_FREE(vmp, sizeof(struct vmsg));
2182eec68d7Srvb 	    continue;
2192eec68d7Srvb 	}
220e7f0c598Srvb 	outstanding_upcalls++;
2212eec68d7Srvb 	wakeup(&vmp->vm_sleep);
2222eec68d7Srvb     }
2232eec68d7Srvb 
22472ac0bccSplunky     while ((vmp = TAILQ_FIRST(&vcp->vc_replies)) != NULL) {
22572ac0bccSplunky 	TAILQ_REMOVE(&vcp->vc_replies, vmp, vm_chain);
22672ac0bccSplunky 
227e7f0c598Srvb 	outstanding_upcalls++;
2282eec68d7Srvb 	wakeup(&vmp->vm_sleep);
2292eec68d7Srvb     }
2302eec68d7Srvb 
2312eec68d7Srvb     MARK_VC_CLOSED(vcp);
232e7f0c598Srvb 
233e7f0c598Srvb     if (outstanding_upcalls) {
234e7f0c598Srvb #ifdef	CODA_VERBOSE
235e7f0c598Srvb 	printf("presleep: outstanding_upcalls = %d\n", outstanding_upcalls);
236e7f0c598Srvb     	(void) tsleep(&outstanding_upcalls, coda_call_sleep, "coda_umount", 0);
237e7f0c598Srvb 	printf("postsleep: outstanding_upcalls = %d\n", outstanding_upcalls);
238e7f0c598Srvb #else
239e7f0c598Srvb     	(void) tsleep(&outstanding_upcalls, coda_call_sleep, "coda_umount", 0);
240e7f0c598Srvb #endif
241e7f0c598Srvb     }
242e7f0c598Srvb 
24395e1ffb1Schristos     err = dounmount(mi->mi_vfsp, flag, l);
244e7f0c598Srvb     if (err)
245461a86f9Schristos 	myprintf(("Error %d unmounting vfs in vcclose(%llu)\n",
246461a86f9Schristos 	           err, (unsigned long long)minor(dev)));
247c6186facSrmind     seldestroy(&vcp->vc_selproc);
2482eec68d7Srvb     return 0;
2492eec68d7Srvb }
2502eec68d7Srvb 
2512eec68d7Srvb int
vc_nb_read(dev_t dev,struct uio * uiop,int flag)252168cd830Schristos vc_nb_read(dev_t dev, struct uio *uiop, int flag)
2532eec68d7Srvb {
254a82aeb55Saugustss     struct vcomm *	vcp;
255a82aeb55Saugustss     struct vmsg *vmp;
2562eec68d7Srvb     int error = 0;
2572eec68d7Srvb 
2582eec68d7Srvb     ENTRY;
2592eec68d7Srvb 
260461a86f9Schristos     if (minor(dev) >= NVCODA)
2612eec68d7Srvb 	return(ENXIO);
2622eec68d7Srvb 
2630aa47cd0Srvb     vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
2642eec68d7Srvb 
26572ac0bccSplunky     /* Get message at head of request queue. */
26672ac0bccSplunky     vmp = TAILQ_FIRST(&vcp->vc_requests);
26772ac0bccSplunky     if (vmp == NULL)
26872ac0bccSplunky 	return(0);	/* Nothing to read */
2692eec68d7Srvb 
2702eec68d7Srvb     /* Move the input args into userspace */
2712eec68d7Srvb     uiop->uio_rw = UIO_READ;
2722eec68d7Srvb     error = uiomove(vmp->vm_data, vmp->vm_inSize, uiop);
2732eec68d7Srvb     if (error) {
2742eec68d7Srvb 	myprintf(("vcread: error (%d) on uiomove\n", error));
2752eec68d7Srvb 	error = EINVAL;
2762eec68d7Srvb     }
2772eec68d7Srvb 
27872ac0bccSplunky     TAILQ_REMOVE(&vcp->vc_requests, vmp, vm_chain);
2792eec68d7Srvb 
2802eec68d7Srvb     /* If request was a signal, free up the message and don't
2812eec68d7Srvb        enqueue it in the reply queue. */
2820aa47cd0Srvb     if (vmp->vm_opcode == CODA_SIGNAL) {
2830aa47cd0Srvb 	if (codadebug)
2842eec68d7Srvb 	    myprintf(("vcread: signal msg (%d, %d)\n",
2852eec68d7Srvb 		      vmp->vm_opcode, vmp->vm_unique));
2866e030479Splunky 	CODA_FREE(vmp->vm_data, VC_IN_NO_DATA);
2876e030479Splunky 	CODA_FREE(vmp, sizeof(struct vmsg));
2882eec68d7Srvb 	return(error);
2892eec68d7Srvb     }
2902eec68d7Srvb 
2912eec68d7Srvb     vmp->vm_flags |= VM_READ;
29272ac0bccSplunky     TAILQ_INSERT_TAIL(&vcp->vc_replies, vmp, vm_chain);
2932eec68d7Srvb 
2942eec68d7Srvb     return(error);
2952eec68d7Srvb }
2962eec68d7Srvb 
2972eec68d7Srvb int
vc_nb_write(dev_t dev,struct uio * uiop,int flag)298168cd830Schristos vc_nb_write(dev_t dev, struct uio *uiop, int flag)
2992eec68d7Srvb {
300a82aeb55Saugustss     struct vcomm *	vcp;
301a82aeb55Saugustss     struct vmsg *vmp;
3020aa47cd0Srvb     struct coda_out_hdr *out;
3032eec68d7Srvb     u_long seq;
3042eec68d7Srvb     u_long opcode;
30581cb2a76Schristos     int tbuf[2];
3062eec68d7Srvb     int error = 0;
3072eec68d7Srvb 
3082eec68d7Srvb     ENTRY;
3092eec68d7Srvb 
310461a86f9Schristos     if (minor(dev) >= NVCODA)
3112eec68d7Srvb 	return(ENXIO);
3122eec68d7Srvb 
3130aa47cd0Srvb     vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
3142eec68d7Srvb 
3150ac7f4ddSandvar     /* Peek at the opcode, unique without transferring the data. */
3162eec68d7Srvb     uiop->uio_rw = UIO_WRITE;
3176e030479Splunky     error = uiomove(tbuf, sizeof(int) * 2, uiop);
3182eec68d7Srvb     if (error) {
3192eec68d7Srvb 	myprintf(("vcwrite: error (%d) on uiomove\n", error));
3202eec68d7Srvb 	return(EINVAL);
3212eec68d7Srvb     }
3222eec68d7Srvb 
32381cb2a76Schristos     opcode = tbuf[0];
32481cb2a76Schristos     seq = tbuf[1];
3252eec68d7Srvb 
3260aa47cd0Srvb     if (codadebug)
3272eec68d7Srvb 	myprintf(("vcwrite got a call for %ld.%ld\n", opcode, seq));
3282eec68d7Srvb 
3292eec68d7Srvb     if (DOWNCALL(opcode)) {
3302eec68d7Srvb 	union outputArgs pbuf;
3312eec68d7Srvb 
3322eec68d7Srvb 	/* get the rest of the data. */
3332eec68d7Srvb 	uiop->uio_rw = UIO_WRITE;
3346e030479Splunky 	error = uiomove(&pbuf.coda_purgeuser.oh.result, sizeof(pbuf) - (sizeof(int)*2), uiop);
3352eec68d7Srvb 	if (error) {
3362eec68d7Srvb 	    myprintf(("vcwrite: error (%d) on uiomove (Op %ld seq %ld)\n",
3372eec68d7Srvb 		      error, opcode, seq));
3382eec68d7Srvb 	    return(EINVAL);
3392eec68d7Srvb 	    }
3402eec68d7Srvb 
3412eec68d7Srvb 	return handleDownCall(opcode, &pbuf);
3422eec68d7Srvb     }
3432eec68d7Srvb 
3442eec68d7Srvb     /* Look for the message on the (waiting for) reply queue. */
34572ac0bccSplunky     TAILQ_FOREACH(vmp, &vcp->vc_replies, vm_chain) {
3462eec68d7Srvb 	if (vmp->vm_unique == seq) break;
3472eec68d7Srvb     }
3482eec68d7Srvb 
34972ac0bccSplunky     if (vmp == NULL) {
3500aa47cd0Srvb 	if (codadebug)
3512eec68d7Srvb 	    myprintf(("vcwrite: msg (%ld, %ld) not found\n", opcode, seq));
3522eec68d7Srvb 
3532eec68d7Srvb 	return(ESRCH);
3542eec68d7Srvb     }
3552eec68d7Srvb 
3562eec68d7Srvb     /* Remove the message from the reply queue */
35772ac0bccSplunky     TAILQ_REMOVE(&vcp->vc_replies, vmp, vm_chain);
3582eec68d7Srvb 
3592eec68d7Srvb     /* move data into response buffer. */
3600aa47cd0Srvb     out = (struct coda_out_hdr *)vmp->vm_data;
3612eec68d7Srvb     /* Don't need to copy opcode and uniquifier. */
3622eec68d7Srvb 
3632eec68d7Srvb     /* get the rest of the data. */
3642eec68d7Srvb     if (vmp->vm_outSize < uiop->uio_resid) {
3659aab9d33Smatt 	myprintf(("vcwrite: more data than asked for (%d < %lu)\n",
3669aab9d33Smatt 		  vmp->vm_outSize, (unsigned long) uiop->uio_resid));
3672eec68d7Srvb 	wakeup(&vmp->vm_sleep); 	/* Notify caller of the error. */
3682eec68d7Srvb 	return(EINVAL);
3692eec68d7Srvb     }
3702eec68d7Srvb 
37181cb2a76Schristos     tbuf[0] = uiop->uio_resid; 	/* Save this value. */
3722eec68d7Srvb     uiop->uio_rw = UIO_WRITE;
3736e030479Splunky     error = uiomove(&out->result, vmp->vm_outSize - (sizeof(int) * 2), uiop);
3742eec68d7Srvb     if (error) {
3752eec68d7Srvb 	myprintf(("vcwrite: error (%d) on uiomove (op %ld seq %ld)\n",
3762eec68d7Srvb 		  error, opcode, seq));
3772eec68d7Srvb 	return(EINVAL);
3782eec68d7Srvb     }
3792eec68d7Srvb 
3802eec68d7Srvb     /* I don't think these are used, but just in case. */
3812eec68d7Srvb     /* XXX - aren't these two already correct? -bnoble */
3822eec68d7Srvb     out->opcode = opcode;
3832eec68d7Srvb     out->unique = seq;
38481cb2a76Schristos     vmp->vm_outSize	= tbuf[0];	/* Amount of data transferred? */
3852eec68d7Srvb     vmp->vm_flags |= VM_WRITE;
3862eec68d7Srvb     wakeup(&vmp->vm_sleep);
3872eec68d7Srvb 
3882eec68d7Srvb     return(0);
3892eec68d7Srvb }
3902eec68d7Srvb 
3912eec68d7Srvb int
vc_nb_ioctl(dev_t dev,u_long cmd,void * addr,int flag,struct lwp * l)39253524e44Schristos vc_nb_ioctl(dev_t dev, u_long cmd, void *addr, int flag,
393168cd830Schristos     struct lwp *l)
3942eec68d7Srvb {
3952eec68d7Srvb     ENTRY;
3962eec68d7Srvb 
3972eec68d7Srvb     switch (cmd) {
3980aa47cd0Srvb     case CODARESIZE: {
3990aa47cd0Srvb 	struct coda_resize *data = (struct coda_resize *)addr;
4000aa47cd0Srvb 	return(coda_nc_resize(data->hashsize, data->heapsize, IS_DOWNCALL));
4012eec68d7Srvb 	break;
4022eec68d7Srvb     }
4030aa47cd0Srvb     case CODASTATS:
4040aa47cd0Srvb 	if (coda_nc_use) {
4050aa47cd0Srvb 	    coda_nc_gather_stats();
4062eec68d7Srvb 	    return(0);
4072eec68d7Srvb 	} else {
4082eec68d7Srvb 	    return(ENODEV);
4092eec68d7Srvb 	}
4102eec68d7Srvb 	break;
4110aa47cd0Srvb     case CODAPRINT:
4120aa47cd0Srvb 	if (coda_nc_use) {
4130aa47cd0Srvb 	    print_coda_nc();
4142eec68d7Srvb 	    return(0);
4152eec68d7Srvb 	} else {
4162eec68d7Srvb 	    return(ENODEV);
4172eec68d7Srvb 	}
4182eec68d7Srvb 	break;
419b951d6c0Srvb     case CIOC_KERNEL_VERSION:
420b951d6c0Srvb 	switch (*(u_int *)addr) {
421b951d6c0Srvb 	case 0:
422b951d6c0Srvb 		*(u_int *)addr = coda_kernel_version;
423b951d6c0Srvb 		return 0;
424b951d6c0Srvb 		break;
425b951d6c0Srvb 	case 1:
426b951d6c0Srvb 	case 2:
427b951d6c0Srvb 		if (coda_kernel_version != *(u_int *)addr)
428b951d6c0Srvb 		    return ENOENT;
429b951d6c0Srvb 		else
430b951d6c0Srvb 		    return 0;
431b951d6c0Srvb 	default:
432b951d6c0Srvb 		return ENOENT;
433b951d6c0Srvb 	}
434b951d6c0Srvb     	break;
4352eec68d7Srvb     default :
4362eec68d7Srvb 	return(EINVAL);
4372eec68d7Srvb 	break;
4382eec68d7Srvb     }
4392eec68d7Srvb }
4402eec68d7Srvb 
4412eec68d7Srvb int
vc_nb_poll(dev_t dev,int events,struct lwp * l)44295e1ffb1Schristos vc_nb_poll(dev_t dev, int events, struct lwp *l)
4432eec68d7Srvb {
444a82aeb55Saugustss     struct vcomm *vcp;
4452eec68d7Srvb     int event_msk = 0;
4462eec68d7Srvb 
4472eec68d7Srvb     ENTRY;
4482eec68d7Srvb 
449461a86f9Schristos     if (minor(dev) >= NVCODA)
4502eec68d7Srvb 	return(ENXIO);
4512eec68d7Srvb 
4520aa47cd0Srvb     vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
4532eec68d7Srvb 
4542eec68d7Srvb     event_msk = events & (POLLIN|POLLRDNORM);
4552eec68d7Srvb     if (!event_msk)
4562eec68d7Srvb 	return(0);
4572eec68d7Srvb 
45872ac0bccSplunky     if (!TAILQ_EMPTY(&vcp->vc_requests))
4592eec68d7Srvb 	return(events & (POLLIN|POLLRDNORM));
4602eec68d7Srvb 
46195e1ffb1Schristos     selrecord(l, &(vcp->vc_selproc));
4622eec68d7Srvb 
4632eec68d7Srvb     return(0);
4642eec68d7Srvb }
4652eec68d7Srvb 
466e0cc03a0Sjdolecek static void
filt_vc_nb_detach(struct knote * kn)467e0cc03a0Sjdolecek filt_vc_nb_detach(struct knote *kn)
468e0cc03a0Sjdolecek {
469e0cc03a0Sjdolecek 	struct vcomm *vcp = kn->kn_hook;
470e0cc03a0Sjdolecek 
4711c3a0558Sthorpej 	selremove_knote(&vcp->vc_selproc, kn);
472e0cc03a0Sjdolecek }
473e0cc03a0Sjdolecek 
474e0cc03a0Sjdolecek static int
filt_vc_nb_read(struct knote * kn,long hint)475168cd830Schristos filt_vc_nb_read(struct knote *kn, long hint)
476e0cc03a0Sjdolecek {
477e0cc03a0Sjdolecek 	struct vcomm *vcp = kn->kn_hook;
478e0cc03a0Sjdolecek 	struct vmsg *vmp;
479e0cc03a0Sjdolecek 
48072ac0bccSplunky 	vmp = TAILQ_FIRST(&vcp->vc_requests);
48172ac0bccSplunky 	if (vmp == NULL)
482e0cc03a0Sjdolecek 		return (0);
483e0cc03a0Sjdolecek 
484e0cc03a0Sjdolecek 	kn->kn_data = vmp->vm_inSize;
485e0cc03a0Sjdolecek 	return (1);
486e0cc03a0Sjdolecek }
487e0cc03a0Sjdolecek 
48818b796d4Smaya static const struct filterops vc_nb_read_filtops = {
48912ae65d9Sthorpej 	.f_flags = FILTEROP_ISFD,
49018b796d4Smaya 	.f_attach = NULL,
49118b796d4Smaya 	.f_detach = filt_vc_nb_detach,
49218b796d4Smaya 	.f_event = filt_vc_nb_read,
49318b796d4Smaya };
494e0cc03a0Sjdolecek 
495e0cc03a0Sjdolecek int
vc_nb_kqfilter(dev_t dev,struct knote * kn)496e0cc03a0Sjdolecek vc_nb_kqfilter(dev_t dev, struct knote *kn)
497e0cc03a0Sjdolecek {
498e0cc03a0Sjdolecek 	struct vcomm *vcp;
499e0cc03a0Sjdolecek 
500e0cc03a0Sjdolecek 	ENTRY;
501e0cc03a0Sjdolecek 
502461a86f9Schristos 	if (minor(dev) >= NVCODA)
503e0cc03a0Sjdolecek 		return(ENXIO);
504e0cc03a0Sjdolecek 
505e0cc03a0Sjdolecek 	vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
506e0cc03a0Sjdolecek 
507e0cc03a0Sjdolecek 	switch (kn->kn_filter) {
508e0cc03a0Sjdolecek 	case EVFILT_READ:
509e0cc03a0Sjdolecek 		kn->kn_fop = &vc_nb_read_filtops;
510e0cc03a0Sjdolecek 		break;
511e0cc03a0Sjdolecek 
512e0cc03a0Sjdolecek 	default:
5134e38160dSpooka 		return (EINVAL);
514e0cc03a0Sjdolecek 	}
515e0cc03a0Sjdolecek 
516e0cc03a0Sjdolecek 	kn->kn_hook = vcp;
517e0cc03a0Sjdolecek 
5181c3a0558Sthorpej 	selrecord_knote(&vcp->vc_selproc, kn);
519e0cc03a0Sjdolecek 
520e0cc03a0Sjdolecek 	return (0);
521e0cc03a0Sjdolecek }
522e0cc03a0Sjdolecek 
5232eec68d7Srvb /*
5242eec68d7Srvb  * Statistics
5252eec68d7Srvb  */
5260aa47cd0Srvb struct coda_clstat coda_clstat;
5272eec68d7Srvb 
5282eec68d7Srvb /*
5297e681f70Swiz  * Key question: whether to sleep interruptably or uninterruptably when
5302eec68d7Srvb  * waiting for Venus.  The former seems better (cause you can ^C a
5312eec68d7Srvb  * job), but then GNU-EMACS completion breaks. Use tsleep with no
5322eec68d7Srvb  * timeout, and no longjmp happens. But, when sleeping
5332eec68d7Srvb  * "uninterruptibly", we don't get told if it returns abnormally
5342eec68d7Srvb  * (e.g. kill -9).
5352eec68d7Srvb  */
5362eec68d7Srvb 
5372eec68d7Srvb int
coda_call(struct coda_mntinfo * mntinfo,int inSize,int * outSize,void * buffer)538323d4b7aSxtraeme coda_call(struct coda_mntinfo *mntinfo, int inSize, int *outSize,
53953524e44Schristos 	void *buffer)
5402eec68d7Srvb {
5412eec68d7Srvb 	struct vcomm *vcp;
5422eec68d7Srvb 	struct vmsg *vmp;
5432eec68d7Srvb 	int error;
5442eec68d7Srvb #ifdef	CTL_C
54595e1ffb1Schristos 	struct lwp *l = curlwp;
54695e1ffb1Schristos 	struct proc *p = l->l_proc;
5479187d280Srvb 	sigset_t psig_omask;
5482eec68d7Srvb 	int i;
549b07ec3fcSad 	psig_omask = l->l_sigmask;	/* XXXSA */
5502eec68d7Srvb #endif
5512eec68d7Srvb 	if (mntinfo == NULL) {
5522eec68d7Srvb 	    /* Unlikely, but could be a race condition with a dying warden */
5532eec68d7Srvb 	    return ENODEV;
5542eec68d7Srvb 	}
5552eec68d7Srvb 
5562eec68d7Srvb 	vcp = &(mntinfo->mi_vcomm);
5572eec68d7Srvb 
5580aa47cd0Srvb 	coda_clstat.ncalls++;
5590aa47cd0Srvb 	coda_clstat.reqs[((struct coda_in_hdr *)buffer)->opcode]++;
5602eec68d7Srvb 
5612eec68d7Srvb 	if (!VC_OPEN(vcp))
5622eec68d7Srvb 	    return(ENODEV);
5632eec68d7Srvb 
5640aa47cd0Srvb 	CODA_ALLOC(vmp,struct vmsg *,sizeof(struct vmsg));
5652eec68d7Srvb 	/* Format the request message. */
5662eec68d7Srvb 	vmp->vm_data = buffer;
5672eec68d7Srvb 	vmp->vm_flags = 0;
5682eec68d7Srvb 	vmp->vm_inSize = inSize;
5692eec68d7Srvb 	vmp->vm_outSize
5702eec68d7Srvb 	    = *outSize ? *outSize : inSize; /* |buffer| >= inSize */
5710aa47cd0Srvb 	vmp->vm_opcode = ((struct coda_in_hdr *)buffer)->opcode;
5722eec68d7Srvb 	vmp->vm_unique = ++vcp->vc_seq;
5730aa47cd0Srvb 	if (codadebug)
5742eec68d7Srvb 	    myprintf(("Doing a call for %d.%d\n",
5752eec68d7Srvb 		      vmp->vm_opcode, vmp->vm_unique));
5762eec68d7Srvb 
5772eec68d7Srvb 	/* Fill in the common input args. */
5780aa47cd0Srvb 	((struct coda_in_hdr *)buffer)->unique = vmp->vm_unique;
5792eec68d7Srvb 
5802eec68d7Srvb 	/* Append msg to request queue and poke Venus. */
58172ac0bccSplunky 	TAILQ_INSERT_TAIL(&vcp->vc_requests, vmp, vm_chain);
582c6186facSrmind 	selnotify(&(vcp->vc_selproc), 0, 0);
5832eec68d7Srvb 
5842eec68d7Srvb 	/* We can be interrupted while we wait for Venus to process
5852eec68d7Srvb 	 * our request.  If the interrupt occurs before Venus has read
5862eec68d7Srvb 	 * the request, we dequeue and return. If it occurs after the
5872eec68d7Srvb 	 * read but before the reply, we dequeue, send a signal
5882eec68d7Srvb 	 * message, and return. If it occurs after the reply we ignore
5892eec68d7Srvb 	 * it. In no case do we want to restart the syscall.  If it
5902eec68d7Srvb 	 * was interrupted by a venus shutdown (vcclose), return
5912eec68d7Srvb 	 * ENODEV.  */
5922eec68d7Srvb 
5932eec68d7Srvb 	/* Ignore return, We have to check anyway */
5942eec68d7Srvb #ifdef	CTL_C
5950aa47cd0Srvb 	/* This is work in progress.  Setting coda_pcatch lets tsleep reawaken
5962eec68d7Srvb 	   on a ^c or ^z.  The problem is that emacs sets certain interrupts
5972eec68d7Srvb 	   as SA_RESTART.  This means that we should exit sleep handle the
5982eec68d7Srvb 	   "signal" and then go to sleep again.  Mostly this is done by letting
5992eec68d7Srvb 	   the syscall complete and be restarted.  We are not idempotent and
6002eec68d7Srvb 	   can not do this.  A better solution is necessary.
6012eec68d7Srvb 	 */
6022eec68d7Srvb 	i = 0;
6032eec68d7Srvb 	do {
6040aa47cd0Srvb 	    error = tsleep(&vmp->vm_sleep, (coda_call_sleep|coda_pcatch), "coda_call", hz*2);
6052eec68d7Srvb 	    if (error == 0)
6062eec68d7Srvb 	    	break;
607284c2b9aSad 	    mutex_enter(p->p_lock);
608b07ec3fcSad 	    if (error == EWOULDBLOCK) {
609976280c9Srvb #ifdef	CODA_VERBOSE
6100aa47cd0Srvb 		    printf("coda_call: tsleep TIMEOUT %d sec\n", 2+2*i);
611c559082bSrvb #endif
612b07ec3fcSad     	    } else if (sigispending(l, SIGIO)) {
613b07ec3fcSad 		    sigaddset(&l->l_sigmask, SIGIO);
614976280c9Srvb #ifdef	CODA_VERBOSE
6150aa47cd0Srvb 		    printf("coda_call: tsleep returns %d SIGIO, cnt %d\n", error, i);
616c559082bSrvb #endif
617b07ec3fcSad     	    } else if (sigispending(l, SIGALRM)) {
618b07ec3fcSad 		    sigaddset(&l->l_sigmask, SIGALRM);
619e7f0c598Srvb #ifdef	CODA_VERBOSE
620e7f0c598Srvb 		    printf("coda_call: tsleep returns %d SIGALRM, cnt %d\n", error, i);
621e7f0c598Srvb #endif
6222eec68d7Srvb 	    } else {
6239187d280Srvb 		    sigset_t tmp;
624b07ec3fcSad 		    tmp = p->p_sigpend.sp_set;	/* array assignment */
625b07ec3fcSad 		    sigminusset(&l->l_sigmask, &tmp);
6269187d280Srvb 
627976280c9Srvb #ifdef	CODA_VERBOSE
6280aa47cd0Srvb 		    printf("coda_call: tsleep returns %d, cnt %d\n", error, i);
6299187d280Srvb 		    printf("coda_call: siglist = %x.%x.%x.%x, sigmask = %x.%x.%x.%x, mask %x.%x.%x.%x\n",
630b07ec3fcSad 			    p->p_sigpend.sp_set.__bits[0], p->p_sigpend.sp_set.__bits[1],
631b07ec3fcSad 			    p->p_sigpend.sp_set.__bits[2], p->p_sigpend.sp_set.__bits[3],
632b07ec3fcSad 			    l->l_sigmask.__bits[0], l->l_sigmask.__bits[1],
633b07ec3fcSad 			    l->l_sigmask.__bits[2], l->l_sigmask.__bits[3],
6349187d280Srvb 			    tmp.__bits[0], tmp.__bits[1], tmp.__bits[2], tmp.__bits[3]);
635c559082bSrvb #endif
636284c2b9aSad 		    mutex_exit(p->p_lock);
6372eec68d7Srvb 		    break;
638c559082bSrvb #ifdef	notyet
639b07ec3fcSad 		    sigminusset(&l->l_sigmask, &p->p_sigpend.sp_set);
6409187d280Srvb 		    printf("coda_call: siglist = %x.%x.%x.%x, sigmask = %x.%x.%x.%x\n",
641b07ec3fcSad 			    p->p_sigpend.sp_set.__bits[0], p->p_sigpend.sp_set.__bits[1],
642b07ec3fcSad 			    p->p_sigpend.sp_set.__bits[2], p->p_sigpend.sp_set.__bits[3],
643b07ec3fcSad 			    l->l_sigmask.__bits[0], l->l_sigmask.__bits[1],
644b07ec3fcSad 			    l->l_sigmask.__bits[2], l->l_sigmask.__bits[3]);
645c559082bSrvb #endif
6462eec68d7Srvb 	    }
647284c2b9aSad 	    mutex_exit(p->p_lock);
648e7f0c598Srvb 	} while (error && i++ < 128 && VC_OPEN(vcp));
649b07ec3fcSad 	l->l_sigmask = psig_omask;	/* XXXSA */
6502eec68d7Srvb #else
6510aa47cd0Srvb 	(void) tsleep(&vmp->vm_sleep, coda_call_sleep, "coda_call", 0);
6522eec68d7Srvb #endif
6532eec68d7Srvb 	if (VC_OPEN(vcp)) {	/* Venus is still alive */
6542eec68d7Srvb  	/* Op went through, interrupt or not... */
6552eec68d7Srvb 	    if (vmp->vm_flags & VM_WRITE) {
6562eec68d7Srvb 		error = 0;
6572eec68d7Srvb 		*outSize = vmp->vm_outSize;
6582eec68d7Srvb 	    }
6592eec68d7Srvb 
6602eec68d7Srvb 	    else if (!(vmp->vm_flags & VM_READ)) {
6612eec68d7Srvb 		/* Interrupted before venus read it. */
662976280c9Srvb #ifdef	CODA_VERBOSE
663976280c9Srvb 		if (1)
664976280c9Srvb #else
665c559082bSrvb 		if (codadebug)
666c559082bSrvb #endif
6672eec68d7Srvb 		    myprintf(("interrupted before read: op = %d.%d, flags = %x\n",
6682eec68d7Srvb 			   vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
66972ac0bccSplunky 
67072ac0bccSplunky 		TAILQ_REMOVE(&vcp->vc_requests, vmp, vm_chain);
6712eec68d7Srvb 		error = EINTR;
6722eec68d7Srvb 	    }
6732eec68d7Srvb 
6742eec68d7Srvb 	    else {
6752eec68d7Srvb 		/* (!(vmp->vm_flags & VM_WRITE)) means interrupted after
6762eec68d7Srvb                    upcall started */
6772eec68d7Srvb 		/* Interrupted after start of upcall, send venus a signal */
6780aa47cd0Srvb 		struct coda_in_hdr *dog;
6792eec68d7Srvb 		struct vmsg *svmp;
6802eec68d7Srvb 
681976280c9Srvb #ifdef	CODA_VERBOSE
682976280c9Srvb 		if (1)
683976280c9Srvb #else
684c559082bSrvb 		if (codadebug)
685c559082bSrvb #endif
6862eec68d7Srvb 		    myprintf(("Sending Venus a signal: op = %d.%d, flags = %x\n",
6872eec68d7Srvb 			   vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
6882eec68d7Srvb 
68972ac0bccSplunky 		TAILQ_REMOVE(&vcp->vc_replies, vmp, vm_chain);
6902eec68d7Srvb 		error = EINTR;
6912eec68d7Srvb 
6920aa47cd0Srvb 		CODA_ALLOC(svmp, struct vmsg *, sizeof (struct vmsg));
6932eec68d7Srvb 
6940aa47cd0Srvb 		CODA_ALLOC((svmp->vm_data), char *, sizeof (struct coda_in_hdr));
6950aa47cd0Srvb 		dog = (struct coda_in_hdr *)svmp->vm_data;
6962eec68d7Srvb 
6972eec68d7Srvb 		svmp->vm_flags = 0;
6980aa47cd0Srvb 		dog->opcode = svmp->vm_opcode = CODA_SIGNAL;
6992eec68d7Srvb 		dog->unique = svmp->vm_unique = vmp->vm_unique;
7000aa47cd0Srvb 		svmp->vm_inSize = sizeof (struct coda_in_hdr);
7010aa47cd0Srvb /*??? rvb */	svmp->vm_outSize = sizeof (struct coda_in_hdr);
7022eec68d7Srvb 
7030aa47cd0Srvb 		if (codadebug)
70427b381f4Sandvar 		    myprintf(("coda_call: enqueuing signal msg (%d, %d)\n",
7052eec68d7Srvb 			   svmp->vm_opcode, svmp->vm_unique));
7062eec68d7Srvb 
707755dfb4fSplunky 		/* insert at head of queue */
708755dfb4fSplunky 		TAILQ_INSERT_HEAD(&vcp->vc_requests, svmp, vm_chain);
709c6186facSrmind 		selnotify(&(vcp->vc_selproc), 0, 0);
7102eec68d7Srvb 	    }
7112eec68d7Srvb 	}
7122eec68d7Srvb 
7132eec68d7Srvb 	else {	/* If venus died (!VC_OPEN(vcp)) */
714b8743242Srin 		if (codadebug) {
7152eec68d7Srvb 			myprintf(("vcclose woke op %d.%d flags %d\n",
7162eec68d7Srvb 			       vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
717b8743242Srin 		}
7182eec68d7Srvb 
7192eec68d7Srvb 		error = ENODEV;
7202eec68d7Srvb 	}
7212eec68d7Srvb 
7220aa47cd0Srvb 	CODA_FREE(vmp, sizeof(struct vmsg));
7232eec68d7Srvb 
724e7f0c598Srvb 	if (outstanding_upcalls > 0 && (--outstanding_upcalls == 0))
725e7f0c598Srvb 		wakeup(&outstanding_upcalls);
726e7f0c598Srvb 
7272eec68d7Srvb 	if (!error)
7280aa47cd0Srvb 		error = ((struct coda_out_hdr *)buffer)->result;
7292eec68d7Srvb 	return(error);
7302eec68d7Srvb }
7319187d280Srvb 
732704aca39Schristos MODULE(MODULE_CLASS_DRIVER, vcoda, NULL);
733704aca39Schristos 
734704aca39Schristos static int
vcoda_modcmd(modcmd_t cmd,void * arg)735704aca39Schristos vcoda_modcmd(modcmd_t cmd, void *arg)
736704aca39Schristos {
737289bc9f7Schristos 	int error = 0;
738704aca39Schristos 
739704aca39Schristos 	switch (cmd) {
740704aca39Schristos 	case MODULE_CMD_INIT:
741704aca39Schristos #ifdef _MODULE
74265fba946Sriz 	{
743289bc9f7Schristos 		int cmajor, dmajor;
744704aca39Schristos 		vcodaattach(NVCODA);
745704aca39Schristos 
746289bc9f7Schristos 		dmajor = cmajor = -1;
747704aca39Schristos 		return devsw_attach("vcoda", NULL, &dmajor,
748704aca39Schristos 		    &vcoda_cdevsw, &cmajor);
74965fba946Sriz 	}
750704aca39Schristos #endif
751704aca39Schristos 		break;
752704aca39Schristos 
753704aca39Schristos 	case MODULE_CMD_FINI:
754704aca39Schristos #ifdef _MODULE
755704aca39Schristos 		{
756704aca39Schristos 			for  (size_t i = 0; i < NVCODA; i++) {
757704aca39Schristos 				struct vcomm *vcp = &coda_mnttbl[i].mi_vcomm;
758704aca39Schristos 				if (VC_OPEN(vcp))
759704aca39Schristos 					return EBUSY;
760704aca39Schristos 			}
761e7bed289Sriastradh 			devsw_detach(NULL, &vcoda_cdevsw);
762704aca39Schristos 		}
763704aca39Schristos #endif
764704aca39Schristos 		break;
765704aca39Schristos 
766704aca39Schristos 	case MODULE_CMD_STAT:
767704aca39Schristos 		return ENOTTY;
768704aca39Schristos 
769704aca39Schristos 	default:
770704aca39Schristos 		return ENOTTY;
771704aca39Schristos 	}
772704aca39Schristos 	return error;
773704aca39Schristos }
774