coda_psdev.c revision 1.9.4.1 1 /* $NetBSD: coda_psdev.c,v 1.9.4.1 1999/04/29 21:09:40 rvb 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 psuedo 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
52 /*
53 * HISTORY
54 * $Log: coda_psdev.c,v $
55 * Revision 1.9.4.1 1999/04/29 21:09:40 rvb
56 * pullup 1.9->1.10 (rvb)
57 *
58 * Revision 1.9 1998/11/11 19:22:08 rvb
59 * Lookup now passes up an extra flag. But old veni will
60 * be ok; new veni will check /dev/cfs0 to make sure that a new
61 * kernel is running.
62 * Also, a bug in vc_nb_close iff CODA_SIGNAL's were seen has been
63 * fixed.
64 *
65 * Revision 1.8 1998/11/09 16:36:16 rvb
66 * Change the way unmounting happens to guarantee that the
67 * client programs are allowed to finish up (coda_call is
68 * forced to complete) and release their locks. Thus there
69 * is a reasonable chance that the vflush implicit in the
70 * unmount will not get hung on held locks.
71 *
72 * Revision 1.7 1998/09/28 17:55:22 rvb
73 * I want to distinguish from DEBUG printouts and CODA_VERBOSE printouts.
74 * The latter are normal informational messages that are sometimes
75 * interesting to view.
76 *
77 * Revision 1.6 1998/09/26 15:24:46 tv
78 * DIAGNOSTIC -> DEBUG for all non-panic messages. DIAGNOSTIC is only for
79 * sanity checks and should not turn on any messages not already printed
80 * without it.
81 *
82 * Revision 1.5 1998/09/25 15:01:13 rvb
83 * Conditionalize "stray" printouts under DIAGNOSTIC and DEBUG.
84 * Make files compile if DEBUG is on (from Alan Barrett). Finally,
85 * make coda an lkm.
86 *
87 * Revision 1.4 1998/09/15 02:02:59 rvb
88 * Final piece of rename cfs->coda
89 *
90 * Revision 1.3 1998/09/12 15:05:48 rvb
91 * Change cfs/CFS in symbols, strings and constants to coda/CODA
92 * to avoid fs conflicts.
93 *
94 * Revision 1.2 1998/09/08 17:12:47 rvb
95 * Pass2 complete
96 *
97 * Revision 1.1.1.1 1998/08/29 21:26:45 rvb
98 * Very Preliminary Coda
99 *
100 * Revision 1.9 1998/08/28 18:12:17 rvb
101 * Now it also works on FreeBSD -current. This code will be
102 * committed to the FreeBSD -current and NetBSD -current
103 * trees. It will then be tailored to the particular platform
104 * by flushing conditional code.
105 *
106 * Revision 1.8 1998/08/18 17:05:15 rvb
107 * Don't use __RCSID now
108 *
109 * Revision 1.7 1998/08/18 16:31:41 rvb
110 * Sync the code for NetBSD -current; test on 1.3 later
111 *
112 * Revision 1.8 1998/06/09 23:30:42 rvb
113 * Try to allow ^C -- take 1
114 *
115 * Revision 1.5.2.8 98/01/23 11:21:04 rvb
116 * Sync with 2.2.5
117 *
118 * Revision 1.5.2.7 98/01/22 22:22:21 rvb
119 * sync 1.2 and 1.3
120 *
121 * Revision 1.5.2.6 98/01/22 13:11:24 rvb
122 * Move make_coda_node ctlfid later so vfsp is known; work on ^c and ^z
123 *
124 * Revision 1.5.2.5 97/12/16 22:01:27 rvb
125 * Oops add cfs_subr.h cfs_venus.h; sync with peter
126 *
127 * Revision 1.5.2.4 97/12/16 12:40:05 rvb
128 * Sync with 1.3
129 *
130 * Revision 1.5.2.3 97/12/10 14:08:24 rvb
131 * Fix O_ flags; check result in coda_call
132 *
133 * Revision 1.5.2.2 97/12/10 11:40:24 rvb
134 * No more ody
135 *
136 * Revision 1.5.2.1 97/12/06 17:41:20 rvb
137 * Sync with peters coda.h
138 *
139 * Revision 1.5 97/12/05 10:39:16 rvb
140 * Read CHANGES
141 *
142 * Revision 1.4.18.9 97/12/05 08:58:07 rvb
143 * peter found this one
144 *
145 * Revision 1.4.18.8 97/11/26 15:28:57 rvb
146 * Cant make downcall pbuf == union cfs_downcalls yet
147 *
148 * Revision 1.4.18.7 97/11/25 09:40:49 rvb
149 * Final cfs_venus.c w/o macros, but one locking bug
150 *
151 * Revision 1.4.18.6 97/11/20 11:46:41 rvb
152 * Capture current cfs_venus
153 *
154 * Revision 1.4.18.5 97/11/18 10:27:15 rvb
155 * cfs_nbsd.c is DEAD!!!; integrated into cfs_vf/vnops.c
156 * cfs_nb_foo and cfs_foo are joined
157 *
158 * Revision 1.4.18.4 97/11/13 22:02:59 rvb
159 * pass2 cfs_NetBSD.h mt
160 *
161 * Revision 1.4.18.3 97/11/12 12:09:38 rvb
162 * reorg pass1
163 *
164 * Revision 1.4.18.2 97/10/29 16:06:09 rvb
165 * Kill DYING
166 *
167 * Revision 1.4.18.1 1997/10/28 23:10:15 rvb
168 * >64Meg; venus can be killed!
169 *
170 * Revision 1.4 1996/12/12 22:10:58 bnoble
171 * Fixed the "downcall invokes venus operation" deadlock in all known cases.
172 * There may be more
173 *
174 * Revision 1.3 1996/11/13 04:14:20 bnoble
175 * Merging BNOBLE_WORK_6_20_96 into main line
176 *
177 * Revision 1.2.8.1 1996/08/22 14:25:04 bnoble
178 * Added a return code from vc_nb_close
179 *
180 * Revision 1.2 1996/01/02 16:56:58 bnoble
181 * Added support for Coda MiniCache and raw inode calls (final commit)
182 *
183 * Revision 1.1.2.1 1995/12/20 01:57:24 bnoble
184 * Added CODA-specific files
185 *
186 * Revision 1.1 1995/03/14 20:52:15 bnoble
187 * Initial revision
188 *
189 */
190
191 /* These routines are the device entry points for Venus. */
192
193 extern int coda_nc_initialized; /* Set if cache has been initialized */
194
195 #ifdef _LKM
196 #define NVCODA 4
197 #else
198 #include <vcoda.h>
199 #endif
200
201 #include <sys/param.h>
202 #include <sys/systm.h>
203 #include <sys/kernel.h>
204 #include <sys/malloc.h>
205 #include <sys/proc.h>
206 #include <sys/mount.h>
207 #include <sys/file.h>
208 #include <sys/ioctl.h>
209 #include <sys/poll.h>
210 #include <sys/select.h>
211
212 #include <coda/coda.h>
213 #include <coda/cnode.h>
214 #include <coda/coda_namecache.h>
215 #include <coda/coda_io.h>
216 #include <coda/coda_psdev.h>
217
218 #define CTL_C
219
220 int coda_psdev_print_entry = 0;
221 static
222 int outstanding_upcalls = 0;
223 int coda_call_sleep = PZERO - 1;
224 #ifdef CTL_C
225 int coda_pcatch = PCATCH;
226 #else
227 #endif
228
229 #define ENTRY if(coda_psdev_print_entry) myprintf(("Entered %s\n",__FUNCTION__))
230
231 void vcodaattach(int n);
232
233 struct vmsg {
234 struct queue vm_chain;
235 caddr_t vm_data;
236 u_short vm_flags;
237 u_short vm_inSize; /* Size is at most 5000 bytes */
238 u_short vm_outSize;
239 u_short vm_opcode; /* copied from data to save ptr lookup */
240 int vm_unique;
241 caddr_t vm_sleep; /* Not used by Mach. */
242 };
243
244 #define VM_READ 1
245 #define VM_WRITE 2
246 #define VM_INTR 4
247
248 /* vcodaattach: do nothing */
249 void
250 vcodaattach(n)
251 int n;
252 {
253 }
254
255 /*
256 * These functions are written for NetBSD.
257 */
258 int
259 vc_nb_open(dev, flag, mode, p)
260 dev_t dev;
261 int flag;
262 int mode;
263 struct proc *p; /* NetBSD only */
264 {
265 register struct vcomm *vcp;
266
267 ENTRY;
268
269 if (minor(dev) >= NVCODA || minor(dev) < 0)
270 return(ENXIO);
271
272 if (!coda_nc_initialized)
273 coda_nc_init();
274
275 vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
276 if (VC_OPEN(vcp))
277 return(EBUSY);
278
279 bzero(&(vcp->vc_selproc), sizeof (struct selinfo));
280 INIT_QUEUE(vcp->vc_requests);
281 INIT_QUEUE(vcp->vc_replys);
282 MARK_VC_OPEN(vcp);
283
284 coda_mnttbl[minor(dev)].mi_vfsp = NULL;
285 coda_mnttbl[minor(dev)].mi_rootvp = NULL;
286
287 return(0);
288 }
289
290 int
291 vc_nb_close (dev, flag, mode, p)
292 dev_t dev;
293 int flag;
294 int mode;
295 struct proc *p;
296 {
297 register struct vcomm *vcp;
298 register struct vmsg *vmp, *nvmp = NULL;
299 struct coda_mntinfo *mi;
300 int err;
301
302 ENTRY;
303
304 if (minor(dev) >= NVCODA || minor(dev) < 0)
305 return(ENXIO);
306
307 mi = &coda_mnttbl[minor(dev)];
308 vcp = &(mi->mi_vcomm);
309
310 if (!VC_OPEN(vcp))
311 panic("vcclose: not open");
312
313 /* prevent future operations on this vfs from succeeding by auto-
314 * unmounting any vfs mounted via this device. This frees user or
315 * sysadm from having to remember where all mount points are located.
316 * Put this before WAKEUPs to avoid queuing new messages between
317 * the WAKEUP and the unmount (which can happen if we're unlucky)
318 */
319 if (!mi->mi_rootvp) {
320 /* just a simple open/close w no mount */
321 MARK_VC_CLOSED(vcp);
322 return 0;
323 }
324
325 /* Let unmount know this is for real */
326 VTOC(mi->mi_rootvp)->c_flags |= C_UNMOUNTING;
327 if (vfs_busy(mi->mi_vfsp, 0, 0))
328 return (EBUSY);
329 coda_unmounting(mi->mi_vfsp);
330
331 /* Wakeup clients so they can return. */
332 for (vmp = (struct vmsg *)GETNEXT(vcp->vc_requests);
333 !EOQ(vmp, vcp->vc_requests);
334 vmp = nvmp)
335 {
336 nvmp = (struct vmsg *)GETNEXT(vmp->vm_chain);
337 /* Free signal request messages and don't wakeup cause
338 no one is waiting. */
339 if (vmp->vm_opcode == CODA_SIGNAL) {
340 CODA_FREE((caddr_t)vmp->vm_data, (u_int)VC_IN_NO_DATA);
341 CODA_FREE((caddr_t)vmp, (u_int)sizeof(struct vmsg));
342 continue;
343 }
344 outstanding_upcalls++;
345 wakeup(&vmp->vm_sleep);
346 }
347
348 for (vmp = (struct vmsg *)GETNEXT(vcp->vc_replys);
349 !EOQ(vmp, vcp->vc_replys);
350 vmp = (struct vmsg *)GETNEXT(vmp->vm_chain))
351 {
352 outstanding_upcalls++;
353 wakeup(&vmp->vm_sleep);
354 }
355
356 MARK_VC_CLOSED(vcp);
357
358 if (outstanding_upcalls) {
359 #ifdef CODA_VERBOSE
360 printf("presleep: outstanding_upcalls = %d\n", outstanding_upcalls);
361 (void) tsleep(&outstanding_upcalls, coda_call_sleep, "coda_umount", 0);
362 printf("postsleep: outstanding_upcalls = %d\n", outstanding_upcalls);
363 #else
364 (void) tsleep(&outstanding_upcalls, coda_call_sleep, "coda_umount", 0);
365 #endif
366 }
367
368 err = dounmount(mi->mi_vfsp, flag, p);
369 if (err)
370 myprintf(("Error %d unmounting vfs in vcclose(%d)\n",
371 err, minor(dev)));
372 return 0;
373 }
374
375 int
376 vc_nb_read(dev, uiop, flag)
377 dev_t dev;
378 struct uio *uiop;
379 int flag;
380 {
381 register struct vcomm * vcp;
382 register struct vmsg *vmp;
383 int error = 0;
384
385 ENTRY;
386
387 if (minor(dev) >= NVCODA || minor(dev) < 0)
388 return(ENXIO);
389
390 vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
391 /* Get message at head of request queue. */
392 if (EMPTY(vcp->vc_requests))
393 return(0); /* Nothing to read */
394
395 vmp = (struct vmsg *)GETNEXT(vcp->vc_requests);
396
397 /* Move the input args into userspace */
398 uiop->uio_rw = UIO_READ;
399 error = uiomove(vmp->vm_data, vmp->vm_inSize, uiop);
400 if (error) {
401 myprintf(("vcread: error (%d) on uiomove\n", error));
402 error = EINVAL;
403 }
404
405 #ifdef OLD_DIAGNOSTIC
406 if (vmp->vm_chain.forw == 0 || vmp->vm_chain.back == 0)
407 panic("vc_nb_read: bad chain");
408 #endif
409
410 REMQUE(vmp->vm_chain);
411
412 /* If request was a signal, free up the message and don't
413 enqueue it in the reply queue. */
414 if (vmp->vm_opcode == CODA_SIGNAL) {
415 if (codadebug)
416 myprintf(("vcread: signal msg (%d, %d)\n",
417 vmp->vm_opcode, vmp->vm_unique));
418 CODA_FREE((caddr_t)vmp->vm_data, (u_int)VC_IN_NO_DATA);
419 CODA_FREE((caddr_t)vmp, (u_int)sizeof(struct vmsg));
420 return(error);
421 }
422
423 vmp->vm_flags |= VM_READ;
424 INSQUE(vmp->vm_chain, vcp->vc_replys);
425
426 return(error);
427 }
428
429 int
430 vc_nb_write(dev, uiop, flag)
431 dev_t dev;
432 struct uio *uiop;
433 int flag;
434 {
435 register struct vcomm * vcp;
436 register struct vmsg *vmp;
437 struct coda_out_hdr *out;
438 u_long seq;
439 u_long opcode;
440 int buf[2];
441 int error = 0;
442
443 ENTRY;
444
445 if (minor(dev) >= NVCODA || minor(dev) < 0)
446 return(ENXIO);
447
448 vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
449
450 /* Peek at the opcode, unique without transfering the data. */
451 uiop->uio_rw = UIO_WRITE;
452 error = uiomove((caddr_t)buf, sizeof(int) * 2, uiop);
453 if (error) {
454 myprintf(("vcwrite: error (%d) on uiomove\n", error));
455 return(EINVAL);
456 }
457
458 opcode = buf[0];
459 seq = buf[1];
460
461 if (codadebug)
462 myprintf(("vcwrite got a call for %ld.%ld\n", opcode, seq));
463
464 if (DOWNCALL(opcode)) {
465 union outputArgs pbuf;
466
467 /* get the rest of the data. */
468 uiop->uio_rw = UIO_WRITE;
469 error = uiomove((caddr_t)&pbuf.coda_purgeuser.oh.result, sizeof(pbuf) - (sizeof(int)*2), uiop);
470 if (error) {
471 myprintf(("vcwrite: error (%d) on uiomove (Op %ld seq %ld)\n",
472 error, opcode, seq));
473 return(EINVAL);
474 }
475
476 return handleDownCall(opcode, &pbuf);
477 }
478
479 /* Look for the message on the (waiting for) reply queue. */
480 for (vmp = (struct vmsg *)GETNEXT(vcp->vc_replys);
481 !EOQ(vmp, vcp->vc_replys);
482 vmp = (struct vmsg *)GETNEXT(vmp->vm_chain))
483 {
484 if (vmp->vm_unique == seq) break;
485 }
486
487 if (EOQ(vmp, vcp->vc_replys)) {
488 if (codadebug)
489 myprintf(("vcwrite: msg (%ld, %ld) not found\n", opcode, seq));
490
491 return(ESRCH);
492 }
493
494 /* Remove the message from the reply queue */
495 REMQUE(vmp->vm_chain);
496
497 /* move data into response buffer. */
498 out = (struct coda_out_hdr *)vmp->vm_data;
499 /* Don't need to copy opcode and uniquifier. */
500
501 /* get the rest of the data. */
502 if (vmp->vm_outSize < uiop->uio_resid) {
503 myprintf(("vcwrite: more data than asked for (%d < %d)\n",
504 vmp->vm_outSize, uiop->uio_resid));
505 wakeup(&vmp->vm_sleep); /* Notify caller of the error. */
506 return(EINVAL);
507 }
508
509 buf[0] = uiop->uio_resid; /* Save this value. */
510 uiop->uio_rw = UIO_WRITE;
511 error = uiomove((caddr_t) &out->result, vmp->vm_outSize - (sizeof(int) * 2), uiop);
512 if (error) {
513 myprintf(("vcwrite: error (%d) on uiomove (op %ld seq %ld)\n",
514 error, opcode, seq));
515 return(EINVAL);
516 }
517
518 /* I don't think these are used, but just in case. */
519 /* XXX - aren't these two already correct? -bnoble */
520 out->opcode = opcode;
521 out->unique = seq;
522 vmp->vm_outSize = buf[0]; /* Amount of data transferred? */
523 vmp->vm_flags |= VM_WRITE;
524 wakeup(&vmp->vm_sleep);
525
526 return(0);
527 }
528
529 int
530 vc_nb_ioctl(dev, cmd, addr, flag, p)
531 dev_t dev;
532 u_long cmd;
533 caddr_t addr;
534 int flag;
535 struct proc *p;
536 {
537 ENTRY;
538
539 switch(cmd) {
540 case CODARESIZE: {
541 struct coda_resize *data = (struct coda_resize *)addr;
542 return(coda_nc_resize(data->hashsize, data->heapsize, IS_DOWNCALL));
543 break;
544 }
545 case CODASTATS:
546 if (coda_nc_use) {
547 coda_nc_gather_stats();
548 return(0);
549 } else {
550 return(ENODEV);
551 }
552 break;
553 case CODAPRINT:
554 if (coda_nc_use) {
555 print_coda_nc();
556 return(0);
557 } else {
558 return(ENODEV);
559 }
560 break;
561 case CIOC_KERNEL_VERSION:
562 switch (*(u_int *)addr) {
563 case 0:
564 *(u_int *)addr = coda_kernel_version;
565 return 0;
566 break;
567 case 1:
568 case 2:
569 if (coda_kernel_version != *(u_int *)addr)
570 return ENOENT;
571 else
572 return 0;
573 default:
574 return ENOENT;
575 }
576 break;
577 default :
578 return(EINVAL);
579 break;
580 }
581 }
582
583 int
584 vc_nb_poll(dev, events, p)
585 dev_t dev;
586 int events;
587 struct proc *p;
588 {
589 register struct vcomm *vcp;
590 int event_msk = 0;
591
592 ENTRY;
593
594 if (minor(dev) >= NVCODA || minor(dev) < 0)
595 return(ENXIO);
596
597 vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
598
599 event_msk = events & (POLLIN|POLLRDNORM);
600 if (!event_msk)
601 return(0);
602
603 if (!EMPTY(vcp->vc_requests))
604 return(events & (POLLIN|POLLRDNORM));
605
606 selrecord(p, &(vcp->vc_selproc));
607
608 return(0);
609 }
610
611 /*
612 * Statistics
613 */
614 struct coda_clstat coda_clstat;
615
616 /*
617 * Key question: whether to sleep interuptably or uninteruptably when
618 * waiting for Venus. The former seems better (cause you can ^C a
619 * job), but then GNU-EMACS completion breaks. Use tsleep with no
620 * timeout, and no longjmp happens. But, when sleeping
621 * "uninterruptibly", we don't get told if it returns abnormally
622 * (e.g. kill -9).
623 */
624
625 int
626 coda_call(mntinfo, inSize, outSize, buffer)
627 struct coda_mntinfo *mntinfo; int inSize; int *outSize; caddr_t buffer;
628 {
629 struct vcomm *vcp;
630 struct vmsg *vmp;
631 int error;
632 #ifdef CTL_C
633 struct proc *p = curproc;
634 sigset_t psig_omask;
635 int i;
636 psig_omask = p->p_siglist; /* array assignment */
637 #endif
638 if (mntinfo == NULL) {
639 /* Unlikely, but could be a race condition with a dying warden */
640 return ENODEV;
641 }
642
643 vcp = &(mntinfo->mi_vcomm);
644
645 coda_clstat.ncalls++;
646 coda_clstat.reqs[((struct coda_in_hdr *)buffer)->opcode]++;
647
648 if (!VC_OPEN(vcp))
649 return(ENODEV);
650
651 CODA_ALLOC(vmp,struct vmsg *,sizeof(struct vmsg));
652 /* Format the request message. */
653 vmp->vm_data = buffer;
654 vmp->vm_flags = 0;
655 vmp->vm_inSize = inSize;
656 vmp->vm_outSize
657 = *outSize ? *outSize : inSize; /* |buffer| >= inSize */
658 vmp->vm_opcode = ((struct coda_in_hdr *)buffer)->opcode;
659 vmp->vm_unique = ++vcp->vc_seq;
660 if (codadebug)
661 myprintf(("Doing a call for %d.%d\n",
662 vmp->vm_opcode, vmp->vm_unique));
663
664 /* Fill in the common input args. */
665 ((struct coda_in_hdr *)buffer)->unique = vmp->vm_unique;
666
667 /* Append msg to request queue and poke Venus. */
668 INSQUE(vmp->vm_chain, vcp->vc_requests);
669 selwakeup(&(vcp->vc_selproc));
670
671 /* We can be interrupted while we wait for Venus to process
672 * our request. If the interrupt occurs before Venus has read
673 * the request, we dequeue and return. If it occurs after the
674 * read but before the reply, we dequeue, send a signal
675 * message, and return. If it occurs after the reply we ignore
676 * it. In no case do we want to restart the syscall. If it
677 * was interrupted by a venus shutdown (vcclose), return
678 * ENODEV. */
679
680 /* Ignore return, We have to check anyway */
681 #ifdef CTL_C
682 /* This is work in progress. Setting coda_pcatch lets tsleep reawaken
683 on a ^c or ^z. The problem is that emacs sets certain interrupts
684 as SA_RESTART. This means that we should exit sleep handle the
685 "signal" and then go to sleep again. Mostly this is done by letting
686 the syscall complete and be restarted. We are not idempotent and
687 can not do this. A better solution is necessary.
688 */
689 i = 0;
690 do {
691 error = tsleep(&vmp->vm_sleep, (coda_call_sleep|coda_pcatch), "coda_call", hz*2);
692 if (error == 0)
693 break;
694 else if (error == EWOULDBLOCK) {
695 #ifdef CODA_VERBOSE
696 printf("coda_call: tsleep TIMEOUT %d sec\n", 2+2*i);
697 #endif
698 } else if (sigismember(&p->p_siglist, SIGIO)) {
699 sigaddset(&p->p_sigmask, SIGIO);
700 #ifdef CODA_VERBOSE
701 printf("coda_call: tsleep returns %d SIGIO, cnt %d\n", error, i);
702 #endif
703 } else if (sigismember(&p->p_siglist, SIGALRM)) {
704 sigaddset(&p->p_sigmask, SIGALRM);
705 #ifdef CODA_VERBOSE
706 printf("coda_call: tsleep returns %d SIGALRM, cnt %d\n", error, i);
707 #endif
708 } else {
709 sigset_t tmp;
710 tmp = p->p_siglist; /* array assignment */
711 sigminusset(&p->p_sigmask, &tmp);
712
713 #ifdef CODA_VERBOSE
714 printf("coda_call: tsleep returns %d, cnt %d\n", error, i);
715 printf("coda_call: siglist = %x.%x.%x.%x, sigmask = %x.%x.%x.%x, mask %x.%x.%x.%x\n",
716 p->p_siglist.__bits[0], p->p_siglist.__bits[1],
717 p->p_siglist.__bits[2], p->p_siglist.__bits[3],
718 p->p_sigmask.__bits[0], p->p_sigmask.__bits[1],
719 p->p_sigmask.__bits[2], p->p_sigmask.__bits[3],
720 tmp.__bits[0], tmp.__bits[1], tmp.__bits[2], tmp.__bits[3]);
721 #endif
722 break;
723 #ifdef notyet
724 sigminusset(&p->p_sigmask, &p->p_siglist);
725 printf("coda_call: siglist = %x.%x.%x.%x, sigmask = %x.%x.%x.%x\n",
726 p->p_siglist.__bits[0], p->p_siglist.__bits[1],
727 p->p_siglist.__bits[2], p->p_siglist.__bits[3],
728 p->p_sigmask.__bits[0], p->p_sigmask.__bits[1],
729 p->p_sigmask.__bits[2], p->p_sigmask.__bits[3]);
730 #endif
731 }
732 } while (error && i++ < 128 && VC_OPEN(vcp));
733 p->p_siglist = psig_omask; /* array assignment */
734 #else
735 (void) tsleep(&vmp->vm_sleep, coda_call_sleep, "coda_call", 0);
736 #endif
737 if (VC_OPEN(vcp)) { /* Venus is still alive */
738 /* Op went through, interrupt or not... */
739 if (vmp->vm_flags & VM_WRITE) {
740 error = 0;
741 *outSize = vmp->vm_outSize;
742 }
743
744 else if (!(vmp->vm_flags & VM_READ)) {
745 /* Interrupted before venus read it. */
746 #ifdef CODA_VERBOSE
747 if (1)
748 #else
749 if (codadebug)
750 #endif
751 myprintf(("interrupted before read: op = %d.%d, flags = %x\n",
752 vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
753 REMQUE(vmp->vm_chain);
754 error = EINTR;
755 }
756
757 else {
758 /* (!(vmp->vm_flags & VM_WRITE)) means interrupted after
759 upcall started */
760 /* Interrupted after start of upcall, send venus a signal */
761 struct coda_in_hdr *dog;
762 struct vmsg *svmp;
763
764 #ifdef CODA_VERBOSE
765 if (1)
766 #else
767 if (codadebug)
768 #endif
769 myprintf(("Sending Venus a signal: op = %d.%d, flags = %x\n",
770 vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
771
772 REMQUE(vmp->vm_chain);
773 error = EINTR;
774
775 CODA_ALLOC(svmp, struct vmsg *, sizeof (struct vmsg));
776
777 CODA_ALLOC((svmp->vm_data), char *, sizeof (struct coda_in_hdr));
778 dog = (struct coda_in_hdr *)svmp->vm_data;
779
780 svmp->vm_flags = 0;
781 dog->opcode = svmp->vm_opcode = CODA_SIGNAL;
782 dog->unique = svmp->vm_unique = vmp->vm_unique;
783 svmp->vm_inSize = sizeof (struct coda_in_hdr);
784 /*??? rvb */ svmp->vm_outSize = sizeof (struct coda_in_hdr);
785
786 if (codadebug)
787 myprintf(("coda_call: enqueing signal msg (%d, %d)\n",
788 svmp->vm_opcode, svmp->vm_unique));
789
790 /* insert at head of queue! */
791 INSQUE(svmp->vm_chain, vcp->vc_requests);
792 selwakeup(&(vcp->vc_selproc));
793 }
794 }
795
796 else { /* If venus died (!VC_OPEN(vcp)) */
797 if (codadebug)
798 myprintf(("vcclose woke op %d.%d flags %d\n",
799 vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
800
801 error = ENODEV;
802 }
803
804 CODA_FREE(vmp, sizeof(struct vmsg));
805
806 if (outstanding_upcalls > 0 && (--outstanding_upcalls == 0))
807 wakeup(&outstanding_upcalls);
808
809 if (!error)
810 error = ((struct coda_out_hdr *)buffer)->result;
811 return(error);
812 }
813
814