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