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