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