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