Home | History | Annotate | Line # | Download | only in coda
coda_psdev.c revision 1.53
      1  1.53  dholland /*	$NetBSD: coda_psdev.c,v 1.53 2014/07/25 08:10:35 dholland Exp $	*/
      2   1.2       rvb 
      3   1.1       rvb /*
      4  1.27     perry  *
      5   1.2       rvb  *             Coda: an Experimental Distributed File System
      6   1.2       rvb  *                              Release 3.1
      7  1.27     perry  *
      8   1.2       rvb  *           Copyright (c) 1987-1998 Carnegie Mellon University
      9   1.2       rvb  *                          All Rights Reserved
     10  1.27     perry  *
     11   1.2       rvb  * Permission  to  use, copy, modify and distribute this software and its
     12   1.2       rvb  * documentation is hereby granted,  provided  that  both  the  copyright
     13   1.2       rvb  * notice  and  this  permission  notice  appear  in  all  copies  of the
     14   1.2       rvb  * software, derivative works or  modified  versions,  and  any  portions
     15   1.2       rvb  * thereof, and that both notices appear in supporting documentation, and
     16   1.2       rvb  * that credit is given to Carnegie Mellon University  in  all  documents
     17   1.2       rvb  * and publicity pertaining to direct or indirect use of this code or its
     18   1.2       rvb  * derivatives.
     19  1.27     perry  *
     20   1.2       rvb  * CODA IS AN EXPERIMENTAL SOFTWARE SYSTEM AND IS  KNOWN  TO  HAVE  BUGS,
     21   1.2       rvb  * SOME  OF  WHICH MAY HAVE SERIOUS CONSEQUENCES.  CARNEGIE MELLON ALLOWS
     22   1.2       rvb  * FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION.   CARNEGIE  MELLON
     23   1.2       rvb  * DISCLAIMS  ANY  LIABILITY  OF  ANY  KIND  FOR  ANY  DAMAGES WHATSOEVER
     24   1.2       rvb  * RESULTING DIRECTLY OR INDIRECTLY FROM THE USE OF THIS SOFTWARE  OR  OF
     25   1.2       rvb  * ANY DERIVATIVE WORK.
     26  1.27     perry  *
     27   1.2       rvb  * Carnegie  Mellon  encourages  users  of  this  software  to return any
     28   1.2       rvb  * improvements or extensions that  they  make,  and  to  grant  Carnegie
     29   1.2       rvb  * Mellon the rights to redistribute these changes without encumbrance.
     30  1.27     perry  *
     31  1.27     perry  * 	@(#) coda/coda_psdev.c,v 1.1.1.1 1998/08/29 21:26:45 rvb Exp $
     32   1.2       rvb  */
     33   1.1       rvb 
     34  1.27     perry /*
     35   1.1       rvb  * Mach Operating System
     36   1.1       rvb  * Copyright (c) 1989 Carnegie-Mellon University
     37   1.1       rvb  * All rights reserved.  The CMU software License Agreement specifies
     38   1.1       rvb  * the terms and conditions for use and redistribution.
     39   1.1       rvb  */
     40   1.1       rvb 
     41   1.1       rvb /*
     42   1.1       rvb  * This code was written for the Coda file system at Carnegie Mellon
     43   1.1       rvb  * University.  Contributers include David Steere, James Kistler, and
     44   1.1       rvb  * M. Satyanarayanan.  */
     45   1.1       rvb 
     46  1.24  jdolecek /* These routines define the pseudo device for communication between
     47  1.27     perry  * Coda's Venus and Minicache in Mach 2.6. They used to be in cfs_subr.c,
     48  1.27     perry  * but I moved them to make it easier to port the Minicache without
     49   1.1       rvb  * porting coda. -- DCS 10/12/94
     50  1.24  jdolecek  *
     51  1.24  jdolecek  * Following code depends on file-system CODA.
     52   1.1       rvb  */
     53   1.1       rvb 
     54   1.1       rvb /* These routines are the device entry points for Venus. */
     55  1.18     lukem 
     56  1.18     lukem #include <sys/cdefs.h>
     57  1.53  dholland __KERNEL_RCSID(0, "$NetBSD: coda_psdev.c,v 1.53 2014/07/25 08:10:35 dholland Exp $");
     58   1.1       rvb 
     59   1.3       rvb extern int coda_nc_initialized;    /* Set if cache has been initialized */
     60   1.1       rvb 
     61  1.46     pooka #ifndef _KERNEL_OPT
     62   1.5       rvb #define	NVCODA 4
     63   1.5       rvb #else
     64   1.3       rvb #include <vcoda.h>
     65   1.5       rvb #endif
     66   1.5       rvb 
     67   1.1       rvb #include <sys/param.h>
     68   1.1       rvb #include <sys/systm.h>
     69   1.1       rvb #include <sys/kernel.h>
     70   1.1       rvb #include <sys/malloc.h>
     71   1.1       rvb #include <sys/proc.h>
     72   1.1       rvb #include <sys/mount.h>
     73   1.1       rvb #include <sys/file.h>
     74   1.1       rvb #include <sys/ioctl.h>
     75   1.1       rvb #include <sys/poll.h>
     76   1.1       rvb #include <sys/select.h>
     77  1.20   gehenna #include <sys/conf.h>
     78  1.45        ad #include <sys/atomic.h>
     79  1.48  christos #include <sys/module.h>
     80   1.1       rvb 
     81  1.16   thorpej #include <miscfs/syncfs/syncfs.h>
     82  1.16   thorpej 
     83   1.4       rvb #include <coda/coda.h>
     84   1.4       rvb #include <coda/cnode.h>
     85   1.4       rvb #include <coda/coda_namecache.h>
     86   1.4       rvb #include <coda/coda_io.h>
     87   1.1       rvb 
     88   1.2       rvb #define CTL_C
     89   1.2       rvb 
     90   1.3       rvb int coda_psdev_print_entry = 0;
     91   1.8       rvb static
     92   1.8       rvb int outstanding_upcalls = 0;
     93   1.8       rvb int coda_call_sleep = PZERO - 1;
     94   1.8       rvb #ifdef	CTL_C
     95   1.8       rvb int coda_pcatch = PCATCH;
     96   1.8       rvb #else
     97   1.8       rvb #endif
     98   1.3       rvb 
     99  1.48  christos int coda_kernel_version = CODA_KERNEL_VERSION;
    100  1.48  christos 
    101  1.19     perry #define ENTRY if(coda_psdev_print_entry) myprintf(("Entered %s\n",__func__))
    102   1.1       rvb 
    103   1.3       rvb void vcodaattach(int n);
    104  1.20   gehenna 
    105  1.20   gehenna dev_type_open(vc_nb_open);
    106  1.20   gehenna dev_type_close(vc_nb_close);
    107  1.20   gehenna dev_type_read(vc_nb_read);
    108  1.20   gehenna dev_type_write(vc_nb_write);
    109  1.20   gehenna dev_type_ioctl(vc_nb_ioctl);
    110  1.20   gehenna dev_type_poll(vc_nb_poll);
    111  1.21  jdolecek dev_type_kqfilter(vc_nb_kqfilter);
    112  1.20   gehenna 
    113  1.20   gehenna const struct cdevsw vcoda_cdevsw = {
    114  1.52  dholland 	.d_open = vc_nb_open,
    115  1.52  dholland 	.d_close = vc_nb_close,
    116  1.52  dholland 	.d_read = vc_nb_read,
    117  1.52  dholland 	.d_write = vc_nb_write,
    118  1.52  dholland 	.d_ioctl = vc_nb_ioctl,
    119  1.52  dholland 	.d_stop = nostop,
    120  1.52  dholland 	.d_tty = notty,
    121  1.52  dholland 	.d_poll = vc_nb_poll,
    122  1.52  dholland 	.d_mmap = nommap,
    123  1.52  dholland 	.d_kqfilter = vc_nb_kqfilter,
    124  1.53  dholland 	.d_discard = nodiscard,
    125  1.52  dholland 	.d_flag = D_OTHER,
    126  1.20   gehenna };
    127   1.1       rvb 
    128   1.1       rvb struct vmsg {
    129  1.41    plunky     TAILQ_ENTRY(vmsg) vm_chain;
    130  1.36  christos     void *	 vm_data;
    131   1.1       rvb     u_short	 vm_flags;
    132   1.1       rvb     u_short      vm_inSize;	/* Size is at most 5000 bytes */
    133   1.1       rvb     u_short	 vm_outSize;
    134   1.1       rvb     u_short	 vm_opcode; 	/* copied from data to save ptr lookup */
    135   1.1       rvb     int		 vm_unique;
    136  1.36  christos     void *	 vm_sleep;	/* Not used by Mach. */
    137   1.1       rvb };
    138   1.1       rvb 
    139  1.48  christos struct coda_mntinfo coda_mnttbl[NVCODA];
    140  1.48  christos 
    141   1.1       rvb #define	VM_READ	    1
    142   1.1       rvb #define	VM_WRITE    2
    143   1.1       rvb #define	VM_INTR	    4
    144   1.1       rvb 
    145   1.3       rvb /* vcodaattach: do nothing */
    146   1.1       rvb void
    147  1.34  christos vcodaattach(int n)
    148   1.1       rvb {
    149   1.1       rvb }
    150   1.1       rvb 
    151  1.27     perry /*
    152   1.1       rvb  * These functions are written for NetBSD.
    153   1.1       rvb  */
    154  1.27     perry int
    155  1.34  christos vc_nb_open(dev_t dev, int flag, int mode,
    156  1.34  christos     struct lwp *l)
    157   1.1       rvb {
    158  1.13  augustss     struct vcomm *vcp;
    159  1.27     perry 
    160   1.1       rvb     ENTRY;
    161   1.1       rvb 
    162  1.47  christos     if (minor(dev) >= NVCODA)
    163   1.1       rvb 	return(ENXIO);
    164  1.27     perry 
    165   1.3       rvb     if (!coda_nc_initialized)
    166   1.3       rvb 	coda_nc_init();
    167  1.27     perry 
    168   1.3       rvb     vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
    169   1.1       rvb     if (VC_OPEN(vcp))
    170   1.1       rvb 	return(EBUSY);
    171  1.27     perry 
    172  1.39     rmind     selinit(&vcp->vc_selproc);
    173  1.41    plunky     TAILQ_INIT(&vcp->vc_requests);
    174  1.41    plunky     TAILQ_INIT(&vcp->vc_replies);
    175   1.1       rvb     MARK_VC_OPEN(vcp);
    176  1.27     perry 
    177   1.3       rvb     coda_mnttbl[minor(dev)].mi_vfsp = NULL;
    178   1.3       rvb     coda_mnttbl[minor(dev)].mi_rootvp = NULL;
    179   1.1       rvb 
    180   1.1       rvb     return(0);
    181   1.1       rvb }
    182   1.1       rvb 
    183  1.27     perry int
    184  1.34  christos vc_nb_close(dev_t dev, int flag, int mode, struct lwp *l)
    185   1.1       rvb {
    186  1.13  augustss     struct vcomm *vcp;
    187  1.41    plunky     struct vmsg *vmp;
    188   1.3       rvb     struct coda_mntinfo *mi;
    189   1.1       rvb     int                 err;
    190  1.27     perry 
    191   1.1       rvb     ENTRY;
    192   1.1       rvb 
    193  1.47  christos     if (minor(dev) >= NVCODA)
    194   1.1       rvb 	return(ENXIO);
    195   1.1       rvb 
    196   1.3       rvb     mi = &coda_mnttbl[minor(dev)];
    197   1.1       rvb     vcp = &(mi->mi_vcomm);
    198  1.27     perry 
    199   1.1       rvb     if (!VC_OPEN(vcp))
    200   1.1       rvb 	panic("vcclose: not open");
    201  1.27     perry 
    202   1.1       rvb     /* prevent future operations on this vfs from succeeding by auto-
    203   1.1       rvb      * unmounting any vfs mounted via this device. This frees user or
    204   1.1       rvb      * sysadm from having to remember where all mount points are located.
    205   1.1       rvb      * Put this before WAKEUPs to avoid queuing new messages between
    206   1.1       rvb      * the WAKEUP and the unmount (which can happen if we're unlucky)
    207   1.1       rvb      */
    208   1.8       rvb     if (!mi->mi_rootvp) {
    209   1.8       rvb 	/* just a simple open/close w no mount */
    210   1.8       rvb 	MARK_VC_CLOSED(vcp);
    211   1.8       rvb 	return 0;
    212   1.1       rvb     }
    213   1.8       rvb 
    214   1.8       rvb     /* Let unmount know this is for real */
    215   1.8       rvb     VTOC(mi->mi_rootvp)->c_flags |= C_UNMOUNTING;
    216   1.8       rvb     coda_unmounting(mi->mi_vfsp);
    217  1.27     perry 
    218   1.1       rvb     /* Wakeup clients so they can return. */
    219  1.41    plunky     while ((vmp = TAILQ_FIRST(&vcp->vc_requests)) != NULL) {
    220  1.41    plunky 	TAILQ_REMOVE(&vcp->vc_requests, vmp, vm_chain);
    221  1.41    plunky 
    222   1.1       rvb 	/* Free signal request messages and don't wakeup cause
    223   1.1       rvb 	   no one is waiting. */
    224   1.3       rvb 	if (vmp->vm_opcode == CODA_SIGNAL) {
    225  1.40    plunky 	    CODA_FREE(vmp->vm_data, VC_IN_NO_DATA);
    226  1.40    plunky 	    CODA_FREE(vmp, sizeof(struct vmsg));
    227   1.1       rvb 	    continue;
    228   1.1       rvb 	}
    229  1.27     perry 	outstanding_upcalls++;
    230   1.1       rvb 	wakeup(&vmp->vm_sleep);
    231   1.1       rvb     }
    232   1.8       rvb 
    233  1.41    plunky     while ((vmp = TAILQ_FIRST(&vcp->vc_replies)) != NULL) {
    234  1.41    plunky 	TAILQ_REMOVE(&vcp->vc_replies, vmp, vm_chain);
    235  1.41    plunky 
    236  1.27     perry 	outstanding_upcalls++;
    237   1.1       rvb 	wakeup(&vmp->vm_sleep);
    238   1.1       rvb     }
    239   1.8       rvb 
    240   1.1       rvb     MARK_VC_CLOSED(vcp);
    241   1.8       rvb 
    242   1.8       rvb     if (outstanding_upcalls) {
    243   1.8       rvb #ifdef	CODA_VERBOSE
    244   1.8       rvb 	printf("presleep: outstanding_upcalls = %d\n", outstanding_upcalls);
    245   1.8       rvb     	(void) tsleep(&outstanding_upcalls, coda_call_sleep, "coda_umount", 0);
    246   1.8       rvb 	printf("postsleep: outstanding_upcalls = %d\n", outstanding_upcalls);
    247   1.8       rvb #else
    248   1.8       rvb     	(void) tsleep(&outstanding_upcalls, coda_call_sleep, "coda_umount", 0);
    249   1.8       rvb #endif
    250   1.8       rvb     }
    251   1.8       rvb 
    252  1.31  christos     err = dounmount(mi->mi_vfsp, flag, l);
    253   1.8       rvb     if (err)
    254  1.47  christos 	myprintf(("Error %d unmounting vfs in vcclose(%llu)\n",
    255  1.47  christos 	           err, (unsigned long long)minor(dev)));
    256  1.39     rmind     seldestroy(&vcp->vc_selproc);
    257   1.1       rvb     return 0;
    258   1.1       rvb }
    259   1.1       rvb 
    260  1.27     perry int
    261  1.34  christos vc_nb_read(dev_t dev, struct uio *uiop, int flag)
    262   1.1       rvb {
    263  1.13  augustss     struct vcomm *	vcp;
    264  1.13  augustss     struct vmsg *vmp;
    265   1.1       rvb     int error = 0;
    266  1.27     perry 
    267   1.1       rvb     ENTRY;
    268   1.1       rvb 
    269  1.47  christos     if (minor(dev) >= NVCODA)
    270   1.1       rvb 	return(ENXIO);
    271  1.27     perry 
    272   1.3       rvb     vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
    273  1.41    plunky 
    274   1.1       rvb     /* Get message at head of request queue. */
    275  1.41    plunky     vmp = TAILQ_FIRST(&vcp->vc_requests);
    276  1.41    plunky     if (vmp == NULL)
    277   1.1       rvb 	return(0);	/* Nothing to read */
    278  1.27     perry 
    279   1.1       rvb     /* Move the input args into userspace */
    280   1.1       rvb     uiop->uio_rw = UIO_READ;
    281   1.1       rvb     error = uiomove(vmp->vm_data, vmp->vm_inSize, uiop);
    282   1.1       rvb     if (error) {
    283   1.1       rvb 	myprintf(("vcread: error (%d) on uiomove\n", error));
    284   1.1       rvb 	error = EINVAL;
    285   1.1       rvb     }
    286   1.1       rvb 
    287  1.41    plunky     TAILQ_REMOVE(&vcp->vc_requests, vmp, vm_chain);
    288  1.27     perry 
    289   1.1       rvb     /* If request was a signal, free up the message and don't
    290   1.1       rvb        enqueue it in the reply queue. */
    291   1.3       rvb     if (vmp->vm_opcode == CODA_SIGNAL) {
    292   1.3       rvb 	if (codadebug)
    293  1.27     perry 	    myprintf(("vcread: signal msg (%d, %d)\n",
    294   1.1       rvb 		      vmp->vm_opcode, vmp->vm_unique));
    295  1.40    plunky 	CODA_FREE(vmp->vm_data, VC_IN_NO_DATA);
    296  1.40    plunky 	CODA_FREE(vmp, sizeof(struct vmsg));
    297   1.1       rvb 	return(error);
    298   1.1       rvb     }
    299  1.27     perry 
    300   1.1       rvb     vmp->vm_flags |= VM_READ;
    301  1.41    plunky     TAILQ_INSERT_TAIL(&vcp->vc_replies, vmp, vm_chain);
    302  1.27     perry 
    303   1.1       rvb     return(error);
    304   1.1       rvb }
    305   1.1       rvb 
    306   1.1       rvb int
    307  1.34  christos vc_nb_write(dev_t dev, struct uio *uiop, int flag)
    308   1.1       rvb {
    309  1.13  augustss     struct vcomm *	vcp;
    310  1.13  augustss     struct vmsg *vmp;
    311   1.3       rvb     struct coda_out_hdr *out;
    312   1.1       rvb     u_long seq;
    313   1.1       rvb     u_long opcode;
    314  1.28  christos     int tbuf[2];
    315   1.1       rvb     int error = 0;
    316   1.1       rvb 
    317   1.1       rvb     ENTRY;
    318   1.1       rvb 
    319  1.47  christos     if (minor(dev) >= NVCODA)
    320   1.1       rvb 	return(ENXIO);
    321  1.27     perry 
    322   1.3       rvb     vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
    323  1.27     perry 
    324   1.1       rvb     /* Peek at the opcode, unique without transfering the data. */
    325   1.1       rvb     uiop->uio_rw = UIO_WRITE;
    326  1.40    plunky     error = uiomove(tbuf, sizeof(int) * 2, uiop);
    327   1.1       rvb     if (error) {
    328   1.1       rvb 	myprintf(("vcwrite: error (%d) on uiomove\n", error));
    329   1.1       rvb 	return(EINVAL);
    330   1.1       rvb     }
    331  1.27     perry 
    332  1.28  christos     opcode = tbuf[0];
    333  1.28  christos     seq = tbuf[1];
    334  1.27     perry 
    335   1.3       rvb     if (codadebug)
    336   1.1       rvb 	myprintf(("vcwrite got a call for %ld.%ld\n", opcode, seq));
    337  1.27     perry 
    338   1.1       rvb     if (DOWNCALL(opcode)) {
    339   1.1       rvb 	union outputArgs pbuf;
    340  1.27     perry 
    341   1.1       rvb 	/* get the rest of the data. */
    342   1.1       rvb 	uiop->uio_rw = UIO_WRITE;
    343  1.40    plunky 	error = uiomove(&pbuf.coda_purgeuser.oh.result, sizeof(pbuf) - (sizeof(int)*2), uiop);
    344   1.1       rvb 	if (error) {
    345  1.27     perry 	    myprintf(("vcwrite: error (%d) on uiomove (Op %ld seq %ld)\n",
    346   1.1       rvb 		      error, opcode, seq));
    347   1.1       rvb 	    return(EINVAL);
    348   1.1       rvb 	    }
    349  1.27     perry 
    350   1.1       rvb 	return handleDownCall(opcode, &pbuf);
    351   1.1       rvb     }
    352  1.27     perry 
    353   1.1       rvb     /* Look for the message on the (waiting for) reply queue. */
    354  1.41    plunky     TAILQ_FOREACH(vmp, &vcp->vc_replies, vm_chain) {
    355   1.1       rvb 	if (vmp->vm_unique == seq) break;
    356   1.1       rvb     }
    357  1.27     perry 
    358  1.41    plunky     if (vmp == NULL) {
    359   1.3       rvb 	if (codadebug)
    360   1.1       rvb 	    myprintf(("vcwrite: msg (%ld, %ld) not found\n", opcode, seq));
    361  1.27     perry 
    362   1.1       rvb 	return(ESRCH);
    363  1.41    plunky     }
    364  1.27     perry 
    365   1.1       rvb     /* Remove the message from the reply queue */
    366  1.41    plunky     TAILQ_REMOVE(&vcp->vc_replies, vmp, vm_chain);
    367  1.27     perry 
    368   1.1       rvb     /* move data into response buffer. */
    369   1.3       rvb     out = (struct coda_out_hdr *)vmp->vm_data;
    370   1.1       rvb     /* Don't need to copy opcode and uniquifier. */
    371  1.27     perry 
    372   1.1       rvb     /* get the rest of the data. */
    373   1.1       rvb     if (vmp->vm_outSize < uiop->uio_resid) {
    374  1.11      matt 	myprintf(("vcwrite: more data than asked for (%d < %lu)\n",
    375  1.11      matt 		  vmp->vm_outSize, (unsigned long) uiop->uio_resid));
    376   1.1       rvb 	wakeup(&vmp->vm_sleep); 	/* Notify caller of the error. */
    377   1.1       rvb 	return(EINVAL);
    378  1.27     perry     }
    379  1.27     perry 
    380  1.28  christos     tbuf[0] = uiop->uio_resid; 	/* Save this value. */
    381   1.1       rvb     uiop->uio_rw = UIO_WRITE;
    382  1.40    plunky     error = uiomove(&out->result, vmp->vm_outSize - (sizeof(int) * 2), uiop);
    383   1.1       rvb     if (error) {
    384  1.27     perry 	myprintf(("vcwrite: error (%d) on uiomove (op %ld seq %ld)\n",
    385   1.1       rvb 		  error, opcode, seq));
    386   1.1       rvb 	return(EINVAL);
    387   1.1       rvb     }
    388  1.27     perry 
    389   1.1       rvb     /* I don't think these are used, but just in case. */
    390   1.1       rvb     /* XXX - aren't these two already correct? -bnoble */
    391   1.1       rvb     out->opcode = opcode;
    392   1.1       rvb     out->unique = seq;
    393  1.28  christos     vmp->vm_outSize	= tbuf[0];	/* Amount of data transferred? */
    394   1.1       rvb     vmp->vm_flags |= VM_WRITE;
    395   1.1       rvb     wakeup(&vmp->vm_sleep);
    396  1.27     perry 
    397   1.1       rvb     return(0);
    398   1.1       rvb }
    399   1.1       rvb 
    400   1.1       rvb int
    401  1.36  christos vc_nb_ioctl(dev_t dev, u_long cmd, void *addr, int flag,
    402  1.34  christos     struct lwp *l)
    403   1.1       rvb {
    404   1.1       rvb     ENTRY;
    405   1.1       rvb 
    406   1.1       rvb     switch(cmd) {
    407   1.3       rvb     case CODARESIZE: {
    408   1.3       rvb 	struct coda_resize *data = (struct coda_resize *)addr;
    409   1.3       rvb 	return(coda_nc_resize(data->hashsize, data->heapsize, IS_DOWNCALL));
    410   1.1       rvb 	break;
    411   1.1       rvb     }
    412   1.3       rvb     case CODASTATS:
    413   1.3       rvb 	if (coda_nc_use) {
    414   1.3       rvb 	    coda_nc_gather_stats();
    415   1.1       rvb 	    return(0);
    416   1.1       rvb 	} else {
    417   1.1       rvb 	    return(ENODEV);
    418   1.1       rvb 	}
    419   1.1       rvb 	break;
    420   1.3       rvb     case CODAPRINT:
    421   1.3       rvb 	if (coda_nc_use) {
    422   1.3       rvb 	    print_coda_nc();
    423   1.1       rvb 	    return(0);
    424   1.1       rvb 	} else {
    425   1.1       rvb 	    return(ENODEV);
    426   1.1       rvb 	}
    427   1.1       rvb 	break;
    428   1.9       rvb     case CIOC_KERNEL_VERSION:
    429   1.9       rvb 	switch (*(u_int *)addr) {
    430   1.9       rvb 	case 0:
    431   1.9       rvb 		*(u_int *)addr = coda_kernel_version;
    432   1.9       rvb 		return 0;
    433   1.9       rvb 		break;
    434   1.9       rvb 	case 1:
    435   1.9       rvb 	case 2:
    436   1.9       rvb 		if (coda_kernel_version != *(u_int *)addr)
    437   1.9       rvb 		    return ENOENT;
    438   1.9       rvb 		else
    439   1.9       rvb 		    return 0;
    440   1.9       rvb 	default:
    441   1.9       rvb 		return ENOENT;
    442   1.9       rvb 	}
    443   1.9       rvb     	break;
    444   1.1       rvb     default :
    445   1.1       rvb 	return(EINVAL);
    446   1.1       rvb 	break;
    447   1.1       rvb     }
    448   1.1       rvb }
    449   1.1       rvb 
    450   1.1       rvb int
    451  1.31  christos vc_nb_poll(dev_t dev, int events, struct lwp *l)
    452   1.1       rvb {
    453  1.13  augustss     struct vcomm *vcp;
    454   1.1       rvb     int event_msk = 0;
    455   1.1       rvb 
    456   1.1       rvb     ENTRY;
    457  1.27     perry 
    458  1.47  christos     if (minor(dev) >= NVCODA)
    459   1.1       rvb 	return(ENXIO);
    460  1.27     perry 
    461   1.3       rvb     vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
    462  1.27     perry 
    463   1.1       rvb     event_msk = events & (POLLIN|POLLRDNORM);
    464   1.1       rvb     if (!event_msk)
    465   1.1       rvb 	return(0);
    466  1.27     perry 
    467  1.41    plunky     if (!TAILQ_EMPTY(&vcp->vc_requests))
    468   1.1       rvb 	return(events & (POLLIN|POLLRDNORM));
    469   1.1       rvb 
    470  1.31  christos     selrecord(l, &(vcp->vc_selproc));
    471  1.27     perry 
    472   1.1       rvb     return(0);
    473   1.1       rvb }
    474   1.1       rvb 
    475  1.21  jdolecek static void
    476  1.21  jdolecek filt_vc_nb_detach(struct knote *kn)
    477  1.21  jdolecek {
    478  1.21  jdolecek 	struct vcomm *vcp = kn->kn_hook;
    479  1.21  jdolecek 
    480  1.22  christos 	SLIST_REMOVE(&vcp->vc_selproc.sel_klist, kn, knote, kn_selnext);
    481  1.21  jdolecek }
    482  1.21  jdolecek 
    483  1.21  jdolecek static int
    484  1.34  christos filt_vc_nb_read(struct knote *kn, long hint)
    485  1.21  jdolecek {
    486  1.27     perry 	struct vcomm *vcp = kn->kn_hook;
    487  1.21  jdolecek 	struct vmsg *vmp;
    488  1.21  jdolecek 
    489  1.41    plunky 	vmp = TAILQ_FIRST(&vcp->vc_requests);
    490  1.41    plunky 	if (vmp == NULL)
    491  1.21  jdolecek 		return (0);
    492  1.21  jdolecek 
    493  1.21  jdolecek 	kn->kn_data = vmp->vm_inSize;
    494  1.21  jdolecek 	return (1);
    495  1.21  jdolecek }
    496  1.21  jdolecek 
    497  1.21  jdolecek static const struct filterops vc_nb_read_filtops =
    498  1.21  jdolecek 	{ 1, NULL, filt_vc_nb_detach, filt_vc_nb_read };
    499  1.21  jdolecek 
    500  1.21  jdolecek int
    501  1.21  jdolecek vc_nb_kqfilter(dev_t dev, struct knote *kn)
    502  1.21  jdolecek {
    503  1.21  jdolecek 	struct vcomm *vcp;
    504  1.21  jdolecek 	struct klist *klist;
    505  1.21  jdolecek 
    506  1.21  jdolecek 	ENTRY;
    507  1.27     perry 
    508  1.47  christos 	if (minor(dev) >= NVCODA)
    509  1.21  jdolecek 		return(ENXIO);
    510  1.27     perry 
    511  1.21  jdolecek 	vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
    512  1.21  jdolecek 
    513  1.21  jdolecek 	switch (kn->kn_filter) {
    514  1.21  jdolecek 	case EVFILT_READ:
    515  1.22  christos 		klist = &vcp->vc_selproc.sel_klist;
    516  1.21  jdolecek 		kn->kn_fop = &vc_nb_read_filtops;
    517  1.21  jdolecek 		break;
    518  1.21  jdolecek 
    519  1.21  jdolecek 	default:
    520  1.37     pooka 		return (EINVAL);
    521  1.21  jdolecek 	}
    522  1.21  jdolecek 
    523  1.21  jdolecek 	kn->kn_hook = vcp;
    524  1.21  jdolecek 
    525  1.21  jdolecek 	SLIST_INSERT_HEAD(klist, kn, kn_selnext);
    526  1.21  jdolecek 
    527  1.21  jdolecek 	return (0);
    528  1.21  jdolecek }
    529  1.21  jdolecek 
    530   1.1       rvb /*
    531   1.1       rvb  * Statistics
    532   1.1       rvb  */
    533   1.3       rvb struct coda_clstat coda_clstat;
    534   1.1       rvb 
    535  1.27     perry /*
    536  1.23       wiz  * Key question: whether to sleep interruptably or uninterruptably when
    537   1.1       rvb  * waiting for Venus.  The former seems better (cause you can ^C a
    538   1.1       rvb  * job), but then GNU-EMACS completion breaks. Use tsleep with no
    539   1.1       rvb  * timeout, and no longjmp happens. But, when sleeping
    540   1.1       rvb  * "uninterruptibly", we don't get told if it returns abnormally
    541  1.27     perry  * (e.g. kill -9).
    542   1.1       rvb  */
    543   1.1       rvb 
    544   1.1       rvb int
    545  1.30   xtraeme coda_call(struct coda_mntinfo *mntinfo, int inSize, int *outSize,
    546  1.36  christos 	void *buffer)
    547   1.1       rvb {
    548   1.1       rvb 	struct vcomm *vcp;
    549   1.1       rvb 	struct vmsg *vmp;
    550   1.1       rvb 	int error;
    551   1.1       rvb #ifdef	CTL_C
    552  1.31  christos 	struct lwp *l = curlwp;
    553  1.31  christos 	struct proc *p = l->l_proc;
    554   1.4       rvb 	sigset_t psig_omask;
    555   1.1       rvb 	int i;
    556  1.35        ad 	psig_omask = l->l_sigmask;	/* XXXSA */
    557   1.1       rvb #endif
    558   1.1       rvb 	if (mntinfo == NULL) {
    559   1.1       rvb 	    /* Unlikely, but could be a race condition with a dying warden */
    560   1.1       rvb 	    return ENODEV;
    561   1.1       rvb 	}
    562   1.1       rvb 
    563   1.1       rvb 	vcp = &(mntinfo->mi_vcomm);
    564  1.27     perry 
    565   1.3       rvb 	coda_clstat.ncalls++;
    566   1.3       rvb 	coda_clstat.reqs[((struct coda_in_hdr *)buffer)->opcode]++;
    567   1.1       rvb 
    568   1.1       rvb 	if (!VC_OPEN(vcp))
    569   1.1       rvb 	    return(ENODEV);
    570   1.1       rvb 
    571   1.3       rvb 	CODA_ALLOC(vmp,struct vmsg *,sizeof(struct vmsg));
    572   1.1       rvb 	/* Format the request message. */
    573   1.1       rvb 	vmp->vm_data = buffer;
    574   1.1       rvb 	vmp->vm_flags = 0;
    575   1.1       rvb 	vmp->vm_inSize = inSize;
    576  1.27     perry 	vmp->vm_outSize
    577   1.1       rvb 	    = *outSize ? *outSize : inSize; /* |buffer| >= inSize */
    578   1.3       rvb 	vmp->vm_opcode = ((struct coda_in_hdr *)buffer)->opcode;
    579   1.1       rvb 	vmp->vm_unique = ++vcp->vc_seq;
    580   1.3       rvb 	if (codadebug)
    581  1.27     perry 	    myprintf(("Doing a call for %d.%d\n",
    582   1.1       rvb 		      vmp->vm_opcode, vmp->vm_unique));
    583  1.27     perry 
    584   1.1       rvb 	/* Fill in the common input args. */
    585   1.3       rvb 	((struct coda_in_hdr *)buffer)->unique = vmp->vm_unique;
    586   1.1       rvb 
    587   1.1       rvb 	/* Append msg to request queue and poke Venus. */
    588  1.41    plunky 	TAILQ_INSERT_TAIL(&vcp->vc_requests, vmp, vm_chain);
    589  1.39     rmind 	selnotify(&(vcp->vc_selproc), 0, 0);
    590   1.1       rvb 
    591   1.1       rvb 	/* We can be interrupted while we wait for Venus to process
    592   1.1       rvb 	 * our request.  If the interrupt occurs before Venus has read
    593   1.1       rvb 	 * the request, we dequeue and return. If it occurs after the
    594   1.1       rvb 	 * read but before the reply, we dequeue, send a signal
    595   1.1       rvb 	 * message, and return. If it occurs after the reply we ignore
    596   1.1       rvb 	 * it. In no case do we want to restart the syscall.  If it
    597   1.1       rvb 	 * was interrupted by a venus shutdown (vcclose), return
    598   1.1       rvb 	 * ENODEV.  */
    599   1.1       rvb 
    600   1.1       rvb 	/* Ignore return, We have to check anyway */
    601   1.1       rvb #ifdef	CTL_C
    602   1.3       rvb 	/* This is work in progress.  Setting coda_pcatch lets tsleep reawaken
    603   1.1       rvb 	   on a ^c or ^z.  The problem is that emacs sets certain interrupts
    604   1.1       rvb 	   as SA_RESTART.  This means that we should exit sleep handle the
    605   1.1       rvb 	   "signal" and then go to sleep again.  Mostly this is done by letting
    606  1.27     perry 	   the syscall complete and be restarted.  We are not idempotent and
    607   1.1       rvb 	   can not do this.  A better solution is necessary.
    608   1.1       rvb 	 */
    609   1.1       rvb 	i = 0;
    610   1.1       rvb 	do {
    611   1.3       rvb 	    error = tsleep(&vmp->vm_sleep, (coda_call_sleep|coda_pcatch), "coda_call", hz*2);
    612   1.1       rvb 	    if (error == 0)
    613   1.1       rvb 	    	break;
    614  1.43        ad 	    mutex_enter(p->p_lock);
    615  1.35        ad 	    if (error == EWOULDBLOCK) {
    616   1.7       rvb #ifdef	CODA_VERBOSE
    617   1.3       rvb 		    printf("coda_call: tsleep TIMEOUT %d sec\n", 2+2*i);
    618   1.5       rvb #endif
    619  1.35        ad     	    } else if (sigispending(l, SIGIO)) {
    620  1.35        ad 		    sigaddset(&l->l_sigmask, SIGIO);
    621   1.7       rvb #ifdef	CODA_VERBOSE
    622   1.3       rvb 		    printf("coda_call: tsleep returns %d SIGIO, cnt %d\n", error, i);
    623   1.5       rvb #endif
    624  1.35        ad     	    } else if (sigispending(l, SIGALRM)) {
    625  1.35        ad 		    sigaddset(&l->l_sigmask, SIGALRM);
    626   1.8       rvb #ifdef	CODA_VERBOSE
    627   1.8       rvb 		    printf("coda_call: tsleep returns %d SIGALRM, cnt %d\n", error, i);
    628   1.8       rvb #endif
    629   1.1       rvb 	    } else {
    630   1.4       rvb 		    sigset_t tmp;
    631  1.35        ad 		    tmp = p->p_sigpend.sp_set;	/* array assignment */
    632  1.35        ad 		    sigminusset(&l->l_sigmask, &tmp);
    633   1.4       rvb 
    634   1.7       rvb #ifdef	CODA_VERBOSE
    635   1.3       rvb 		    printf("coda_call: tsleep returns %d, cnt %d\n", error, i);
    636   1.4       rvb 		    printf("coda_call: siglist = %x.%x.%x.%x, sigmask = %x.%x.%x.%x, mask %x.%x.%x.%x\n",
    637  1.35        ad 			    p->p_sigpend.sp_set.__bits[0], p->p_sigpend.sp_set.__bits[1],
    638  1.35        ad 			    p->p_sigpend.sp_set.__bits[2], p->p_sigpend.sp_set.__bits[3],
    639  1.35        ad 			    l->l_sigmask.__bits[0], l->l_sigmask.__bits[1],
    640  1.35        ad 			    l->l_sigmask.__bits[2], l->l_sigmask.__bits[3],
    641   1.4       rvb 			    tmp.__bits[0], tmp.__bits[1], tmp.__bits[2], tmp.__bits[3]);
    642   1.5       rvb #endif
    643  1.43        ad 		    mutex_exit(p->p_lock);
    644   1.1       rvb 		    break;
    645   1.5       rvb #ifdef	notyet
    646  1.35        ad 		    sigminusset(&l->l_sigmask, &p->p_sigpend.sp_set);
    647  1.27     perry 		    printf("coda_call: siglist = %x.%x.%x.%x, sigmask = %x.%x.%x.%x\n",
    648  1.35        ad 			    p->p_sigpend.sp_set.__bits[0], p->p_sigpend.sp_set.__bits[1],
    649  1.35        ad 			    p->p_sigpend.sp_set.__bits[2], p->p_sigpend.sp_set.__bits[3],
    650  1.35        ad 			    l->l_sigmask.__bits[0], l->l_sigmask.__bits[1],
    651  1.35        ad 			    l->l_sigmask.__bits[2], l->l_sigmask.__bits[3]);
    652   1.5       rvb #endif
    653   1.1       rvb 	    }
    654  1.43        ad 	    mutex_exit(p->p_lock);
    655   1.8       rvb 	} while (error && i++ < 128 && VC_OPEN(vcp));
    656  1.35        ad 	l->l_sigmask = psig_omask;	/* XXXSA */
    657   1.1       rvb #else
    658   1.3       rvb 	(void) tsleep(&vmp->vm_sleep, coda_call_sleep, "coda_call", 0);
    659   1.1       rvb #endif
    660   1.1       rvb 	if (VC_OPEN(vcp)) {	/* Venus is still alive */
    661   1.1       rvb  	/* Op went through, interrupt or not... */
    662   1.1       rvb 	    if (vmp->vm_flags & VM_WRITE) {
    663   1.1       rvb 		error = 0;
    664   1.1       rvb 		*outSize = vmp->vm_outSize;
    665   1.1       rvb 	    }
    666   1.1       rvb 
    667  1.27     perry 	    else if (!(vmp->vm_flags & VM_READ)) {
    668   1.1       rvb 		/* Interrupted before venus read it. */
    669   1.7       rvb #ifdef	CODA_VERBOSE
    670   1.7       rvb 		if (1)
    671   1.7       rvb #else
    672   1.5       rvb 		if (codadebug)
    673   1.5       rvb #endif
    674   1.1       rvb 		    myprintf(("interrupted before read: op = %d.%d, flags = %x\n",
    675   1.1       rvb 			   vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
    676  1.41    plunky 
    677  1.41    plunky 		TAILQ_REMOVE(&vcp->vc_requests, vmp, vm_chain);
    678   1.1       rvb 		error = EINTR;
    679   1.1       rvb 	    }
    680  1.27     perry 
    681  1.27     perry 	    else {
    682   1.1       rvb 		/* (!(vmp->vm_flags & VM_WRITE)) means interrupted after
    683   1.1       rvb                    upcall started */
    684   1.1       rvb 		/* Interrupted after start of upcall, send venus a signal */
    685   1.3       rvb 		struct coda_in_hdr *dog;
    686   1.1       rvb 		struct vmsg *svmp;
    687  1.27     perry 
    688   1.7       rvb #ifdef	CODA_VERBOSE
    689   1.7       rvb 		if (1)
    690   1.7       rvb #else
    691   1.5       rvb 		if (codadebug)
    692   1.5       rvb #endif
    693   1.1       rvb 		    myprintf(("Sending Venus a signal: op = %d.%d, flags = %x\n",
    694   1.1       rvb 			   vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
    695  1.27     perry 
    696  1.41    plunky 		TAILQ_REMOVE(&vcp->vc_replies, vmp, vm_chain);
    697   1.1       rvb 		error = EINTR;
    698  1.27     perry 
    699   1.3       rvb 		CODA_ALLOC(svmp, struct vmsg *, sizeof (struct vmsg));
    700   1.1       rvb 
    701   1.3       rvb 		CODA_ALLOC((svmp->vm_data), char *, sizeof (struct coda_in_hdr));
    702   1.3       rvb 		dog = (struct coda_in_hdr *)svmp->vm_data;
    703  1.27     perry 
    704   1.1       rvb 		svmp->vm_flags = 0;
    705   1.3       rvb 		dog->opcode = svmp->vm_opcode = CODA_SIGNAL;
    706   1.1       rvb 		dog->unique = svmp->vm_unique = vmp->vm_unique;
    707   1.3       rvb 		svmp->vm_inSize = sizeof (struct coda_in_hdr);
    708   1.3       rvb /*??? rvb */	svmp->vm_outSize = sizeof (struct coda_in_hdr);
    709  1.27     perry 
    710   1.3       rvb 		if (codadebug)
    711   1.3       rvb 		    myprintf(("coda_call: enqueing signal msg (%d, %d)\n",
    712   1.1       rvb 			   svmp->vm_opcode, svmp->vm_unique));
    713  1.27     perry 
    714  1.42    plunky 		/* insert at head of queue */
    715  1.42    plunky 		TAILQ_INSERT_HEAD(&vcp->vc_requests, svmp, vm_chain);
    716  1.39     rmind 		selnotify(&(vcp->vc_selproc), 0, 0);
    717   1.1       rvb 	    }
    718   1.1       rvb 	}
    719   1.1       rvb 
    720   1.1       rvb 	else {	/* If venus died (!VC_OPEN(vcp)) */
    721   1.3       rvb 	    if (codadebug)
    722   1.1       rvb 		myprintf(("vcclose woke op %d.%d flags %d\n",
    723   1.1       rvb 		       vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
    724  1.27     perry 
    725   1.1       rvb 		error = ENODEV;
    726   1.1       rvb 	}
    727   1.1       rvb 
    728   1.3       rvb 	CODA_FREE(vmp, sizeof(struct vmsg));
    729   1.8       rvb 
    730   1.8       rvb 	if (outstanding_upcalls > 0 && (--outstanding_upcalls == 0))
    731   1.8       rvb 		wakeup(&outstanding_upcalls);
    732   1.1       rvb 
    733   1.1       rvb 	if (!error)
    734   1.3       rvb 		error = ((struct coda_out_hdr *)buffer)->result;
    735   1.1       rvb 	return(error);
    736   1.1       rvb }
    737   1.4       rvb 
    738  1.48  christos MODULE(MODULE_CLASS_DRIVER, vcoda, NULL);
    739  1.48  christos 
    740  1.48  christos static int
    741  1.48  christos vcoda_modcmd(modcmd_t cmd, void *arg)
    742  1.48  christos {
    743  1.50  christos 	int error = 0;
    744  1.48  christos 
    745  1.48  christos 	switch (cmd) {
    746  1.48  christos 	case MODULE_CMD_INIT:
    747  1.48  christos #ifdef _MODULE
    748  1.51       riz 	{
    749  1.50  christos 		int cmajor, dmajor;
    750  1.48  christos 		vcodaattach(NVCODA);
    751  1.48  christos 
    752  1.50  christos 		dmajor = cmajor = -1;
    753  1.48  christos 		return devsw_attach("vcoda", NULL, &dmajor,
    754  1.48  christos 		    &vcoda_cdevsw, &cmajor);
    755  1.51       riz 	}
    756  1.48  christos #endif
    757  1.48  christos 		break;
    758  1.48  christos 
    759  1.48  christos 	case MODULE_CMD_FINI:
    760  1.48  christos #ifdef _MODULE
    761  1.48  christos 		{
    762  1.48  christos 			for  (size_t i = 0; i < NVCODA; i++) {
    763  1.48  christos 				struct vcomm *vcp = &coda_mnttbl[i].mi_vcomm;
    764  1.48  christos 				if (VC_OPEN(vcp))
    765  1.48  christos 					return EBUSY;
    766  1.48  christos 			}
    767  1.48  christos 			return devsw_detach(NULL, &vcoda_cdevsw);
    768  1.48  christos 		}
    769  1.48  christos #endif
    770  1.48  christos 		break;
    771  1.48  christos 
    772  1.48  christos 	case MODULE_CMD_STAT:
    773  1.48  christos 		return ENOTTY;
    774  1.48  christos 
    775  1.48  christos 	default:
    776  1.48  christos 		return ENOTTY;
    777  1.48  christos 	}
    778  1.48  christos 	return error;
    779  1.48  christos }
    780