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