Home | History | Annotate | Line # | Download | only in coda
coda_psdev.c revision 1.8
      1 /*	$NetBSD: coda_psdev.c,v 1.8 1998/11/09 16:36:16 rvb Exp $	*/
      2 
      3 /*
      4  *
      5  *             Coda: an Experimental Distributed File System
      6  *                              Release 3.1
      7  *
      8  *           Copyright (c) 1987-1998 Carnegie Mellon University
      9  *                          All Rights Reserved
     10  *
     11  * Permission  to  use, copy, modify and distribute this software and its
     12  * documentation is hereby granted,  provided  that  both  the  copyright
     13  * notice  and  this  permission  notice  appear  in  all  copies  of the
     14  * software, derivative works or  modified  versions,  and  any  portions
     15  * thereof, and that both notices appear in supporting documentation, and
     16  * that credit is given to Carnegie Mellon University  in  all  documents
     17  * and publicity pertaining to direct or indirect use of this code or its
     18  * derivatives.
     19  *
     20  * CODA IS AN EXPERIMENTAL SOFTWARE SYSTEM AND IS  KNOWN  TO  HAVE  BUGS,
     21  * SOME  OF  WHICH MAY HAVE SERIOUS CONSEQUENCES.  CARNEGIE MELLON ALLOWS
     22  * FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION.   CARNEGIE  MELLON
     23  * DISCLAIMS  ANY  LIABILITY  OF  ANY  KIND  FOR  ANY  DAMAGES WHATSOEVER
     24  * RESULTING DIRECTLY OR INDIRECTLY FROM THE USE OF THIS SOFTWARE  OR  OF
     25  * ANY DERIVATIVE WORK.
     26  *
     27  * Carnegie  Mellon  encourages  users  of  this  software  to return any
     28  * improvements or extensions that  they  make,  and  to  grant  Carnegie
     29  * Mellon the rights to redistribute these changes without encumbrance.
     30  *
     31  * 	@(#) coda/coda_psdev.c,v 1.1.1.1 1998/08/29 21:26:45 rvb Exp $
     32  */
     33 
     34 /*
     35  * Mach Operating System
     36  * Copyright (c) 1989 Carnegie-Mellon University
     37  * All rights reserved.  The CMU software License Agreement specifies
     38  * the terms and conditions for use and redistribution.
     39  */
     40 
     41 /*
     42  * This code was written for the Coda file system at Carnegie Mellon
     43  * University.  Contributers include David Steere, James Kistler, and
     44  * M. Satyanarayanan.  */
     45 
     46 /* These routines define the psuedo device for communication between
     47  * Coda's Venus and Minicache in Mach 2.6. They used to be in cfs_subr.c,
     48  * but I moved them to make it easier to port the Minicache without
     49  * porting coda. -- DCS 10/12/94
     50  */
     51 
     52 /*
     53  * HISTORY
     54  * $Log: coda_psdev.c,v $
     55  * Revision 1.8  1998/11/09 16:36:16  rvb
     56  * Change the way unmounting happens to guarantee that the
     57  * client programs are allowed to finish up (coda_call is
     58  * forced to complete) and release their locks.  Thus there
     59  * is a reasonable chance that the vflush implicit in the
     60  * unmount will not get hung on held locks.
     61  *
     62  * Revision 1.7  1998/09/28 17:55:22  rvb
     63  * I want to distinguish from DEBUG printouts and CODA_VERBOSE printouts.
     64  * The latter are normal informational messages that are sometimes
     65  * interesting to view.
     66  *
     67  * Revision 1.6  1998/09/26 15:24:46  tv
     68  * DIAGNOSTIC -> DEBUG for all non-panic messages.  DIAGNOSTIC is only for
     69  * sanity checks and should not turn on any messages not already printed
     70  * without it.
     71  *
     72  * Revision 1.5  1998/09/25 15:01:13  rvb
     73  * Conditionalize "stray" printouts under DIAGNOSTIC and DEBUG.
     74  * Make files compile if DEBUG is on (from  Alan Barrett).  Finally,
     75  * make coda an lkm.
     76  *
     77  * Revision 1.4  1998/09/15 02:02:59  rvb
     78  * Final piece of rename cfs->coda
     79  *
     80  * Revision 1.3  1998/09/12 15:05:48  rvb
     81  * Change cfs/CFS in symbols, strings and constants to coda/CODA
     82  * to avoid fs conflicts.
     83  *
     84  * Revision 1.2  1998/09/08 17:12:47  rvb
     85  * Pass2 complete
     86  *
     87  * Revision 1.1.1.1  1998/08/29 21:26:45  rvb
     88  * Very Preliminary Coda
     89  *
     90  * Revision 1.9  1998/08/28 18:12:17  rvb
     91  * Now it also works on FreeBSD -current.  This code will be
     92  * committed to the FreeBSD -current and NetBSD -current
     93  * trees.  It will then be tailored to the particular platform
     94  * by flushing conditional code.
     95  *
     96  * Revision 1.8  1998/08/18 17:05:15  rvb
     97  * Don't use __RCSID now
     98  *
     99  * Revision 1.7  1998/08/18 16:31:41  rvb
    100  * Sync the code for NetBSD -current; test on 1.3 later
    101  *
    102  * Revision 1.8  1998/06/09 23:30:42  rvb
    103  * Try to allow ^C -- take 1
    104  *
    105  * Revision 1.5.2.8  98/01/23  11:21:04  rvb
    106  * Sync with 2.2.5
    107  *
    108  * Revision 1.5.2.7  98/01/22  22:22:21  rvb
    109  * sync 1.2 and 1.3
    110  *
    111  * Revision 1.5.2.6  98/01/22  13:11:24  rvb
    112  * Move make_coda_node ctlfid later so vfsp is known; work on ^c and ^z
    113  *
    114  * Revision 1.5.2.5  97/12/16  22:01:27  rvb
    115  * Oops add cfs_subr.h cfs_venus.h; sync with peter
    116  *
    117  * Revision 1.5.2.4  97/12/16  12:40:05  rvb
    118  * Sync with 1.3
    119  *
    120  * Revision 1.5.2.3  97/12/10  14:08:24  rvb
    121  * Fix O_ flags; check result in coda_call
    122  *
    123  * Revision 1.5.2.2  97/12/10  11:40:24  rvb
    124  * No more ody
    125  *
    126  * Revision 1.5.2.1  97/12/06  17:41:20  rvb
    127  * Sync with peters coda.h
    128  *
    129  * Revision 1.5  97/12/05  10:39:16  rvb
    130  * Read CHANGES
    131  *
    132  * Revision 1.4.18.9  97/12/05  08:58:07  rvb
    133  * peter found this one
    134  *
    135  * Revision 1.4.18.8  97/11/26  15:28:57  rvb
    136  * Cant make downcall pbuf == union cfs_downcalls yet
    137  *
    138  * Revision 1.4.18.7  97/11/25  09:40:49  rvb
    139  * Final cfs_venus.c w/o macros, but one locking bug
    140  *
    141  * Revision 1.4.18.6  97/11/20  11:46:41  rvb
    142  * Capture current cfs_venus
    143  *
    144  * Revision 1.4.18.5  97/11/18  10:27:15  rvb
    145  * cfs_nbsd.c is DEAD!!!; integrated into cfs_vf/vnops.c
    146  * cfs_nb_foo and cfs_foo are joined
    147  *
    148  * Revision 1.4.18.4  97/11/13  22:02:59  rvb
    149  * pass2 cfs_NetBSD.h mt
    150  *
    151  * Revision 1.4.18.3  97/11/12  12:09:38  rvb
    152  * reorg pass1
    153  *
    154  * Revision 1.4.18.2  97/10/29  16:06:09  rvb
    155  * Kill DYING
    156  *
    157  * Revision 1.4.18.1  1997/10/28 23:10:15  rvb
    158  * >64Meg; venus can be killed!
    159  *
    160  * Revision 1.4  1996/12/12 22:10:58  bnoble
    161  * Fixed the "downcall invokes venus operation" deadlock in all known cases.
    162  * There may be more
    163  *
    164  * Revision 1.3  1996/11/13 04:14:20  bnoble
    165  * Merging BNOBLE_WORK_6_20_96 into main line
    166  *
    167  * Revision 1.2.8.1  1996/08/22 14:25:04  bnoble
    168  * Added a return code from vc_nb_close
    169  *
    170  * Revision 1.2  1996/01/02 16:56:58  bnoble
    171  * Added support for Coda MiniCache and raw inode calls (final commit)
    172  *
    173  * Revision 1.1.2.1  1995/12/20 01:57:24  bnoble
    174  * Added CODA-specific files
    175  *
    176  * Revision 1.1  1995/03/14  20:52:15  bnoble
    177  * Initial revision
    178  *
    179  */
    180 
    181 /* These routines are the device entry points for Venus. */
    182 
    183 extern int coda_nc_initialized;    /* Set if cache has been initialized */
    184 
    185 #ifdef	_LKM
    186 #define	NVCODA 4
    187 #else
    188 #include <vcoda.h>
    189 #endif
    190 
    191 #include <sys/param.h>
    192 #include <sys/systm.h>
    193 #include <sys/kernel.h>
    194 #include <sys/malloc.h>
    195 #include <sys/proc.h>
    196 #include <sys/mount.h>
    197 #include <sys/file.h>
    198 #include <sys/ioctl.h>
    199 #include <sys/poll.h>
    200 #include <sys/select.h>
    201 
    202 #include <coda/coda.h>
    203 #include <coda/cnode.h>
    204 #include <coda/coda_namecache.h>
    205 #include <coda/coda_io.h>
    206 #include <coda/coda_psdev.h>
    207 
    208 #define CTL_C
    209 
    210 int coda_psdev_print_entry = 0;
    211 static
    212 int outstanding_upcalls = 0;
    213 int coda_call_sleep = PZERO - 1;
    214 #ifdef	CTL_C
    215 int coda_pcatch = PCATCH;
    216 #else
    217 #endif
    218 
    219 #define ENTRY if(coda_psdev_print_entry) myprintf(("Entered %s\n",__FUNCTION__))
    220 
    221 void vcodaattach(int n);
    222 
    223 struct vmsg {
    224     struct queue vm_chain;
    225     caddr_t	 vm_data;
    226     u_short	 vm_flags;
    227     u_short      vm_inSize;	/* Size is at most 5000 bytes */
    228     u_short	 vm_outSize;
    229     u_short	 vm_opcode; 	/* copied from data to save ptr lookup */
    230     int		 vm_unique;
    231     caddr_t	 vm_sleep;	/* Not used by Mach. */
    232 };
    233 
    234 #define	VM_READ	    1
    235 #define	VM_WRITE    2
    236 #define	VM_INTR	    4
    237 
    238 /* vcodaattach: do nothing */
    239 void
    240 vcodaattach(n)
    241     int n;
    242 {
    243 }
    244 
    245 /*
    246  * These functions are written for NetBSD.
    247  */
    248 int
    249 vc_nb_open(dev, flag, mode, p)
    250     dev_t        dev;
    251     int          flag;
    252     int          mode;
    253     struct proc *p;             /* NetBSD only */
    254 {
    255     register struct vcomm *vcp;
    256 
    257     ENTRY;
    258 
    259     if (minor(dev) >= NVCODA || minor(dev) < 0)
    260 	return(ENXIO);
    261 
    262     if (!coda_nc_initialized)
    263 	coda_nc_init();
    264 
    265     vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
    266     if (VC_OPEN(vcp))
    267 	return(EBUSY);
    268 
    269     bzero(&(vcp->vc_selproc), sizeof (struct selinfo));
    270     INIT_QUEUE(vcp->vc_requests);
    271     INIT_QUEUE(vcp->vc_replys);
    272     MARK_VC_OPEN(vcp);
    273 
    274     coda_mnttbl[minor(dev)].mi_vfsp = NULL;
    275     coda_mnttbl[minor(dev)].mi_rootvp = NULL;
    276 
    277     return(0);
    278 }
    279 
    280 int
    281 vc_nb_close (dev, flag, mode, p)
    282     dev_t        dev;
    283     int          flag;
    284     int          mode;
    285     struct proc *p;
    286 {
    287     register struct vcomm *vcp;
    288     register struct vmsg *vmp;
    289     struct coda_mntinfo *mi;
    290     int                 err;
    291 
    292     ENTRY;
    293 
    294     if (minor(dev) >= NVCODA || minor(dev) < 0)
    295 	return(ENXIO);
    296 
    297     mi = &coda_mnttbl[minor(dev)];
    298     vcp = &(mi->mi_vcomm);
    299 
    300     if (!VC_OPEN(vcp))
    301 	panic("vcclose: not open");
    302 
    303     /* prevent future operations on this vfs from succeeding by auto-
    304      * unmounting any vfs mounted via this device. This frees user or
    305      * sysadm from having to remember where all mount points are located.
    306      * Put this before WAKEUPs to avoid queuing new messages between
    307      * the WAKEUP and the unmount (which can happen if we're unlucky)
    308      */
    309     if (!mi->mi_rootvp) {
    310 	/* just a simple open/close w no mount */
    311 	MARK_VC_CLOSED(vcp);
    312 	return 0;
    313     }
    314 
    315     /* Let unmount know this is for real */
    316     VTOC(mi->mi_rootvp)->c_flags |= C_UNMOUNTING;
    317     if (vfs_busy(mi->mi_vfsp, 0, 0))
    318 	return (EBUSY);
    319     coda_unmounting(mi->mi_vfsp);
    320 
    321     /* Wakeup clients so they can return. */
    322     for (vmp = (struct vmsg *)GETNEXT(vcp->vc_requests);
    323 	 !EOQ(vmp, vcp->vc_requests);
    324 	 vmp = (struct vmsg *)GETNEXT(vmp->vm_chain))
    325     {
    326 	/* Free signal request messages and don't wakeup cause
    327 	   no one is waiting. */
    328 	if (vmp->vm_opcode == CODA_SIGNAL) {
    329 	    CODA_FREE((caddr_t)vmp->vm_data, (u_int)VC_IN_NO_DATA);
    330 	    CODA_FREE((caddr_t)vmp, (u_int)sizeof(struct vmsg));
    331 	    continue;
    332 	}
    333 	outstanding_upcalls++;
    334 	wakeup(&vmp->vm_sleep);
    335     }
    336 
    337     for (vmp = (struct vmsg *)GETNEXT(vcp->vc_replys);
    338 	 !EOQ(vmp, vcp->vc_replys);
    339 	 vmp = (struct vmsg *)GETNEXT(vmp->vm_chain))
    340     {
    341 	outstanding_upcalls++;
    342 	wakeup(&vmp->vm_sleep);
    343     }
    344 
    345     MARK_VC_CLOSED(vcp);
    346 
    347     if (outstanding_upcalls) {
    348 #ifdef	CODA_VERBOSE
    349 	printf("presleep: outstanding_upcalls = %d\n", outstanding_upcalls);
    350     	(void) tsleep(&outstanding_upcalls, coda_call_sleep, "coda_umount", 0);
    351 	printf("postsleep: outstanding_upcalls = %d\n", outstanding_upcalls);
    352 #else
    353     	(void) tsleep(&outstanding_upcalls, coda_call_sleep, "coda_umount", 0);
    354 #endif
    355     }
    356 
    357     err = dounmount(mi->mi_vfsp, flag, p);
    358     if (err)
    359 	myprintf(("Error %d unmounting vfs in vcclose(%d)\n",
    360 	           err, minor(dev)));
    361     return 0;
    362 }
    363 
    364 int
    365 vc_nb_read(dev, uiop, flag)
    366     dev_t        dev;
    367     struct uio  *uiop;
    368     int          flag;
    369 {
    370     register struct vcomm *	vcp;
    371     register struct vmsg *vmp;
    372     int error = 0;
    373 
    374     ENTRY;
    375 
    376     if (minor(dev) >= NVCODA || minor(dev) < 0)
    377 	return(ENXIO);
    378 
    379     vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
    380     /* Get message at head of request queue. */
    381     if (EMPTY(vcp->vc_requests))
    382 	return(0);	/* Nothing to read */
    383 
    384     vmp = (struct vmsg *)GETNEXT(vcp->vc_requests);
    385 
    386     /* Move the input args into userspace */
    387     uiop->uio_rw = UIO_READ;
    388     error = uiomove(vmp->vm_data, vmp->vm_inSize, uiop);
    389     if (error) {
    390 	myprintf(("vcread: error (%d) on uiomove\n", error));
    391 	error = EINVAL;
    392     }
    393 
    394 #ifdef OLD_DIAGNOSTIC
    395     if (vmp->vm_chain.forw == 0 || vmp->vm_chain.back == 0)
    396 	panic("vc_nb_read: bad chain");
    397 #endif
    398 
    399     REMQUE(vmp->vm_chain);
    400 
    401     /* If request was a signal, free up the message and don't
    402        enqueue it in the reply queue. */
    403     if (vmp->vm_opcode == CODA_SIGNAL) {
    404 	if (codadebug)
    405 	    myprintf(("vcread: signal msg (%d, %d)\n",
    406 		      vmp->vm_opcode, vmp->vm_unique));
    407 	CODA_FREE((caddr_t)vmp->vm_data, (u_int)VC_IN_NO_DATA);
    408 	CODA_FREE((caddr_t)vmp, (u_int)sizeof(struct vmsg));
    409 	return(error);
    410     }
    411 
    412     vmp->vm_flags |= VM_READ;
    413     INSQUE(vmp->vm_chain, vcp->vc_replys);
    414 
    415     return(error);
    416 }
    417 
    418 int
    419 vc_nb_write(dev, uiop, flag)
    420     dev_t        dev;
    421     struct uio  *uiop;
    422     int          flag;
    423 {
    424     register struct vcomm *	vcp;
    425     register struct vmsg *vmp;
    426     struct coda_out_hdr *out;
    427     u_long seq;
    428     u_long opcode;
    429     int buf[2];
    430     int error = 0;
    431 
    432     ENTRY;
    433 
    434     if (minor(dev) >= NVCODA || minor(dev) < 0)
    435 	return(ENXIO);
    436 
    437     vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
    438 
    439     /* Peek at the opcode, unique without transfering the data. */
    440     uiop->uio_rw = UIO_WRITE;
    441     error = uiomove((caddr_t)buf, sizeof(int) * 2, uiop);
    442     if (error) {
    443 	myprintf(("vcwrite: error (%d) on uiomove\n", error));
    444 	return(EINVAL);
    445     }
    446 
    447     opcode = buf[0];
    448     seq = buf[1];
    449 
    450     if (codadebug)
    451 	myprintf(("vcwrite got a call for %ld.%ld\n", opcode, seq));
    452 
    453     if (DOWNCALL(opcode)) {
    454 	union outputArgs pbuf;
    455 
    456 	/* get the rest of the data. */
    457 	uiop->uio_rw = UIO_WRITE;
    458 	error = uiomove((caddr_t)&pbuf.coda_purgeuser.oh.result, sizeof(pbuf) - (sizeof(int)*2), uiop);
    459 	if (error) {
    460 	    myprintf(("vcwrite: error (%d) on uiomove (Op %ld seq %ld)\n",
    461 		      error, opcode, seq));
    462 	    return(EINVAL);
    463 	    }
    464 
    465 	return handleDownCall(opcode, &pbuf);
    466     }
    467 
    468     /* Look for the message on the (waiting for) reply queue. */
    469     for (vmp = (struct vmsg *)GETNEXT(vcp->vc_replys);
    470 	 !EOQ(vmp, vcp->vc_replys);
    471 	 vmp = (struct vmsg *)GETNEXT(vmp->vm_chain))
    472     {
    473 	if (vmp->vm_unique == seq) break;
    474     }
    475 
    476     if (EOQ(vmp, vcp->vc_replys)) {
    477 	if (codadebug)
    478 	    myprintf(("vcwrite: msg (%ld, %ld) not found\n", opcode, seq));
    479 
    480 	return(ESRCH);
    481 	}
    482 
    483     /* Remove the message from the reply queue */
    484     REMQUE(vmp->vm_chain);
    485 
    486     /* move data into response buffer. */
    487     out = (struct coda_out_hdr *)vmp->vm_data;
    488     /* Don't need to copy opcode and uniquifier. */
    489 
    490     /* get the rest of the data. */
    491     if (vmp->vm_outSize < uiop->uio_resid) {
    492 	myprintf(("vcwrite: more data than asked for (%d < %d)\n",
    493 		  vmp->vm_outSize, uiop->uio_resid));
    494 	wakeup(&vmp->vm_sleep); 	/* Notify caller of the error. */
    495 	return(EINVAL);
    496     }
    497 
    498     buf[0] = uiop->uio_resid; 	/* Save this value. */
    499     uiop->uio_rw = UIO_WRITE;
    500     error = uiomove((caddr_t) &out->result, vmp->vm_outSize - (sizeof(int) * 2), uiop);
    501     if (error) {
    502 	myprintf(("vcwrite: error (%d) on uiomove (op %ld seq %ld)\n",
    503 		  error, opcode, seq));
    504 	return(EINVAL);
    505     }
    506 
    507     /* I don't think these are used, but just in case. */
    508     /* XXX - aren't these two already correct? -bnoble */
    509     out->opcode = opcode;
    510     out->unique = seq;
    511     vmp->vm_outSize	= buf[0];	/* Amount of data transferred? */
    512     vmp->vm_flags |= VM_WRITE;
    513     wakeup(&vmp->vm_sleep);
    514 
    515     return(0);
    516 }
    517 
    518 int
    519 vc_nb_ioctl(dev, cmd, addr, flag, p)
    520     dev_t         dev;
    521     u_long        cmd;
    522     caddr_t       addr;
    523     int           flag;
    524     struct proc  *p;
    525 {
    526     ENTRY;
    527 
    528     switch(cmd) {
    529     case CODARESIZE: {
    530 	struct coda_resize *data = (struct coda_resize *)addr;
    531 	return(coda_nc_resize(data->hashsize, data->heapsize, IS_DOWNCALL));
    532 	break;
    533     }
    534     case CODASTATS:
    535 	if (coda_nc_use) {
    536 	    coda_nc_gather_stats();
    537 	    return(0);
    538 	} else {
    539 	    return(ENODEV);
    540 	}
    541 	break;
    542     case CODAPRINT:
    543 	if (coda_nc_use) {
    544 	    print_coda_nc();
    545 	    return(0);
    546 	} else {
    547 	    return(ENODEV);
    548 	}
    549 	break;
    550     default :
    551 	return(EINVAL);
    552 	break;
    553     }
    554 }
    555 
    556 int
    557 vc_nb_poll(dev, events, p)
    558     dev_t         dev;
    559     int           events;
    560     struct proc  *p;
    561 {
    562     register struct vcomm *vcp;
    563     int event_msk = 0;
    564 
    565     ENTRY;
    566 
    567     if (minor(dev) >= NVCODA || minor(dev) < 0)
    568 	return(ENXIO);
    569 
    570     vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
    571 
    572     event_msk = events & (POLLIN|POLLRDNORM);
    573     if (!event_msk)
    574 	return(0);
    575 
    576     if (!EMPTY(vcp->vc_requests))
    577 	return(events & (POLLIN|POLLRDNORM));
    578 
    579     selrecord(p, &(vcp->vc_selproc));
    580 
    581     return(0);
    582 }
    583 
    584 /*
    585  * Statistics
    586  */
    587 struct coda_clstat coda_clstat;
    588 
    589 /*
    590  * Key question: whether to sleep interuptably or uninteruptably when
    591  * waiting for Venus.  The former seems better (cause you can ^C a
    592  * job), but then GNU-EMACS completion breaks. Use tsleep with no
    593  * timeout, and no longjmp happens. But, when sleeping
    594  * "uninterruptibly", we don't get told if it returns abnormally
    595  * (e.g. kill -9).
    596  */
    597 
    598 int
    599 coda_call(mntinfo, inSize, outSize, buffer)
    600      struct coda_mntinfo *mntinfo; int inSize; int *outSize; caddr_t buffer;
    601 {
    602 	struct vcomm *vcp;
    603 	struct vmsg *vmp;
    604 	int error;
    605 #ifdef	CTL_C
    606 	struct proc *p = curproc;
    607 	sigset_t psig_omask;
    608 	int i;
    609 	psig_omask = p->p_siglist;	/* array assignment */
    610 #endif
    611 	if (mntinfo == NULL) {
    612 	    /* Unlikely, but could be a race condition with a dying warden */
    613 	    return ENODEV;
    614 	}
    615 
    616 	vcp = &(mntinfo->mi_vcomm);
    617 
    618 	coda_clstat.ncalls++;
    619 	coda_clstat.reqs[((struct coda_in_hdr *)buffer)->opcode]++;
    620 
    621 	if (!VC_OPEN(vcp))
    622 	    return(ENODEV);
    623 
    624 	CODA_ALLOC(vmp,struct vmsg *,sizeof(struct vmsg));
    625 	/* Format the request message. */
    626 	vmp->vm_data = buffer;
    627 	vmp->vm_flags = 0;
    628 	vmp->vm_inSize = inSize;
    629 	vmp->vm_outSize
    630 	    = *outSize ? *outSize : inSize; /* |buffer| >= inSize */
    631 	vmp->vm_opcode = ((struct coda_in_hdr *)buffer)->opcode;
    632 	vmp->vm_unique = ++vcp->vc_seq;
    633 	if (codadebug)
    634 	    myprintf(("Doing a call for %d.%d\n",
    635 		      vmp->vm_opcode, vmp->vm_unique));
    636 
    637 	/* Fill in the common input args. */
    638 	((struct coda_in_hdr *)buffer)->unique = vmp->vm_unique;
    639 
    640 	/* Append msg to request queue and poke Venus. */
    641 	INSQUE(vmp->vm_chain, vcp->vc_requests);
    642 	selwakeup(&(vcp->vc_selproc));
    643 
    644 	/* We can be interrupted while we wait for Venus to process
    645 	 * our request.  If the interrupt occurs before Venus has read
    646 	 * the request, we dequeue and return. If it occurs after the
    647 	 * read but before the reply, we dequeue, send a signal
    648 	 * message, and return. If it occurs after the reply we ignore
    649 	 * it. In no case do we want to restart the syscall.  If it
    650 	 * was interrupted by a venus shutdown (vcclose), return
    651 	 * ENODEV.  */
    652 
    653 	/* Ignore return, We have to check anyway */
    654 #ifdef	CTL_C
    655 	/* This is work in progress.  Setting coda_pcatch lets tsleep reawaken
    656 	   on a ^c or ^z.  The problem is that emacs sets certain interrupts
    657 	   as SA_RESTART.  This means that we should exit sleep handle the
    658 	   "signal" and then go to sleep again.  Mostly this is done by letting
    659 	   the syscall complete and be restarted.  We are not idempotent and
    660 	   can not do this.  A better solution is necessary.
    661 	 */
    662 	i = 0;
    663 	do {
    664 	    error = tsleep(&vmp->vm_sleep, (coda_call_sleep|coda_pcatch), "coda_call", hz*2);
    665 	    if (error == 0)
    666 	    	break;
    667 	    else if (error == EWOULDBLOCK) {
    668 #ifdef	CODA_VERBOSE
    669 		    printf("coda_call: tsleep TIMEOUT %d sec\n", 2+2*i);
    670 #endif
    671     	    } else if (sigismember(&p->p_siglist, SIGIO)) {
    672 		    sigaddset(&p->p_sigmask, SIGIO);
    673 #ifdef	CODA_VERBOSE
    674 		    printf("coda_call: tsleep returns %d SIGIO, cnt %d\n", error, i);
    675 #endif
    676     	    } else if (sigismember(&p->p_siglist, SIGALRM)) {
    677 		    sigaddset(&p->p_sigmask, SIGALRM);
    678 #ifdef	CODA_VERBOSE
    679 		    printf("coda_call: tsleep returns %d SIGALRM, cnt %d\n", error, i);
    680 #endif
    681 	    } else {
    682 		    sigset_t tmp;
    683 		    tmp = p->p_siglist;		/* array assignment */
    684 		    sigminusset(&p->p_sigmask, &tmp);
    685 
    686 #ifdef	CODA_VERBOSE
    687 		    printf("coda_call: tsleep returns %d, cnt %d\n", error, i);
    688 		    printf("coda_call: siglist = %x.%x.%x.%x, sigmask = %x.%x.%x.%x, mask %x.%x.%x.%x\n",
    689 			    p->p_siglist.__bits[0], p->p_siglist.__bits[1],
    690 			    p->p_siglist.__bits[2], p->p_siglist.__bits[3],
    691 			    p->p_sigmask.__bits[0], p->p_sigmask.__bits[1],
    692 			    p->p_sigmask.__bits[2], p->p_sigmask.__bits[3],
    693 			    tmp.__bits[0], tmp.__bits[1], tmp.__bits[2], tmp.__bits[3]);
    694 #endif
    695 		    break;
    696 #ifdef	notyet
    697 		    sigminusset(&p->p_sigmask, &p->p_siglist);
    698 		    printf("coda_call: siglist = %x.%x.%x.%x, sigmask = %x.%x.%x.%x\n",
    699 			    p->p_siglist.__bits[0], p->p_siglist.__bits[1],
    700 			    p->p_siglist.__bits[2], p->p_siglist.__bits[3],
    701 			    p->p_sigmask.__bits[0], p->p_sigmask.__bits[1],
    702 			    p->p_sigmask.__bits[2], p->p_sigmask.__bits[3]);
    703 #endif
    704 	    }
    705 	} while (error && i++ < 128 && VC_OPEN(vcp));
    706 	p->p_siglist = psig_omask;	/* array assignment */
    707 #else
    708 	(void) tsleep(&vmp->vm_sleep, coda_call_sleep, "coda_call", 0);
    709 #endif
    710 	if (VC_OPEN(vcp)) {	/* Venus is still alive */
    711  	/* Op went through, interrupt or not... */
    712 	    if (vmp->vm_flags & VM_WRITE) {
    713 		error = 0;
    714 		*outSize = vmp->vm_outSize;
    715 	    }
    716 
    717 	    else if (!(vmp->vm_flags & VM_READ)) {
    718 		/* Interrupted before venus read it. */
    719 #ifdef	CODA_VERBOSE
    720 		if (1)
    721 #else
    722 		if (codadebug)
    723 #endif
    724 		    myprintf(("interrupted before read: op = %d.%d, flags = %x\n",
    725 			   vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
    726 		REMQUE(vmp->vm_chain);
    727 		error = EINTR;
    728 	    }
    729 
    730 	    else {
    731 		/* (!(vmp->vm_flags & VM_WRITE)) means interrupted after
    732                    upcall started */
    733 		/* Interrupted after start of upcall, send venus a signal */
    734 		struct coda_in_hdr *dog;
    735 		struct vmsg *svmp;
    736 
    737 #ifdef	CODA_VERBOSE
    738 		if (1)
    739 #else
    740 		if (codadebug)
    741 #endif
    742 		    myprintf(("Sending Venus a signal: op = %d.%d, flags = %x\n",
    743 			   vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
    744 
    745 		REMQUE(vmp->vm_chain);
    746 		error = EINTR;
    747 
    748 		CODA_ALLOC(svmp, struct vmsg *, sizeof (struct vmsg));
    749 
    750 		CODA_ALLOC((svmp->vm_data), char *, sizeof (struct coda_in_hdr));
    751 		dog = (struct coda_in_hdr *)svmp->vm_data;
    752 
    753 		svmp->vm_flags = 0;
    754 		dog->opcode = svmp->vm_opcode = CODA_SIGNAL;
    755 		dog->unique = svmp->vm_unique = vmp->vm_unique;
    756 		svmp->vm_inSize = sizeof (struct coda_in_hdr);
    757 /*??? rvb */	svmp->vm_outSize = sizeof (struct coda_in_hdr);
    758 
    759 		if (codadebug)
    760 		    myprintf(("coda_call: enqueing signal msg (%d, %d)\n",
    761 			   svmp->vm_opcode, svmp->vm_unique));
    762 
    763 		/* insert at head of queue! */
    764 		INSQUE(svmp->vm_chain, vcp->vc_requests);
    765 		selwakeup(&(vcp->vc_selproc));
    766 	    }
    767 	}
    768 
    769 	else {	/* If venus died (!VC_OPEN(vcp)) */
    770 	    if (codadebug)
    771 		myprintf(("vcclose woke op %d.%d flags %d\n",
    772 		       vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
    773 
    774 		error = ENODEV;
    775 	}
    776 
    777 	CODA_FREE(vmp, sizeof(struct vmsg));
    778 
    779 	if (outstanding_upcalls > 0 && (--outstanding_upcalls == 0))
    780 		wakeup(&outstanding_upcalls);
    781 
    782 	if (!error)
    783 		error = ((struct coda_out_hdr *)buffer)->result;
    784 	return(error);
    785 }
    786 
    787