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