Home | History | Annotate | Line # | Download | only in coda
coda_psdev.c revision 1.31
      1 /*	$NetBSD: coda_psdev.c,v 1.31 2005/12/11 12:19:50 christos 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 pseudo 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  * Following code depends on file-system CODA.
     52  */
     53 
     54 /* These routines are the device entry points for Venus. */
     55 
     56 #include <sys/cdefs.h>
     57 __KERNEL_RCSID(0, "$NetBSD: coda_psdev.c,v 1.31 2005/12/11 12:19:50 christos Exp $");
     58 
     59 extern int coda_nc_initialized;    /* Set if cache has been initialized */
     60 
     61 #ifdef	_LKM
     62 #define	NVCODA 4
     63 #else
     64 #include <vcoda.h>
     65 #endif
     66 
     67 #include <sys/param.h>
     68 #include <sys/systm.h>
     69 #include <sys/kernel.h>
     70 #include <sys/malloc.h>
     71 #include <sys/proc.h>
     72 #include <sys/mount.h>
     73 #include <sys/file.h>
     74 #include <sys/ioctl.h>
     75 #include <sys/poll.h>
     76 #include <sys/select.h>
     77 #include <sys/conf.h>
     78 
     79 #include <miscfs/syncfs/syncfs.h>
     80 
     81 #include <coda/coda.h>
     82 #include <coda/cnode.h>
     83 #include <coda/coda_namecache.h>
     84 #include <coda/coda_io.h>
     85 
     86 #define CTL_C
     87 
     88 int coda_psdev_print_entry = 0;
     89 static
     90 int outstanding_upcalls = 0;
     91 int coda_call_sleep = PZERO - 1;
     92 #ifdef	CTL_C
     93 int coda_pcatch = PCATCH;
     94 #else
     95 #endif
     96 
     97 #define ENTRY if(coda_psdev_print_entry) myprintf(("Entered %s\n",__func__))
     98 
     99 void vcodaattach(int n);
    100 
    101 dev_type_open(vc_nb_open);
    102 dev_type_close(vc_nb_close);
    103 dev_type_read(vc_nb_read);
    104 dev_type_write(vc_nb_write);
    105 dev_type_ioctl(vc_nb_ioctl);
    106 dev_type_poll(vc_nb_poll);
    107 dev_type_kqfilter(vc_nb_kqfilter);
    108 
    109 const struct cdevsw vcoda_cdevsw = {
    110 	vc_nb_open, vc_nb_close, vc_nb_read, vc_nb_write, vc_nb_ioctl,
    111 	nostop, notty, vc_nb_poll, nommap, vc_nb_kqfilter,
    112 };
    113 
    114 struct vmsg {
    115     struct queue vm_chain;
    116     caddr_t	 vm_data;
    117     u_short	 vm_flags;
    118     u_short      vm_inSize;	/* Size is at most 5000 bytes */
    119     u_short	 vm_outSize;
    120     u_short	 vm_opcode; 	/* copied from data to save ptr lookup */
    121     int		 vm_unique;
    122     caddr_t	 vm_sleep;	/* Not used by Mach. */
    123 };
    124 
    125 #define	VM_READ	    1
    126 #define	VM_WRITE    2
    127 #define	VM_INTR	    4
    128 
    129 /* vcodaattach: do nothing */
    130 void
    131 vcodaattach(int n)
    132 {
    133 }
    134 
    135 /*
    136  * These functions are written for NetBSD.
    137  */
    138 int
    139 vc_nb_open(dev_t dev, int flag, int mode, struct lwp *l /* NetBSD only */)
    140 {
    141     struct vcomm *vcp;
    142 
    143     ENTRY;
    144 
    145     if (minor(dev) >= NVCODA || minor(dev) < 0)
    146 	return(ENXIO);
    147 
    148     if (!coda_nc_initialized)
    149 	coda_nc_init();
    150 
    151     vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
    152     if (VC_OPEN(vcp))
    153 	return(EBUSY);
    154 
    155     memset(&(vcp->vc_selproc), 0, sizeof (struct selinfo));
    156     INIT_QUEUE(vcp->vc_requests);
    157     INIT_QUEUE(vcp->vc_replys);
    158     MARK_VC_OPEN(vcp);
    159 
    160     coda_mnttbl[minor(dev)].mi_vfsp = NULL;
    161     coda_mnttbl[minor(dev)].mi_rootvp = NULL;
    162 
    163     return(0);
    164 }
    165 
    166 int
    167 vc_nb_close(dev_t dev, int flag, int mode, struct lwp *l)
    168 {
    169     struct vcomm *vcp;
    170     struct vmsg *vmp, *nvmp = NULL;
    171     struct coda_mntinfo *mi;
    172     int                 err;
    173 
    174     ENTRY;
    175 
    176     if (minor(dev) >= NVCODA || minor(dev) < 0)
    177 	return(ENXIO);
    178 
    179     mi = &coda_mnttbl[minor(dev)];
    180     vcp = &(mi->mi_vcomm);
    181 
    182     if (!VC_OPEN(vcp))
    183 	panic("vcclose: not open");
    184 
    185     /* prevent future operations on this vfs from succeeding by auto-
    186      * unmounting any vfs mounted via this device. This frees user or
    187      * sysadm from having to remember where all mount points are located.
    188      * Put this before WAKEUPs to avoid queuing new messages between
    189      * the WAKEUP and the unmount (which can happen if we're unlucky)
    190      */
    191     if (!mi->mi_rootvp) {
    192 	/* just a simple open/close w no mount */
    193 	MARK_VC_CLOSED(vcp);
    194 	return 0;
    195     }
    196 
    197     /* Let unmount know this is for real */
    198     /*
    199      * XXX Freeze syncer.  Must do this before locking the
    200      * mount point.  See dounmount for details().
    201      */
    202     lockmgr(&syncer_lock, LK_EXCLUSIVE, NULL);
    203     VTOC(mi->mi_rootvp)->c_flags |= C_UNMOUNTING;
    204     if (vfs_busy(mi->mi_vfsp, 0, 0)) {
    205 	lockmgr(&syncer_lock, LK_RELEASE, NULL);
    206 	return (EBUSY);
    207     }
    208     coda_unmounting(mi->mi_vfsp);
    209 
    210     /* Wakeup clients so they can return. */
    211     for (vmp = (struct vmsg *)GETNEXT(vcp->vc_requests);
    212 	 !EOQ(vmp, vcp->vc_requests);
    213 	 vmp = nvmp)
    214     {
    215     	nvmp = (struct vmsg *)GETNEXT(vmp->vm_chain);
    216 	/* Free signal request messages and don't wakeup cause
    217 	   no one is waiting. */
    218 	if (vmp->vm_opcode == CODA_SIGNAL) {
    219 	    CODA_FREE((caddr_t)vmp->vm_data, (u_int)VC_IN_NO_DATA);
    220 	    CODA_FREE((caddr_t)vmp, (u_int)sizeof(struct vmsg));
    221 	    continue;
    222 	}
    223 	outstanding_upcalls++;
    224 	wakeup(&vmp->vm_sleep);
    225     }
    226 
    227     for (vmp = (struct vmsg *)GETNEXT(vcp->vc_replys);
    228 	 !EOQ(vmp, vcp->vc_replys);
    229 	 vmp = (struct vmsg *)GETNEXT(vmp->vm_chain))
    230     {
    231 	outstanding_upcalls++;
    232 	wakeup(&vmp->vm_sleep);
    233     }
    234 
    235     MARK_VC_CLOSED(vcp);
    236 
    237     if (outstanding_upcalls) {
    238 #ifdef	CODA_VERBOSE
    239 	printf("presleep: outstanding_upcalls = %d\n", outstanding_upcalls);
    240     	(void) tsleep(&outstanding_upcalls, coda_call_sleep, "coda_umount", 0);
    241 	printf("postsleep: outstanding_upcalls = %d\n", outstanding_upcalls);
    242 #else
    243     	(void) tsleep(&outstanding_upcalls, coda_call_sleep, "coda_umount", 0);
    244 #endif
    245     }
    246 
    247     err = dounmount(mi->mi_vfsp, flag, l);
    248     if (err)
    249 	myprintf(("Error %d unmounting vfs in vcclose(%d)\n",
    250 	           err, minor(dev)));
    251     return 0;
    252 }
    253 
    254 int
    255 vc_nb_read(dev_t dev, struct uio *uiop, int flag)
    256 {
    257     struct vcomm *	vcp;
    258     struct vmsg *vmp;
    259     int error = 0;
    260 
    261     ENTRY;
    262 
    263     if (minor(dev) >= NVCODA || minor(dev) < 0)
    264 	return(ENXIO);
    265 
    266     vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
    267     /* Get message at head of request queue. */
    268     if (EMPTY(vcp->vc_requests))
    269 	return(0);	/* Nothing to read */
    270 
    271     vmp = (struct vmsg *)GETNEXT(vcp->vc_requests);
    272 
    273     /* Move the input args into userspace */
    274     uiop->uio_rw = UIO_READ;
    275     error = uiomove(vmp->vm_data, vmp->vm_inSize, uiop);
    276     if (error) {
    277 	myprintf(("vcread: error (%d) on uiomove\n", error));
    278 	error = EINVAL;
    279     }
    280 
    281 #ifdef OLD_DIAGNOSTIC
    282     if (vmp->vm_chain.forw == 0 || vmp->vm_chain.back == 0)
    283 	panic("vc_nb_read: bad chain");
    284 #endif
    285 
    286     REMQUE(vmp->vm_chain);
    287 
    288     /* If request was a signal, free up the message and don't
    289        enqueue it in the reply queue. */
    290     if (vmp->vm_opcode == CODA_SIGNAL) {
    291 	if (codadebug)
    292 	    myprintf(("vcread: signal msg (%d, %d)\n",
    293 		      vmp->vm_opcode, vmp->vm_unique));
    294 	CODA_FREE((caddr_t)vmp->vm_data, (u_int)VC_IN_NO_DATA);
    295 	CODA_FREE((caddr_t)vmp, (u_int)sizeof(struct vmsg));
    296 	return(error);
    297     }
    298 
    299     vmp->vm_flags |= VM_READ;
    300     INSQUE(vmp->vm_chain, vcp->vc_replys);
    301 
    302     return(error);
    303 }
    304 
    305 int
    306 vc_nb_write(dev_t dev, struct uio *uiop, int flag)
    307 {
    308     struct vcomm *	vcp;
    309     struct vmsg *vmp;
    310     struct coda_out_hdr *out;
    311     u_long seq;
    312     u_long opcode;
    313     int tbuf[2];
    314     int error = 0;
    315 
    316     ENTRY;
    317 
    318     if (minor(dev) >= NVCODA || minor(dev) < 0)
    319 	return(ENXIO);
    320 
    321     vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
    322 
    323     /* Peek at the opcode, unique without transfering the data. */
    324     uiop->uio_rw = UIO_WRITE;
    325     error = uiomove((caddr_t)tbuf, sizeof(int) * 2, uiop);
    326     if (error) {
    327 	myprintf(("vcwrite: error (%d) on uiomove\n", error));
    328 	return(EINVAL);
    329     }
    330 
    331     opcode = tbuf[0];
    332     seq = tbuf[1];
    333 
    334     if (codadebug)
    335 	myprintf(("vcwrite got a call for %ld.%ld\n", opcode, seq));
    336 
    337     if (DOWNCALL(opcode)) {
    338 	union outputArgs pbuf;
    339 
    340 	/* get the rest of the data. */
    341 	uiop->uio_rw = UIO_WRITE;
    342 	error = uiomove((caddr_t)&pbuf.coda_purgeuser.oh.result, sizeof(pbuf) - (sizeof(int)*2), uiop);
    343 	if (error) {
    344 	    myprintf(("vcwrite: error (%d) on uiomove (Op %ld seq %ld)\n",
    345 		      error, opcode, seq));
    346 	    return(EINVAL);
    347 	    }
    348 
    349 	return handleDownCall(opcode, &pbuf);
    350     }
    351 
    352     /* Look for the message on the (waiting for) reply queue. */
    353     for (vmp = (struct vmsg *)GETNEXT(vcp->vc_replys);
    354 	 !EOQ(vmp, vcp->vc_replys);
    355 	 vmp = (struct vmsg *)GETNEXT(vmp->vm_chain))
    356     {
    357 	if (vmp->vm_unique == seq) break;
    358     }
    359 
    360     if (EOQ(vmp, vcp->vc_replys)) {
    361 	if (codadebug)
    362 	    myprintf(("vcwrite: msg (%ld, %ld) not found\n", opcode, seq));
    363 
    364 	return(ESRCH);
    365 	}
    366 
    367     /* Remove the message from the reply queue */
    368     REMQUE(vmp->vm_chain);
    369 
    370     /* move data into response buffer. */
    371     out = (struct coda_out_hdr *)vmp->vm_data;
    372     /* Don't need to copy opcode and uniquifier. */
    373 
    374     /* get the rest of the data. */
    375     if (vmp->vm_outSize < uiop->uio_resid) {
    376 	myprintf(("vcwrite: more data than asked for (%d < %lu)\n",
    377 		  vmp->vm_outSize, (unsigned long) uiop->uio_resid));
    378 	wakeup(&vmp->vm_sleep); 	/* Notify caller of the error. */
    379 	return(EINVAL);
    380     }
    381 
    382     tbuf[0] = uiop->uio_resid; 	/* Save this value. */
    383     uiop->uio_rw = UIO_WRITE;
    384     error = uiomove((caddr_t) &out->result, vmp->vm_outSize - (sizeof(int) * 2), uiop);
    385     if (error) {
    386 	myprintf(("vcwrite: error (%d) on uiomove (op %ld seq %ld)\n",
    387 		  error, opcode, seq));
    388 	return(EINVAL);
    389     }
    390 
    391     /* I don't think these are used, but just in case. */
    392     /* XXX - aren't these two already correct? -bnoble */
    393     out->opcode = opcode;
    394     out->unique = seq;
    395     vmp->vm_outSize	= tbuf[0];	/* Amount of data transferred? */
    396     vmp->vm_flags |= VM_WRITE;
    397     wakeup(&vmp->vm_sleep);
    398 
    399     return(0);
    400 }
    401 
    402 int
    403 vc_nb_ioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct lwp *l)
    404 {
    405     ENTRY;
    406 
    407     switch(cmd) {
    408     case CODARESIZE: {
    409 	struct coda_resize *data = (struct coda_resize *)addr;
    410 	return(coda_nc_resize(data->hashsize, data->heapsize, IS_DOWNCALL));
    411 	break;
    412     }
    413     case CODASTATS:
    414 	if (coda_nc_use) {
    415 	    coda_nc_gather_stats();
    416 	    return(0);
    417 	} else {
    418 	    return(ENODEV);
    419 	}
    420 	break;
    421     case CODAPRINT:
    422 	if (coda_nc_use) {
    423 	    print_coda_nc();
    424 	    return(0);
    425 	} else {
    426 	    return(ENODEV);
    427 	}
    428 	break;
    429     case CIOC_KERNEL_VERSION:
    430 	switch (*(u_int *)addr) {
    431 	case 0:
    432 		*(u_int *)addr = coda_kernel_version;
    433 		return 0;
    434 		break;
    435 	case 1:
    436 	case 2:
    437 		if (coda_kernel_version != *(u_int *)addr)
    438 		    return ENOENT;
    439 		else
    440 		    return 0;
    441 	default:
    442 		return ENOENT;
    443 	}
    444     	break;
    445     default :
    446 	return(EINVAL);
    447 	break;
    448     }
    449 }
    450 
    451 int
    452 vc_nb_poll(dev_t dev, int events, struct lwp *l)
    453 {
    454     struct vcomm *vcp;
    455     int event_msk = 0;
    456 
    457     ENTRY;
    458 
    459     if (minor(dev) >= NVCODA || minor(dev) < 0)
    460 	return(ENXIO);
    461 
    462     vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
    463 
    464     event_msk = events & (POLLIN|POLLRDNORM);
    465     if (!event_msk)
    466 	return(0);
    467 
    468     if (!EMPTY(vcp->vc_requests))
    469 	return(events & (POLLIN|POLLRDNORM));
    470 
    471     selrecord(l, &(vcp->vc_selproc));
    472 
    473     return(0);
    474 }
    475 
    476 static void
    477 filt_vc_nb_detach(struct knote *kn)
    478 {
    479 	struct vcomm *vcp = kn->kn_hook;
    480 
    481 	SLIST_REMOVE(&vcp->vc_selproc.sel_klist, kn, knote, kn_selnext);
    482 }
    483 
    484 static int
    485 filt_vc_nb_read(struct knote *kn, long hint)
    486 {
    487 	struct vcomm *vcp = kn->kn_hook;
    488 	struct vmsg *vmp;
    489 
    490 	if (EMPTY(vcp->vc_requests))
    491 		return (0);
    492 
    493 	vmp = (struct vmsg *)GETNEXT(vcp->vc_requests);
    494 
    495 	kn->kn_data = vmp->vm_inSize;
    496 	return (1);
    497 }
    498 
    499 static const struct filterops vc_nb_read_filtops =
    500 	{ 1, NULL, filt_vc_nb_detach, filt_vc_nb_read };
    501 
    502 int
    503 vc_nb_kqfilter(dev_t dev, struct knote *kn)
    504 {
    505 	struct vcomm *vcp;
    506 	struct klist *klist;
    507 
    508 	ENTRY;
    509 
    510 	if (minor(dev) >= NVCODA || minor(dev) < 0)
    511 		return(ENXIO);
    512 
    513 	vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
    514 
    515 	switch (kn->kn_filter) {
    516 	case EVFILT_READ:
    517 		klist = &vcp->vc_selproc.sel_klist;
    518 		kn->kn_fop = &vc_nb_read_filtops;
    519 		break;
    520 
    521 	default:
    522 		return (1);
    523 	}
    524 
    525 	kn->kn_hook = vcp;
    526 
    527 	SLIST_INSERT_HEAD(klist, kn, kn_selnext);
    528 
    529 	return (0);
    530 }
    531 
    532 /*
    533  * Statistics
    534  */
    535 struct coda_clstat coda_clstat;
    536 
    537 /*
    538  * Key question: whether to sleep interruptably or uninterruptably when
    539  * waiting for Venus.  The former seems better (cause you can ^C a
    540  * job), but then GNU-EMACS completion breaks. Use tsleep with no
    541  * timeout, and no longjmp happens. But, when sleeping
    542  * "uninterruptibly", we don't get told if it returns abnormally
    543  * (e.g. kill -9).
    544  */
    545 
    546 int
    547 coda_call(struct coda_mntinfo *mntinfo, int inSize, int *outSize,
    548 	caddr_t buffer)
    549 {
    550 	struct vcomm *vcp;
    551 	struct vmsg *vmp;
    552 	int error;
    553 #ifdef	CTL_C
    554 	struct lwp *l = curlwp;
    555 	struct proc *p = l->l_proc;
    556 	sigset_t psig_omask;
    557 	int i;
    558 	psig_omask = l->l_proc->p_sigctx.ps_siglist;	/* array assignment */
    559 #endif
    560 	if (mntinfo == NULL) {
    561 	    /* Unlikely, but could be a race condition with a dying warden */
    562 	    return ENODEV;
    563 	}
    564 
    565 	vcp = &(mntinfo->mi_vcomm);
    566 
    567 	coda_clstat.ncalls++;
    568 	coda_clstat.reqs[((struct coda_in_hdr *)buffer)->opcode]++;
    569 
    570 	if (!VC_OPEN(vcp))
    571 	    return(ENODEV);
    572 
    573 	CODA_ALLOC(vmp,struct vmsg *,sizeof(struct vmsg));
    574 	/* Format the request message. */
    575 	vmp->vm_data = buffer;
    576 	vmp->vm_flags = 0;
    577 	vmp->vm_inSize = inSize;
    578 	vmp->vm_outSize
    579 	    = *outSize ? *outSize : inSize; /* |buffer| >= inSize */
    580 	vmp->vm_opcode = ((struct coda_in_hdr *)buffer)->opcode;
    581 	vmp->vm_unique = ++vcp->vc_seq;
    582 	if (codadebug)
    583 	    myprintf(("Doing a call for %d.%d\n",
    584 		      vmp->vm_opcode, vmp->vm_unique));
    585 
    586 	/* Fill in the common input args. */
    587 	((struct coda_in_hdr *)buffer)->unique = vmp->vm_unique;
    588 
    589 	/* Append msg to request queue and poke Venus. */
    590 	INSQUE(vmp->vm_chain, vcp->vc_requests);
    591 	selnotify(&(vcp->vc_selproc), 0);
    592 
    593 	/* We can be interrupted while we wait for Venus to process
    594 	 * our request.  If the interrupt occurs before Venus has read
    595 	 * the request, we dequeue and return. If it occurs after the
    596 	 * read but before the reply, we dequeue, send a signal
    597 	 * message, and return. If it occurs after the reply we ignore
    598 	 * it. In no case do we want to restart the syscall.  If it
    599 	 * was interrupted by a venus shutdown (vcclose), return
    600 	 * ENODEV.  */
    601 
    602 	/* Ignore return, We have to check anyway */
    603 #ifdef	CTL_C
    604 	/* This is work in progress.  Setting coda_pcatch lets tsleep reawaken
    605 	   on a ^c or ^z.  The problem is that emacs sets certain interrupts
    606 	   as SA_RESTART.  This means that we should exit sleep handle the
    607 	   "signal" and then go to sleep again.  Mostly this is done by letting
    608 	   the syscall complete and be restarted.  We are not idempotent and
    609 	   can not do this.  A better solution is necessary.
    610 	 */
    611 	i = 0;
    612 	do {
    613 	    error = tsleep(&vmp->vm_sleep, (coda_call_sleep|coda_pcatch), "coda_call", hz*2);
    614 	    if (error == 0)
    615 	    	break;
    616 	    else if (error == EWOULDBLOCK) {
    617 #ifdef	CODA_VERBOSE
    618 		    printf("coda_call: tsleep TIMEOUT %d sec\n", 2+2*i);
    619 #endif
    620     	    } else if (sigismember(&p->p_sigctx.ps_siglist, SIGIO)) {
    621 		    sigaddset(&p->p_sigctx.ps_sigmask, SIGIO);
    622 #ifdef	CODA_VERBOSE
    623 		    printf("coda_call: tsleep returns %d SIGIO, cnt %d\n", error, i);
    624 #endif
    625     	    } else if (sigismember(&p->p_sigctx.ps_siglist, SIGALRM)) {
    626 		    sigaddset(&p->p_sigctx.ps_sigmask, SIGALRM);
    627 #ifdef	CODA_VERBOSE
    628 		    printf("coda_call: tsleep returns %d SIGALRM, cnt %d\n", error, i);
    629 #endif
    630 	    } else {
    631 		    sigset_t tmp;
    632 		    tmp = p->p_sigctx.ps_siglist;	/* array assignment */
    633 		    sigminusset(&p->p_sigctx.ps_sigmask, &tmp);
    634 
    635 #ifdef	CODA_VERBOSE
    636 		    printf("coda_call: tsleep returns %d, cnt %d\n", error, i);
    637 		    printf("coda_call: siglist = %x.%x.%x.%x, sigmask = %x.%x.%x.%x, mask %x.%x.%x.%x\n",
    638 			    p->p_sigctx.ps_siglist.__bits[0], p->p_sigctx.ps_siglist.__bits[1],
    639 			    p->p_sigctx.ps_siglist.__bits[2], p->p_sigctx.ps_siglist.__bits[3],
    640 			    p->p_sigctx.ps_sigmask.__bits[0], p->p_sigctx.ps_sigmask.__bits[1],
    641 			    p->p_sigctx.ps_sigmask.__bits[2], p->p_sigctx.ps_sigmask.__bits[3],
    642 			    tmp.__bits[0], tmp.__bits[1], tmp.__bits[2], tmp.__bits[3]);
    643 #endif
    644 		    break;
    645 #ifdef	notyet
    646 		    sigminusset(&p->p_sigctx.ps_sigmask, &p->p_sigctx.ps_siglist);
    647 		    printf("coda_call: siglist = %x.%x.%x.%x, sigmask = %x.%x.%x.%x\n",
    648 			    p->p_sigctx.ps_siglist.__bits[0], p->p_sigctx.ps_siglist.__bits[1],
    649 			    p->p_sigctx.ps_siglist.__bits[2], p->p_sigctx.ps_siglist.__bits[3],
    650 			    p->p_sigctx.ps_sigmask.__bits[0], p->p_sigctx.ps_sigmask.__bits[1],
    651 			    p->p_sigctx.ps_sigmask.__bits[2], p->p_sigctx.ps_sigmask.__bits[3]);
    652 #endif
    653 	    }
    654 	} while (error && i++ < 128 && VC_OPEN(vcp));
    655 	p->p_sigctx.ps_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 #ifdef	CODA_VERBOSE
    669 		if (1)
    670 #else
    671 		if (codadebug)
    672 #endif
    673 		    myprintf(("interrupted before read: op = %d.%d, flags = %x\n",
    674 			   vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
    675 		REMQUE(vmp->vm_chain);
    676 		error = EINTR;
    677 	    }
    678 
    679 	    else {
    680 		/* (!(vmp->vm_flags & VM_WRITE)) means interrupted after
    681                    upcall started */
    682 		/* Interrupted after start of upcall, send venus a signal */
    683 		struct coda_in_hdr *dog;
    684 		struct vmsg *svmp;
    685 
    686 #ifdef	CODA_VERBOSE
    687 		if (1)
    688 #else
    689 		if (codadebug)
    690 #endif
    691 		    myprintf(("Sending Venus a signal: op = %d.%d, flags = %x\n",
    692 			   vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
    693 
    694 		REMQUE(vmp->vm_chain);
    695 		error = EINTR;
    696 
    697 		CODA_ALLOC(svmp, struct vmsg *, sizeof (struct vmsg));
    698 
    699 		CODA_ALLOC((svmp->vm_data), char *, sizeof (struct coda_in_hdr));
    700 		dog = (struct coda_in_hdr *)svmp->vm_data;
    701 
    702 		svmp->vm_flags = 0;
    703 		dog->opcode = svmp->vm_opcode = CODA_SIGNAL;
    704 		dog->unique = svmp->vm_unique = vmp->vm_unique;
    705 		svmp->vm_inSize = sizeof (struct coda_in_hdr);
    706 /*??? rvb */	svmp->vm_outSize = sizeof (struct coda_in_hdr);
    707 
    708 		if (codadebug)
    709 		    myprintf(("coda_call: enqueing signal msg (%d, %d)\n",
    710 			   svmp->vm_opcode, svmp->vm_unique));
    711 
    712 		/* insert at head of queue! */
    713 		INSQUE(svmp->vm_chain, vcp->vc_requests);
    714 		selnotify(&(vcp->vc_selproc), 0);
    715 	    }
    716 	}
    717 
    718 	else {	/* If venus died (!VC_OPEN(vcp)) */
    719 	    if (codadebug)
    720 		myprintf(("vcclose woke op %d.%d flags %d\n",
    721 		       vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
    722 
    723 		error = ENODEV;
    724 	}
    725 
    726 	CODA_FREE(vmp, sizeof(struct vmsg));
    727 
    728 	if (outstanding_upcalls > 0 && (--outstanding_upcalls == 0))
    729 		wakeup(&outstanding_upcalls);
    730 
    731 	if (!error)
    732 		error = ((struct coda_out_hdr *)buffer)->result;
    733 	return(error);
    734 }
    735 
    736