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