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