xref: /netbsd-src/sys/coda/coda_psdev.c (revision dc306354b0b29af51801a7632f1e95265a68cd81)
1 /*	$NetBSD: coda_psdev.c,v 1.9 1998/11/11 19:22:08 rvb Exp $	*/
2 
3 /*
4  *
5  *             Coda: an Experimental Distributed File System
6  *                              Release 3.1
7  *
8  *           Copyright (c) 1987-1998 Carnegie Mellon University
9  *                          All Rights Reserved
10  *
11  * Permission  to  use, copy, modify and distribute this software and its
12  * documentation is hereby granted,  provided  that  both  the  copyright
13  * notice  and  this  permission  notice  appear  in  all  copies  of the
14  * software, derivative works or  modified  versions,  and  any  portions
15  * thereof, and that both notices appear in supporting documentation, and
16  * that credit is given to Carnegie Mellon University  in  all  documents
17  * and publicity pertaining to direct or indirect use of this code or its
18  * derivatives.
19  *
20  * CODA IS AN EXPERIMENTAL SOFTWARE SYSTEM AND IS  KNOWN  TO  HAVE  BUGS,
21  * SOME  OF  WHICH MAY HAVE SERIOUS CONSEQUENCES.  CARNEGIE MELLON ALLOWS
22  * FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION.   CARNEGIE  MELLON
23  * DISCLAIMS  ANY  LIABILITY  OF  ANY  KIND  FOR  ANY  DAMAGES WHATSOEVER
24  * RESULTING DIRECTLY OR INDIRECTLY FROM THE USE OF THIS SOFTWARE  OR  OF
25  * ANY DERIVATIVE WORK.
26  *
27  * Carnegie  Mellon  encourages  users  of  this  software  to return any
28  * improvements or extensions that  they  make,  and  to  grant  Carnegie
29  * Mellon the rights to redistribute these changes without encumbrance.
30  *
31  * 	@(#) coda/coda_psdev.c,v 1.1.1.1 1998/08/29 21:26:45 rvb Exp $
32  */
33 
34 /*
35  * Mach Operating System
36  * Copyright (c) 1989 Carnegie-Mellon University
37  * All rights reserved.  The CMU software License Agreement specifies
38  * the terms and conditions for use and redistribution.
39  */
40 
41 /*
42  * This code was written for the Coda file system at Carnegie Mellon
43  * University.  Contributers include David Steere, James Kistler, and
44  * M. Satyanarayanan.  */
45 
46 /* These routines define the psuedo device for communication between
47  * Coda's Venus and Minicache in Mach 2.6. They used to be in cfs_subr.c,
48  * but I moved them to make it easier to port the Minicache without
49  * porting coda. -- DCS 10/12/94
50  */
51 
52 /*
53  * HISTORY
54  * $Log: coda_psdev.c,v $
55  * Revision 1.9  1998/11/11 19:22:08  rvb
56  * Lookup now passes up an extra flag.  But old veni will
57  * be ok; new veni will check /dev/cfs0 to make sure that a new
58  * kernel is running.
59  * Also, a bug in vc_nb_close iff CODA_SIGNAL's were seen has been
60  * fixed.
61  *
62  * Revision 1.8  1998/11/09 16:36:16  rvb
63  * Change the way unmounting happens to guarantee that the
64  * client programs are allowed to finish up (coda_call is
65  * forced to complete) and release their locks.  Thus there
66  * is a reasonable chance that the vflush implicit in the
67  * unmount will not get hung on held locks.
68  *
69  * Revision 1.7  1998/09/28 17:55:22  rvb
70  * I want to distinguish from DEBUG printouts and CODA_VERBOSE printouts.
71  * The latter are normal informational messages that are sometimes
72  * interesting to view.
73  *
74  * Revision 1.6  1998/09/26 15:24:46  tv
75  * DIAGNOSTIC -> DEBUG for all non-panic messages.  DIAGNOSTIC is only for
76  * sanity checks and should not turn on any messages not already printed
77  * without it.
78  *
79  * Revision 1.5  1998/09/25 15:01:13  rvb
80  * Conditionalize "stray" printouts under DIAGNOSTIC and DEBUG.
81  * Make files compile if DEBUG is on (from  Alan Barrett).  Finally,
82  * make coda an lkm.
83  *
84  * Revision 1.4  1998/09/15 02:02:59  rvb
85  * Final piece of rename cfs->coda
86  *
87  * Revision 1.3  1998/09/12 15:05:48  rvb
88  * Change cfs/CFS in symbols, strings and constants to coda/CODA
89  * to avoid fs conflicts.
90  *
91  * Revision 1.2  1998/09/08 17:12:47  rvb
92  * Pass2 complete
93  *
94  * Revision 1.1.1.1  1998/08/29 21:26:45  rvb
95  * Very Preliminary Coda
96  *
97  * Revision 1.9  1998/08/28 18:12:17  rvb
98  * Now it also works on FreeBSD -current.  This code will be
99  * committed to the FreeBSD -current and NetBSD -current
100  * trees.  It will then be tailored to the particular platform
101  * by flushing conditional code.
102  *
103  * Revision 1.8  1998/08/18 17:05:15  rvb
104  * Don't use __RCSID now
105  *
106  * Revision 1.7  1998/08/18 16:31:41  rvb
107  * Sync the code for NetBSD -current; test on 1.3 later
108  *
109  * Revision 1.8  1998/06/09 23:30:42  rvb
110  * Try to allow ^C -- take 1
111  *
112  * Revision 1.5.2.8  98/01/23  11:21:04  rvb
113  * Sync with 2.2.5
114  *
115  * Revision 1.5.2.7  98/01/22  22:22:21  rvb
116  * sync 1.2 and 1.3
117  *
118  * Revision 1.5.2.6  98/01/22  13:11:24  rvb
119  * Move make_coda_node ctlfid later so vfsp is known; work on ^c and ^z
120  *
121  * Revision 1.5.2.5  97/12/16  22:01:27  rvb
122  * Oops add cfs_subr.h cfs_venus.h; sync with peter
123  *
124  * Revision 1.5.2.4  97/12/16  12:40:05  rvb
125  * Sync with 1.3
126  *
127  * Revision 1.5.2.3  97/12/10  14:08:24  rvb
128  * Fix O_ flags; check result in coda_call
129  *
130  * Revision 1.5.2.2  97/12/10  11:40:24  rvb
131  * No more ody
132  *
133  * Revision 1.5.2.1  97/12/06  17:41:20  rvb
134  * Sync with peters coda.h
135  *
136  * Revision 1.5  97/12/05  10:39:16  rvb
137  * Read CHANGES
138  *
139  * Revision 1.4.18.9  97/12/05  08:58:07  rvb
140  * peter found this one
141  *
142  * Revision 1.4.18.8  97/11/26  15:28:57  rvb
143  * Cant make downcall pbuf == union cfs_downcalls yet
144  *
145  * Revision 1.4.18.7  97/11/25  09:40:49  rvb
146  * Final cfs_venus.c w/o macros, but one locking bug
147  *
148  * Revision 1.4.18.6  97/11/20  11:46:41  rvb
149  * Capture current cfs_venus
150  *
151  * Revision 1.4.18.5  97/11/18  10:27:15  rvb
152  * cfs_nbsd.c is DEAD!!!; integrated into cfs_vf/vnops.c
153  * cfs_nb_foo and cfs_foo are joined
154  *
155  * Revision 1.4.18.4  97/11/13  22:02:59  rvb
156  * pass2 cfs_NetBSD.h mt
157  *
158  * Revision 1.4.18.3  97/11/12  12:09:38  rvb
159  * reorg pass1
160  *
161  * Revision 1.4.18.2  97/10/29  16:06:09  rvb
162  * Kill DYING
163  *
164  * Revision 1.4.18.1  1997/10/28 23:10:15  rvb
165  * >64Meg; venus can be killed!
166  *
167  * Revision 1.4  1996/12/12 22:10:58  bnoble
168  * Fixed the "downcall invokes venus operation" deadlock in all known cases.
169  * There may be more
170  *
171  * Revision 1.3  1996/11/13 04:14:20  bnoble
172  * Merging BNOBLE_WORK_6_20_96 into main line
173  *
174  * Revision 1.2.8.1  1996/08/22 14:25:04  bnoble
175  * Added a return code from vc_nb_close
176  *
177  * Revision 1.2  1996/01/02 16:56:58  bnoble
178  * Added support for Coda MiniCache and raw inode calls (final commit)
179  *
180  * Revision 1.1.2.1  1995/12/20 01:57:24  bnoble
181  * Added CODA-specific files
182  *
183  * Revision 1.1  1995/03/14  20:52:15  bnoble
184  * Initial revision
185  *
186  */
187 
188 /* These routines are the device entry points for Venus. */
189 
190 extern int coda_nc_initialized;    /* Set if cache has been initialized */
191 
192 #ifdef	_LKM
193 #define	NVCODA 4
194 #else
195 #include <vcoda.h>
196 #endif
197 
198 #include <sys/param.h>
199 #include <sys/systm.h>
200 #include <sys/kernel.h>
201 #include <sys/malloc.h>
202 #include <sys/proc.h>
203 #include <sys/mount.h>
204 #include <sys/file.h>
205 #include <sys/ioctl.h>
206 #include <sys/poll.h>
207 #include <sys/select.h>
208 
209 #include <coda/coda.h>
210 #include <coda/cnode.h>
211 #include <coda/coda_namecache.h>
212 #include <coda/coda_io.h>
213 #include <coda/coda_psdev.h>
214 
215 #define CTL_C
216 
217 int coda_psdev_print_entry = 0;
218 static
219 int outstanding_upcalls = 0;
220 int coda_call_sleep = PZERO - 1;
221 #ifdef	CTL_C
222 int coda_pcatch = PCATCH;
223 #else
224 #endif
225 
226 #define ENTRY if(coda_psdev_print_entry) myprintf(("Entered %s\n",__FUNCTION__))
227 
228 void vcodaattach(int n);
229 
230 struct vmsg {
231     struct queue vm_chain;
232     caddr_t	 vm_data;
233     u_short	 vm_flags;
234     u_short      vm_inSize;	/* Size is at most 5000 bytes */
235     u_short	 vm_outSize;
236     u_short	 vm_opcode; 	/* copied from data to save ptr lookup */
237     int		 vm_unique;
238     caddr_t	 vm_sleep;	/* Not used by Mach. */
239 };
240 
241 #define	VM_READ	    1
242 #define	VM_WRITE    2
243 #define	VM_INTR	    4
244 
245 /* vcodaattach: do nothing */
246 void
247 vcodaattach(n)
248     int n;
249 {
250 }
251 
252 /*
253  * These functions are written for NetBSD.
254  */
255 int
256 vc_nb_open(dev, flag, mode, p)
257     dev_t        dev;
258     int          flag;
259     int          mode;
260     struct proc *p;             /* NetBSD only */
261 {
262     register struct vcomm *vcp;
263 
264     ENTRY;
265 
266     if (minor(dev) >= NVCODA || minor(dev) < 0)
267 	return(ENXIO);
268 
269     if (!coda_nc_initialized)
270 	coda_nc_init();
271 
272     vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
273     if (VC_OPEN(vcp))
274 	return(EBUSY);
275 
276     bzero(&(vcp->vc_selproc), sizeof (struct selinfo));
277     INIT_QUEUE(vcp->vc_requests);
278     INIT_QUEUE(vcp->vc_replys);
279     MARK_VC_OPEN(vcp);
280 
281     coda_mnttbl[minor(dev)].mi_vfsp = NULL;
282     coda_mnttbl[minor(dev)].mi_rootvp = NULL;
283 
284     return(0);
285 }
286 
287 int
288 vc_nb_close (dev, flag, mode, p)
289     dev_t        dev;
290     int          flag;
291     int          mode;
292     struct proc *p;
293 {
294     register struct vcomm *vcp;
295     register struct vmsg *vmp, *nvmp = NULL;
296     struct coda_mntinfo *mi;
297     int                 err;
298 
299     ENTRY;
300 
301     if (minor(dev) >= NVCODA || minor(dev) < 0)
302 	return(ENXIO);
303 
304     mi = &coda_mnttbl[minor(dev)];
305     vcp = &(mi->mi_vcomm);
306 
307     if (!VC_OPEN(vcp))
308 	panic("vcclose: not open");
309 
310     /* prevent future operations on this vfs from succeeding by auto-
311      * unmounting any vfs mounted via this device. This frees user or
312      * sysadm from having to remember where all mount points are located.
313      * Put this before WAKEUPs to avoid queuing new messages between
314      * the WAKEUP and the unmount (which can happen if we're unlucky)
315      */
316     if (!mi->mi_rootvp) {
317 	/* just a simple open/close w no mount */
318 	MARK_VC_CLOSED(vcp);
319 	return 0;
320     }
321 
322     /* Let unmount know this is for real */
323     VTOC(mi->mi_rootvp)->c_flags |= C_UNMOUNTING;
324     if (vfs_busy(mi->mi_vfsp, 0, 0))
325 	return (EBUSY);
326     coda_unmounting(mi->mi_vfsp);
327 
328     /* Wakeup clients so they can return. */
329     for (vmp = (struct vmsg *)GETNEXT(vcp->vc_requests);
330 	 !EOQ(vmp, vcp->vc_requests);
331 	 nvmp = vmp)
332     {
333     	nvmp = (struct vmsg *)GETNEXT(vmp->vm_chain);
334 	/* Free signal request messages and don't wakeup cause
335 	   no one is waiting. */
336 	if (vmp->vm_opcode == CODA_SIGNAL) {
337 	    CODA_FREE((caddr_t)vmp->vm_data, (u_int)VC_IN_NO_DATA);
338 	    CODA_FREE((caddr_t)vmp, (u_int)sizeof(struct vmsg));
339 	    continue;
340 	}
341 	outstanding_upcalls++;
342 	wakeup(&vmp->vm_sleep);
343     }
344 
345     for (vmp = (struct vmsg *)GETNEXT(vcp->vc_replys);
346 	 !EOQ(vmp, vcp->vc_replys);
347 	 vmp = (struct vmsg *)GETNEXT(vmp->vm_chain))
348     {
349 	outstanding_upcalls++;
350 	wakeup(&vmp->vm_sleep);
351     }
352 
353     MARK_VC_CLOSED(vcp);
354 
355     if (outstanding_upcalls) {
356 #ifdef	CODA_VERBOSE
357 	printf("presleep: outstanding_upcalls = %d\n", outstanding_upcalls);
358     	(void) tsleep(&outstanding_upcalls, coda_call_sleep, "coda_umount", 0);
359 	printf("postsleep: outstanding_upcalls = %d\n", outstanding_upcalls);
360 #else
361     	(void) tsleep(&outstanding_upcalls, coda_call_sleep, "coda_umount", 0);
362 #endif
363     }
364 
365     err = dounmount(mi->mi_vfsp, flag, p);
366     if (err)
367 	myprintf(("Error %d unmounting vfs in vcclose(%d)\n",
368 	           err, minor(dev)));
369     return 0;
370 }
371 
372 int
373 vc_nb_read(dev, uiop, flag)
374     dev_t        dev;
375     struct uio  *uiop;
376     int          flag;
377 {
378     register struct vcomm *	vcp;
379     register struct vmsg *vmp;
380     int error = 0;
381 
382     ENTRY;
383 
384     if (minor(dev) >= NVCODA || minor(dev) < 0)
385 	return(ENXIO);
386 
387     vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
388     /* Get message at head of request queue. */
389     if (EMPTY(vcp->vc_requests))
390 	return(0);	/* Nothing to read */
391 
392     vmp = (struct vmsg *)GETNEXT(vcp->vc_requests);
393 
394     /* Move the input args into userspace */
395     uiop->uio_rw = UIO_READ;
396     error = uiomove(vmp->vm_data, vmp->vm_inSize, uiop);
397     if (error) {
398 	myprintf(("vcread: error (%d) on uiomove\n", error));
399 	error = EINVAL;
400     }
401 
402 #ifdef OLD_DIAGNOSTIC
403     if (vmp->vm_chain.forw == 0 || vmp->vm_chain.back == 0)
404 	panic("vc_nb_read: bad chain");
405 #endif
406 
407     REMQUE(vmp->vm_chain);
408 
409     /* If request was a signal, free up the message and don't
410        enqueue it in the reply queue. */
411     if (vmp->vm_opcode == CODA_SIGNAL) {
412 	if (codadebug)
413 	    myprintf(("vcread: signal msg (%d, %d)\n",
414 		      vmp->vm_opcode, vmp->vm_unique));
415 	CODA_FREE((caddr_t)vmp->vm_data, (u_int)VC_IN_NO_DATA);
416 	CODA_FREE((caddr_t)vmp, (u_int)sizeof(struct vmsg));
417 	return(error);
418     }
419 
420     vmp->vm_flags |= VM_READ;
421     INSQUE(vmp->vm_chain, vcp->vc_replys);
422 
423     return(error);
424 }
425 
426 int
427 vc_nb_write(dev, uiop, flag)
428     dev_t        dev;
429     struct uio  *uiop;
430     int          flag;
431 {
432     register struct vcomm *	vcp;
433     register struct vmsg *vmp;
434     struct coda_out_hdr *out;
435     u_long seq;
436     u_long opcode;
437     int buf[2];
438     int error = 0;
439 
440     ENTRY;
441 
442     if (minor(dev) >= NVCODA || minor(dev) < 0)
443 	return(ENXIO);
444 
445     vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
446 
447     /* Peek at the opcode, unique without transfering the data. */
448     uiop->uio_rw = UIO_WRITE;
449     error = uiomove((caddr_t)buf, sizeof(int) * 2, uiop);
450     if (error) {
451 	myprintf(("vcwrite: error (%d) on uiomove\n", error));
452 	return(EINVAL);
453     }
454 
455     opcode = buf[0];
456     seq = buf[1];
457 
458     if (codadebug)
459 	myprintf(("vcwrite got a call for %ld.%ld\n", opcode, seq));
460 
461     if (DOWNCALL(opcode)) {
462 	union outputArgs pbuf;
463 
464 	/* get the rest of the data. */
465 	uiop->uio_rw = UIO_WRITE;
466 	error = uiomove((caddr_t)&pbuf.coda_purgeuser.oh.result, sizeof(pbuf) - (sizeof(int)*2), uiop);
467 	if (error) {
468 	    myprintf(("vcwrite: error (%d) on uiomove (Op %ld seq %ld)\n",
469 		      error, opcode, seq));
470 	    return(EINVAL);
471 	    }
472 
473 	return handleDownCall(opcode, &pbuf);
474     }
475 
476     /* Look for the message on the (waiting for) reply queue. */
477     for (vmp = (struct vmsg *)GETNEXT(vcp->vc_replys);
478 	 !EOQ(vmp, vcp->vc_replys);
479 	 vmp = (struct vmsg *)GETNEXT(vmp->vm_chain))
480     {
481 	if (vmp->vm_unique == seq) break;
482     }
483 
484     if (EOQ(vmp, vcp->vc_replys)) {
485 	if (codadebug)
486 	    myprintf(("vcwrite: msg (%ld, %ld) not found\n", opcode, seq));
487 
488 	return(ESRCH);
489 	}
490 
491     /* Remove the message from the reply queue */
492     REMQUE(vmp->vm_chain);
493 
494     /* move data into response buffer. */
495     out = (struct coda_out_hdr *)vmp->vm_data;
496     /* Don't need to copy opcode and uniquifier. */
497 
498     /* get the rest of the data. */
499     if (vmp->vm_outSize < uiop->uio_resid) {
500 	myprintf(("vcwrite: more data than asked for (%d < %d)\n",
501 		  vmp->vm_outSize, uiop->uio_resid));
502 	wakeup(&vmp->vm_sleep); 	/* Notify caller of the error. */
503 	return(EINVAL);
504     }
505 
506     buf[0] = uiop->uio_resid; 	/* Save this value. */
507     uiop->uio_rw = UIO_WRITE;
508     error = uiomove((caddr_t) &out->result, vmp->vm_outSize - (sizeof(int) * 2), uiop);
509     if (error) {
510 	myprintf(("vcwrite: error (%d) on uiomove (op %ld seq %ld)\n",
511 		  error, opcode, seq));
512 	return(EINVAL);
513     }
514 
515     /* I don't think these are used, but just in case. */
516     /* XXX - aren't these two already correct? -bnoble */
517     out->opcode = opcode;
518     out->unique = seq;
519     vmp->vm_outSize	= buf[0];	/* Amount of data transferred? */
520     vmp->vm_flags |= VM_WRITE;
521     wakeup(&vmp->vm_sleep);
522 
523     return(0);
524 }
525 
526 int
527 vc_nb_ioctl(dev, cmd, addr, flag, p)
528     dev_t         dev;
529     u_long        cmd;
530     caddr_t       addr;
531     int           flag;
532     struct proc  *p;
533 {
534     ENTRY;
535 
536     switch(cmd) {
537     case CODARESIZE: {
538 	struct coda_resize *data = (struct coda_resize *)addr;
539 	return(coda_nc_resize(data->hashsize, data->heapsize, IS_DOWNCALL));
540 	break;
541     }
542     case CODASTATS:
543 	if (coda_nc_use) {
544 	    coda_nc_gather_stats();
545 	    return(0);
546 	} else {
547 	    return(ENODEV);
548 	}
549 	break;
550     case CODAPRINT:
551 	if (coda_nc_use) {
552 	    print_coda_nc();
553 	    return(0);
554 	} else {
555 	    return(ENODEV);
556 	}
557 	break;
558     case CIOC_KERNEL_VERSION:
559 	switch (*(u_int *)addr) {
560 	case 0:
561 		*(u_int *)addr = coda_kernel_version;
562 		return 0;
563 		break;
564 	case 1:
565 	case 2:
566 		if (coda_kernel_version != *(u_int *)addr)
567 		    return ENOENT;
568 		else
569 		    return 0;
570 	default:
571 		return ENOENT;
572 	}
573     	break;
574     default :
575 	return(EINVAL);
576 	break;
577     }
578 }
579 
580 int
581 vc_nb_poll(dev, events, p)
582     dev_t         dev;
583     int           events;
584     struct proc  *p;
585 {
586     register struct vcomm *vcp;
587     int event_msk = 0;
588 
589     ENTRY;
590 
591     if (minor(dev) >= NVCODA || minor(dev) < 0)
592 	return(ENXIO);
593 
594     vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
595 
596     event_msk = events & (POLLIN|POLLRDNORM);
597     if (!event_msk)
598 	return(0);
599 
600     if (!EMPTY(vcp->vc_requests))
601 	return(events & (POLLIN|POLLRDNORM));
602 
603     selrecord(p, &(vcp->vc_selproc));
604 
605     return(0);
606 }
607 
608 /*
609  * Statistics
610  */
611 struct coda_clstat coda_clstat;
612 
613 /*
614  * Key question: whether to sleep interuptably or uninteruptably when
615  * waiting for Venus.  The former seems better (cause you can ^C a
616  * job), but then GNU-EMACS completion breaks. Use tsleep with no
617  * timeout, and no longjmp happens. But, when sleeping
618  * "uninterruptibly", we don't get told if it returns abnormally
619  * (e.g. kill -9).
620  */
621 
622 int
623 coda_call(mntinfo, inSize, outSize, buffer)
624      struct coda_mntinfo *mntinfo; int inSize; int *outSize; caddr_t buffer;
625 {
626 	struct vcomm *vcp;
627 	struct vmsg *vmp;
628 	int error;
629 #ifdef	CTL_C
630 	struct proc *p = curproc;
631 	sigset_t psig_omask;
632 	int i;
633 	psig_omask = p->p_siglist;	/* array assignment */
634 #endif
635 	if (mntinfo == NULL) {
636 	    /* Unlikely, but could be a race condition with a dying warden */
637 	    return ENODEV;
638 	}
639 
640 	vcp = &(mntinfo->mi_vcomm);
641 
642 	coda_clstat.ncalls++;
643 	coda_clstat.reqs[((struct coda_in_hdr *)buffer)->opcode]++;
644 
645 	if (!VC_OPEN(vcp))
646 	    return(ENODEV);
647 
648 	CODA_ALLOC(vmp,struct vmsg *,sizeof(struct vmsg));
649 	/* Format the request message. */
650 	vmp->vm_data = buffer;
651 	vmp->vm_flags = 0;
652 	vmp->vm_inSize = inSize;
653 	vmp->vm_outSize
654 	    = *outSize ? *outSize : inSize; /* |buffer| >= inSize */
655 	vmp->vm_opcode = ((struct coda_in_hdr *)buffer)->opcode;
656 	vmp->vm_unique = ++vcp->vc_seq;
657 	if (codadebug)
658 	    myprintf(("Doing a call for %d.%d\n",
659 		      vmp->vm_opcode, vmp->vm_unique));
660 
661 	/* Fill in the common input args. */
662 	((struct coda_in_hdr *)buffer)->unique = vmp->vm_unique;
663 
664 	/* Append msg to request queue and poke Venus. */
665 	INSQUE(vmp->vm_chain, vcp->vc_requests);
666 	selwakeup(&(vcp->vc_selproc));
667 
668 	/* We can be interrupted while we wait for Venus to process
669 	 * our request.  If the interrupt occurs before Venus has read
670 	 * the request, we dequeue and return. If it occurs after the
671 	 * read but before the reply, we dequeue, send a signal
672 	 * message, and return. If it occurs after the reply we ignore
673 	 * it. In no case do we want to restart the syscall.  If it
674 	 * was interrupted by a venus shutdown (vcclose), return
675 	 * ENODEV.  */
676 
677 	/* Ignore return, We have to check anyway */
678 #ifdef	CTL_C
679 	/* This is work in progress.  Setting coda_pcatch lets tsleep reawaken
680 	   on a ^c or ^z.  The problem is that emacs sets certain interrupts
681 	   as SA_RESTART.  This means that we should exit sleep handle the
682 	   "signal" and then go to sleep again.  Mostly this is done by letting
683 	   the syscall complete and be restarted.  We are not idempotent and
684 	   can not do this.  A better solution is necessary.
685 	 */
686 	i = 0;
687 	do {
688 	    error = tsleep(&vmp->vm_sleep, (coda_call_sleep|coda_pcatch), "coda_call", hz*2);
689 	    if (error == 0)
690 	    	break;
691 	    else if (error == EWOULDBLOCK) {
692 #ifdef	CODA_VERBOSE
693 		    printf("coda_call: tsleep TIMEOUT %d sec\n", 2+2*i);
694 #endif
695     	    } else if (sigismember(&p->p_siglist, SIGIO)) {
696 		    sigaddset(&p->p_sigmask, SIGIO);
697 #ifdef	CODA_VERBOSE
698 		    printf("coda_call: tsleep returns %d SIGIO, cnt %d\n", error, i);
699 #endif
700     	    } else if (sigismember(&p->p_siglist, SIGALRM)) {
701 		    sigaddset(&p->p_sigmask, SIGALRM);
702 #ifdef	CODA_VERBOSE
703 		    printf("coda_call: tsleep returns %d SIGALRM, cnt %d\n", error, i);
704 #endif
705 	    } else {
706 		    sigset_t tmp;
707 		    tmp = p->p_siglist;		/* array assignment */
708 		    sigminusset(&p->p_sigmask, &tmp);
709 
710 #ifdef	CODA_VERBOSE
711 		    printf("coda_call: tsleep returns %d, cnt %d\n", error, i);
712 		    printf("coda_call: siglist = %x.%x.%x.%x, sigmask = %x.%x.%x.%x, mask %x.%x.%x.%x\n",
713 			    p->p_siglist.__bits[0], p->p_siglist.__bits[1],
714 			    p->p_siglist.__bits[2], p->p_siglist.__bits[3],
715 			    p->p_sigmask.__bits[0], p->p_sigmask.__bits[1],
716 			    p->p_sigmask.__bits[2], p->p_sigmask.__bits[3],
717 			    tmp.__bits[0], tmp.__bits[1], tmp.__bits[2], tmp.__bits[3]);
718 #endif
719 		    break;
720 #ifdef	notyet
721 		    sigminusset(&p->p_sigmask, &p->p_siglist);
722 		    printf("coda_call: siglist = %x.%x.%x.%x, sigmask = %x.%x.%x.%x\n",
723 			    p->p_siglist.__bits[0], p->p_siglist.__bits[1],
724 			    p->p_siglist.__bits[2], p->p_siglist.__bits[3],
725 			    p->p_sigmask.__bits[0], p->p_sigmask.__bits[1],
726 			    p->p_sigmask.__bits[2], p->p_sigmask.__bits[3]);
727 #endif
728 	    }
729 	} while (error && i++ < 128 && VC_OPEN(vcp));
730 	p->p_siglist = psig_omask;	/* array assignment */
731 #else
732 	(void) tsleep(&vmp->vm_sleep, coda_call_sleep, "coda_call", 0);
733 #endif
734 	if (VC_OPEN(vcp)) {	/* Venus is still alive */
735  	/* Op went through, interrupt or not... */
736 	    if (vmp->vm_flags & VM_WRITE) {
737 		error = 0;
738 		*outSize = vmp->vm_outSize;
739 	    }
740 
741 	    else if (!(vmp->vm_flags & VM_READ)) {
742 		/* Interrupted before venus read it. */
743 #ifdef	CODA_VERBOSE
744 		if (1)
745 #else
746 		if (codadebug)
747 #endif
748 		    myprintf(("interrupted before read: op = %d.%d, flags = %x\n",
749 			   vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
750 		REMQUE(vmp->vm_chain);
751 		error = EINTR;
752 	    }
753 
754 	    else {
755 		/* (!(vmp->vm_flags & VM_WRITE)) means interrupted after
756                    upcall started */
757 		/* Interrupted after start of upcall, send venus a signal */
758 		struct coda_in_hdr *dog;
759 		struct vmsg *svmp;
760 
761 #ifdef	CODA_VERBOSE
762 		if (1)
763 #else
764 		if (codadebug)
765 #endif
766 		    myprintf(("Sending Venus a signal: op = %d.%d, flags = %x\n",
767 			   vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
768 
769 		REMQUE(vmp->vm_chain);
770 		error = EINTR;
771 
772 		CODA_ALLOC(svmp, struct vmsg *, sizeof (struct vmsg));
773 
774 		CODA_ALLOC((svmp->vm_data), char *, sizeof (struct coda_in_hdr));
775 		dog = (struct coda_in_hdr *)svmp->vm_data;
776 
777 		svmp->vm_flags = 0;
778 		dog->opcode = svmp->vm_opcode = CODA_SIGNAL;
779 		dog->unique = svmp->vm_unique = vmp->vm_unique;
780 		svmp->vm_inSize = sizeof (struct coda_in_hdr);
781 /*??? rvb */	svmp->vm_outSize = sizeof (struct coda_in_hdr);
782 
783 		if (codadebug)
784 		    myprintf(("coda_call: enqueing signal msg (%d, %d)\n",
785 			   svmp->vm_opcode, svmp->vm_unique));
786 
787 		/* insert at head of queue! */
788 		INSQUE(svmp->vm_chain, vcp->vc_requests);
789 		selwakeup(&(vcp->vc_selproc));
790 	    }
791 	}
792 
793 	else {	/* If venus died (!VC_OPEN(vcp)) */
794 	    if (codadebug)
795 		myprintf(("vcclose woke op %d.%d flags %d\n",
796 		       vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
797 
798 		error = ENODEV;
799 	}
800 
801 	CODA_FREE(vmp, sizeof(struct vmsg));
802 
803 	if (outstanding_upcalls > 0 && (--outstanding_upcalls == 0))
804 		wakeup(&outstanding_upcalls);
805 
806 	if (!error)
807 		error = ((struct coda_out_hdr *)buffer)->result;
808 	return(error);
809 }
810 
811