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