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