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