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