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