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