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