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