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