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