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