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