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