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