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