1 /* $NetBSD: coda_psdev.c,v 1.22 2002/11/26 18:45:22 christos 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 /* These routines are the device entry points for Venus. */ 53 54 #include <sys/cdefs.h> 55 __KERNEL_RCSID(0, "$NetBSD: coda_psdev.c,v 1.22 2002/11/26 18:45:22 christos Exp $"); 56 57 extern int coda_nc_initialized; /* Set if cache has been initialized */ 58 59 #ifdef _LKM 60 #define NVCODA 4 61 #else 62 #include <vcoda.h> 63 #endif 64 65 #include <sys/param.h> 66 #include <sys/systm.h> 67 #include <sys/kernel.h> 68 #include <sys/malloc.h> 69 #include <sys/proc.h> 70 #include <sys/mount.h> 71 #include <sys/file.h> 72 #include <sys/ioctl.h> 73 #include <sys/poll.h> 74 #include <sys/select.h> 75 #include <sys/conf.h> 76 77 #include <miscfs/syncfs/syncfs.h> 78 79 #include <coda/coda.h> 80 #include <coda/cnode.h> 81 #include <coda/coda_namecache.h> 82 #include <coda/coda_io.h> 83 84 #define CTL_C 85 86 int coda_psdev_print_entry = 0; 87 static 88 int outstanding_upcalls = 0; 89 int coda_call_sleep = PZERO - 1; 90 #ifdef CTL_C 91 int coda_pcatch = PCATCH; 92 #else 93 #endif 94 95 #define ENTRY if(coda_psdev_print_entry) myprintf(("Entered %s\n",__func__)) 96 97 void vcodaattach(int n); 98 99 dev_type_open(vc_nb_open); 100 dev_type_close(vc_nb_close); 101 dev_type_read(vc_nb_read); 102 dev_type_write(vc_nb_write); 103 dev_type_ioctl(vc_nb_ioctl); 104 dev_type_poll(vc_nb_poll); 105 dev_type_kqfilter(vc_nb_kqfilter); 106 107 const struct cdevsw vcoda_cdevsw = { 108 vc_nb_open, vc_nb_close, vc_nb_read, vc_nb_write, vc_nb_ioctl, 109 nostop, notty, vc_nb_poll, nommap, vc_nb_kqfilter, 110 }; 111 112 struct vmsg { 113 struct queue vm_chain; 114 caddr_t vm_data; 115 u_short vm_flags; 116 u_short vm_inSize; /* Size is at most 5000 bytes */ 117 u_short vm_outSize; 118 u_short vm_opcode; /* copied from data to save ptr lookup */ 119 int vm_unique; 120 caddr_t vm_sleep; /* Not used by Mach. */ 121 }; 122 123 #define VM_READ 1 124 #define VM_WRITE 2 125 #define VM_INTR 4 126 127 /* vcodaattach: do nothing */ 128 void 129 vcodaattach(n) 130 int n; 131 { 132 } 133 134 /* 135 * These functions are written for NetBSD. 136 */ 137 int 138 vc_nb_open(dev, flag, mode, p) 139 dev_t dev; 140 int flag; 141 int mode; 142 struct proc *p; /* NetBSD only */ 143 { 144 struct vcomm *vcp; 145 146 ENTRY; 147 148 if (minor(dev) >= NVCODA || minor(dev) < 0) 149 return(ENXIO); 150 151 if (!coda_nc_initialized) 152 coda_nc_init(); 153 154 vcp = &coda_mnttbl[minor(dev)].mi_vcomm; 155 if (VC_OPEN(vcp)) 156 return(EBUSY); 157 158 memset(&(vcp->vc_selproc), 0, sizeof (struct selinfo)); 159 INIT_QUEUE(vcp->vc_requests); 160 INIT_QUEUE(vcp->vc_replys); 161 MARK_VC_OPEN(vcp); 162 163 coda_mnttbl[minor(dev)].mi_vfsp = NULL; 164 coda_mnttbl[minor(dev)].mi_rootvp = NULL; 165 166 return(0); 167 } 168 169 int 170 vc_nb_close (dev, flag, mode, p) 171 dev_t dev; 172 int flag; 173 int mode; 174 struct proc *p; 175 { 176 struct vcomm *vcp; 177 struct vmsg *vmp, *nvmp = NULL; 178 struct coda_mntinfo *mi; 179 int err; 180 181 ENTRY; 182 183 if (minor(dev) >= NVCODA || minor(dev) < 0) 184 return(ENXIO); 185 186 mi = &coda_mnttbl[minor(dev)]; 187 vcp = &(mi->mi_vcomm); 188 189 if (!VC_OPEN(vcp)) 190 panic("vcclose: not open"); 191 192 /* prevent future operations on this vfs from succeeding by auto- 193 * unmounting any vfs mounted via this device. This frees user or 194 * sysadm from having to remember where all mount points are located. 195 * Put this before WAKEUPs to avoid queuing new messages between 196 * the WAKEUP and the unmount (which can happen if we're unlucky) 197 */ 198 if (!mi->mi_rootvp) { 199 /* just a simple open/close w no mount */ 200 MARK_VC_CLOSED(vcp); 201 return 0; 202 } 203 204 /* Let unmount know this is for real */ 205 /* 206 * XXX Freeze syncer. Must do this before locking the 207 * mount point. See dounmount for details(). 208 */ 209 lockmgr(&syncer_lock, LK_EXCLUSIVE, NULL); 210 VTOC(mi->mi_rootvp)->c_flags |= C_UNMOUNTING; 211 if (vfs_busy(mi->mi_vfsp, 0, 0)) { 212 lockmgr(&syncer_lock, LK_RELEASE, NULL); 213 return (EBUSY); 214 } 215 coda_unmounting(mi->mi_vfsp); 216 217 /* Wakeup clients so they can return. */ 218 for (vmp = (struct vmsg *)GETNEXT(vcp->vc_requests); 219 !EOQ(vmp, vcp->vc_requests); 220 vmp = nvmp) 221 { 222 nvmp = (struct vmsg *)GETNEXT(vmp->vm_chain); 223 /* Free signal request messages and don't wakeup cause 224 no one is waiting. */ 225 if (vmp->vm_opcode == CODA_SIGNAL) { 226 CODA_FREE((caddr_t)vmp->vm_data, (u_int)VC_IN_NO_DATA); 227 CODA_FREE((caddr_t)vmp, (u_int)sizeof(struct vmsg)); 228 continue; 229 } 230 outstanding_upcalls++; 231 wakeup(&vmp->vm_sleep); 232 } 233 234 for (vmp = (struct vmsg *)GETNEXT(vcp->vc_replys); 235 !EOQ(vmp, vcp->vc_replys); 236 vmp = (struct vmsg *)GETNEXT(vmp->vm_chain)) 237 { 238 outstanding_upcalls++; 239 wakeup(&vmp->vm_sleep); 240 } 241 242 MARK_VC_CLOSED(vcp); 243 244 if (outstanding_upcalls) { 245 #ifdef CODA_VERBOSE 246 printf("presleep: outstanding_upcalls = %d\n", outstanding_upcalls); 247 (void) tsleep(&outstanding_upcalls, coda_call_sleep, "coda_umount", 0); 248 printf("postsleep: outstanding_upcalls = %d\n", outstanding_upcalls); 249 #else 250 (void) tsleep(&outstanding_upcalls, coda_call_sleep, "coda_umount", 0); 251 #endif 252 } 253 254 err = dounmount(mi->mi_vfsp, flag, p); 255 if (err) 256 myprintf(("Error %d unmounting vfs in vcclose(%d)\n", 257 err, minor(dev))); 258 return 0; 259 } 260 261 int 262 vc_nb_read(dev, uiop, flag) 263 dev_t dev; 264 struct uio *uiop; 265 int flag; 266 { 267 struct vcomm * vcp; 268 struct vmsg *vmp; 269 int error = 0; 270 271 ENTRY; 272 273 if (minor(dev) >= NVCODA || minor(dev) < 0) 274 return(ENXIO); 275 276 vcp = &coda_mnttbl[minor(dev)].mi_vcomm; 277 /* Get message at head of request queue. */ 278 if (EMPTY(vcp->vc_requests)) 279 return(0); /* Nothing to read */ 280 281 vmp = (struct vmsg *)GETNEXT(vcp->vc_requests); 282 283 /* Move the input args into userspace */ 284 uiop->uio_rw = UIO_READ; 285 error = uiomove(vmp->vm_data, vmp->vm_inSize, uiop); 286 if (error) { 287 myprintf(("vcread: error (%d) on uiomove\n", error)); 288 error = EINVAL; 289 } 290 291 #ifdef OLD_DIAGNOSTIC 292 if (vmp->vm_chain.forw == 0 || vmp->vm_chain.back == 0) 293 panic("vc_nb_read: bad chain"); 294 #endif 295 296 REMQUE(vmp->vm_chain); 297 298 /* If request was a signal, free up the message and don't 299 enqueue it in the reply queue. */ 300 if (vmp->vm_opcode == CODA_SIGNAL) { 301 if (codadebug) 302 myprintf(("vcread: signal msg (%d, %d)\n", 303 vmp->vm_opcode, vmp->vm_unique)); 304 CODA_FREE((caddr_t)vmp->vm_data, (u_int)VC_IN_NO_DATA); 305 CODA_FREE((caddr_t)vmp, (u_int)sizeof(struct vmsg)); 306 return(error); 307 } 308 309 vmp->vm_flags |= VM_READ; 310 INSQUE(vmp->vm_chain, vcp->vc_replys); 311 312 return(error); 313 } 314 315 int 316 vc_nb_write(dev, uiop, flag) 317 dev_t dev; 318 struct uio *uiop; 319 int flag; 320 { 321 struct vcomm * vcp; 322 struct vmsg *vmp; 323 struct coda_out_hdr *out; 324 u_long seq; 325 u_long opcode; 326 int buf[2]; 327 int error = 0; 328 329 ENTRY; 330 331 if (minor(dev) >= NVCODA || minor(dev) < 0) 332 return(ENXIO); 333 334 vcp = &coda_mnttbl[minor(dev)].mi_vcomm; 335 336 /* Peek at the opcode, unique without transfering the data. */ 337 uiop->uio_rw = UIO_WRITE; 338 error = uiomove((caddr_t)buf, sizeof(int) * 2, uiop); 339 if (error) { 340 myprintf(("vcwrite: error (%d) on uiomove\n", error)); 341 return(EINVAL); 342 } 343 344 opcode = buf[0]; 345 seq = buf[1]; 346 347 if (codadebug) 348 myprintf(("vcwrite got a call for %ld.%ld\n", opcode, seq)); 349 350 if (DOWNCALL(opcode)) { 351 union outputArgs pbuf; 352 353 /* get the rest of the data. */ 354 uiop->uio_rw = UIO_WRITE; 355 error = uiomove((caddr_t)&pbuf.coda_purgeuser.oh.result, sizeof(pbuf) - (sizeof(int)*2), uiop); 356 if (error) { 357 myprintf(("vcwrite: error (%d) on uiomove (Op %ld seq %ld)\n", 358 error, opcode, seq)); 359 return(EINVAL); 360 } 361 362 return handleDownCall(opcode, &pbuf); 363 } 364 365 /* Look for the message on the (waiting for) reply queue. */ 366 for (vmp = (struct vmsg *)GETNEXT(vcp->vc_replys); 367 !EOQ(vmp, vcp->vc_replys); 368 vmp = (struct vmsg *)GETNEXT(vmp->vm_chain)) 369 { 370 if (vmp->vm_unique == seq) break; 371 } 372 373 if (EOQ(vmp, vcp->vc_replys)) { 374 if (codadebug) 375 myprintf(("vcwrite: msg (%ld, %ld) not found\n", opcode, seq)); 376 377 return(ESRCH); 378 } 379 380 /* Remove the message from the reply queue */ 381 REMQUE(vmp->vm_chain); 382 383 /* move data into response buffer. */ 384 out = (struct coda_out_hdr *)vmp->vm_data; 385 /* Don't need to copy opcode and uniquifier. */ 386 387 /* get the rest of the data. */ 388 if (vmp->vm_outSize < uiop->uio_resid) { 389 myprintf(("vcwrite: more data than asked for (%d < %lu)\n", 390 vmp->vm_outSize, (unsigned long) uiop->uio_resid)); 391 wakeup(&vmp->vm_sleep); /* Notify caller of the error. */ 392 return(EINVAL); 393 } 394 395 buf[0] = uiop->uio_resid; /* Save this value. */ 396 uiop->uio_rw = UIO_WRITE; 397 error = uiomove((caddr_t) &out->result, vmp->vm_outSize - (sizeof(int) * 2), uiop); 398 if (error) { 399 myprintf(("vcwrite: error (%d) on uiomove (op %ld seq %ld)\n", 400 error, opcode, seq)); 401 return(EINVAL); 402 } 403 404 /* I don't think these are used, but just in case. */ 405 /* XXX - aren't these two already correct? -bnoble */ 406 out->opcode = opcode; 407 out->unique = seq; 408 vmp->vm_outSize = buf[0]; /* Amount of data transferred? */ 409 vmp->vm_flags |= VM_WRITE; 410 wakeup(&vmp->vm_sleep); 411 412 return(0); 413 } 414 415 int 416 vc_nb_ioctl(dev, cmd, addr, flag, p) 417 dev_t dev; 418 u_long cmd; 419 caddr_t addr; 420 int flag; 421 struct proc *p; 422 { 423 ENTRY; 424 425 switch(cmd) { 426 case CODARESIZE: { 427 struct coda_resize *data = (struct coda_resize *)addr; 428 return(coda_nc_resize(data->hashsize, data->heapsize, IS_DOWNCALL)); 429 break; 430 } 431 case CODASTATS: 432 if (coda_nc_use) { 433 coda_nc_gather_stats(); 434 return(0); 435 } else { 436 return(ENODEV); 437 } 438 break; 439 case CODAPRINT: 440 if (coda_nc_use) { 441 print_coda_nc(); 442 return(0); 443 } else { 444 return(ENODEV); 445 } 446 break; 447 case CIOC_KERNEL_VERSION: 448 switch (*(u_int *)addr) { 449 case 0: 450 *(u_int *)addr = coda_kernel_version; 451 return 0; 452 break; 453 case 1: 454 case 2: 455 if (coda_kernel_version != *(u_int *)addr) 456 return ENOENT; 457 else 458 return 0; 459 default: 460 return ENOENT; 461 } 462 break; 463 default : 464 return(EINVAL); 465 break; 466 } 467 } 468 469 int 470 vc_nb_poll(dev, events, p) 471 dev_t dev; 472 int events; 473 struct proc *p; 474 { 475 struct vcomm *vcp; 476 int event_msk = 0; 477 478 ENTRY; 479 480 if (minor(dev) >= NVCODA || minor(dev) < 0) 481 return(ENXIO); 482 483 vcp = &coda_mnttbl[minor(dev)].mi_vcomm; 484 485 event_msk = events & (POLLIN|POLLRDNORM); 486 if (!event_msk) 487 return(0); 488 489 if (!EMPTY(vcp->vc_requests)) 490 return(events & (POLLIN|POLLRDNORM)); 491 492 selrecord(p, &(vcp->vc_selproc)); 493 494 return(0); 495 } 496 497 static void 498 filt_vc_nb_detach(struct knote *kn) 499 { 500 struct vcomm *vcp = kn->kn_hook; 501 502 SLIST_REMOVE(&vcp->vc_selproc.sel_klist, kn, knote, kn_selnext); 503 } 504 505 static int 506 filt_vc_nb_read(struct knote *kn, long hint) 507 { 508 struct vcomm *vcp = kn->kn_hook; 509 struct vmsg *vmp; 510 511 if (EMPTY(vcp->vc_requests)) 512 return (0); 513 514 vmp = (struct vmsg *)GETNEXT(vcp->vc_requests); 515 516 kn->kn_data = vmp->vm_inSize; 517 return (1); 518 } 519 520 static const struct filterops vc_nb_read_filtops = 521 { 1, NULL, filt_vc_nb_detach, filt_vc_nb_read }; 522 523 int 524 vc_nb_kqfilter(dev_t dev, struct knote *kn) 525 { 526 struct vcomm *vcp; 527 struct klist *klist; 528 529 ENTRY; 530 531 if (minor(dev) >= NVCODA || minor(dev) < 0) 532 return(ENXIO); 533 534 vcp = &coda_mnttbl[minor(dev)].mi_vcomm; 535 536 switch (kn->kn_filter) { 537 case EVFILT_READ: 538 klist = &vcp->vc_selproc.sel_klist; 539 kn->kn_fop = &vc_nb_read_filtops; 540 break; 541 542 default: 543 return (1); 544 } 545 546 kn->kn_hook = vcp; 547 548 SLIST_INSERT_HEAD(klist, kn, kn_selnext); 549 550 return (0); 551 } 552 553 /* 554 * Statistics 555 */ 556 struct coda_clstat coda_clstat; 557 558 /* 559 * Key question: whether to sleep interuptably or uninteruptably when 560 * waiting for Venus. The former seems better (cause you can ^C a 561 * job), but then GNU-EMACS completion breaks. Use tsleep with no 562 * timeout, and no longjmp happens. But, when sleeping 563 * "uninterruptibly", we don't get told if it returns abnormally 564 * (e.g. kill -9). 565 */ 566 567 int 568 coda_call(mntinfo, inSize, outSize, buffer) 569 struct coda_mntinfo *mntinfo; int inSize; int *outSize; caddr_t buffer; 570 { 571 struct vcomm *vcp; 572 struct vmsg *vmp; 573 int error; 574 #ifdef CTL_C 575 struct proc *p = curproc; 576 sigset_t psig_omask; 577 int i; 578 psig_omask = p->p_sigctx.ps_siglist; /* array assignment */ 579 #endif 580 if (mntinfo == NULL) { 581 /* Unlikely, but could be a race condition with a dying warden */ 582 return ENODEV; 583 } 584 585 vcp = &(mntinfo->mi_vcomm); 586 587 coda_clstat.ncalls++; 588 coda_clstat.reqs[((struct coda_in_hdr *)buffer)->opcode]++; 589 590 if (!VC_OPEN(vcp)) 591 return(ENODEV); 592 593 CODA_ALLOC(vmp,struct vmsg *,sizeof(struct vmsg)); 594 /* Format the request message. */ 595 vmp->vm_data = buffer; 596 vmp->vm_flags = 0; 597 vmp->vm_inSize = inSize; 598 vmp->vm_outSize 599 = *outSize ? *outSize : inSize; /* |buffer| >= inSize */ 600 vmp->vm_opcode = ((struct coda_in_hdr *)buffer)->opcode; 601 vmp->vm_unique = ++vcp->vc_seq; 602 if (codadebug) 603 myprintf(("Doing a call for %d.%d\n", 604 vmp->vm_opcode, vmp->vm_unique)); 605 606 /* Fill in the common input args. */ 607 ((struct coda_in_hdr *)buffer)->unique = vmp->vm_unique; 608 609 /* Append msg to request queue and poke Venus. */ 610 INSQUE(vmp->vm_chain, vcp->vc_requests); 611 selnotify(&(vcp->vc_selproc), 0); 612 613 /* We can be interrupted while we wait for Venus to process 614 * our request. If the interrupt occurs before Venus has read 615 * the request, we dequeue and return. If it occurs after the 616 * read but before the reply, we dequeue, send a signal 617 * message, and return. If it occurs after the reply we ignore 618 * it. In no case do we want to restart the syscall. If it 619 * was interrupted by a venus shutdown (vcclose), return 620 * ENODEV. */ 621 622 /* Ignore return, We have to check anyway */ 623 #ifdef CTL_C 624 /* This is work in progress. Setting coda_pcatch lets tsleep reawaken 625 on a ^c or ^z. The problem is that emacs sets certain interrupts 626 as SA_RESTART. This means that we should exit sleep handle the 627 "signal" and then go to sleep again. Mostly this is done by letting 628 the syscall complete and be restarted. We are not idempotent and 629 can not do this. A better solution is necessary. 630 */ 631 i = 0; 632 do { 633 error = tsleep(&vmp->vm_sleep, (coda_call_sleep|coda_pcatch), "coda_call", hz*2); 634 if (error == 0) 635 break; 636 else if (error == EWOULDBLOCK) { 637 #ifdef CODA_VERBOSE 638 printf("coda_call: tsleep TIMEOUT %d sec\n", 2+2*i); 639 #endif 640 } else if (sigismember(&p->p_sigctx.ps_siglist, SIGIO)) { 641 sigaddset(&p->p_sigctx.ps_sigmask, SIGIO); 642 #ifdef CODA_VERBOSE 643 printf("coda_call: tsleep returns %d SIGIO, cnt %d\n", error, i); 644 #endif 645 } else if (sigismember(&p->p_sigctx.ps_siglist, SIGALRM)) { 646 sigaddset(&p->p_sigctx.ps_sigmask, SIGALRM); 647 #ifdef CODA_VERBOSE 648 printf("coda_call: tsleep returns %d SIGALRM, cnt %d\n", error, i); 649 #endif 650 } else { 651 sigset_t tmp; 652 tmp = p->p_sigctx.ps_siglist; /* array assignment */ 653 sigminusset(&p->p_sigctx.ps_sigmask, &tmp); 654 655 #ifdef CODA_VERBOSE 656 printf("coda_call: tsleep returns %d, cnt %d\n", error, i); 657 printf("coda_call: siglist = %x.%x.%x.%x, sigmask = %x.%x.%x.%x, mask %x.%x.%x.%x\n", 658 p->p_sigctx.ps_siglist.__bits[0], p->p_sigctx.ps_siglist.__bits[1], 659 p->p_sigctx.ps_siglist.__bits[2], p->p_sigctx.ps_siglist.__bits[3], 660 p->p_sigctx.ps_sigmask.__bits[0], p->p_sigctx.ps_sigmask.__bits[1], 661 p->p_sigctx.ps_sigmask.__bits[2], p->p_sigctx.ps_sigmask.__bits[3], 662 tmp.__bits[0], tmp.__bits[1], tmp.__bits[2], tmp.__bits[3]); 663 #endif 664 break; 665 #ifdef notyet 666 sigminusset(&p->p_sigctx.ps_sigmask, &p->p_sigctx.ps_siglist); 667 printf("coda_call: siglist = %x.%x.%x.%x, sigmask = %x.%x.%x.%x\n", 668 p->p_sigctx.ps_siglist.__bits[0], p->p_sigctx.ps_siglist.__bits[1], 669 p->p_sigctx.ps_siglist.__bits[2], p->p_sigctx.ps_siglist.__bits[3], 670 p->p_sigctx.ps_sigmask.__bits[0], p->p_sigctx.ps_sigmask.__bits[1], 671 p->p_sigctx.ps_sigmask.__bits[2], p->p_sigctx.ps_sigmask.__bits[3]); 672 #endif 673 } 674 } while (error && i++ < 128 && VC_OPEN(vcp)); 675 p->p_sigctx.ps_siglist = psig_omask; /* array assignment */ 676 #else 677 (void) tsleep(&vmp->vm_sleep, coda_call_sleep, "coda_call", 0); 678 #endif 679 if (VC_OPEN(vcp)) { /* Venus is still alive */ 680 /* Op went through, interrupt or not... */ 681 if (vmp->vm_flags & VM_WRITE) { 682 error = 0; 683 *outSize = vmp->vm_outSize; 684 } 685 686 else if (!(vmp->vm_flags & VM_READ)) { 687 /* Interrupted before venus read it. */ 688 #ifdef CODA_VERBOSE 689 if (1) 690 #else 691 if (codadebug) 692 #endif 693 myprintf(("interrupted before read: op = %d.%d, flags = %x\n", 694 vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags)); 695 REMQUE(vmp->vm_chain); 696 error = EINTR; 697 } 698 699 else { 700 /* (!(vmp->vm_flags & VM_WRITE)) means interrupted after 701 upcall started */ 702 /* Interrupted after start of upcall, send venus a signal */ 703 struct coda_in_hdr *dog; 704 struct vmsg *svmp; 705 706 #ifdef CODA_VERBOSE 707 if (1) 708 #else 709 if (codadebug) 710 #endif 711 myprintf(("Sending Venus a signal: op = %d.%d, flags = %x\n", 712 vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags)); 713 714 REMQUE(vmp->vm_chain); 715 error = EINTR; 716 717 CODA_ALLOC(svmp, struct vmsg *, sizeof (struct vmsg)); 718 719 CODA_ALLOC((svmp->vm_data), char *, sizeof (struct coda_in_hdr)); 720 dog = (struct coda_in_hdr *)svmp->vm_data; 721 722 svmp->vm_flags = 0; 723 dog->opcode = svmp->vm_opcode = CODA_SIGNAL; 724 dog->unique = svmp->vm_unique = vmp->vm_unique; 725 svmp->vm_inSize = sizeof (struct coda_in_hdr); 726 /*??? rvb */ svmp->vm_outSize = sizeof (struct coda_in_hdr); 727 728 if (codadebug) 729 myprintf(("coda_call: enqueing signal msg (%d, %d)\n", 730 svmp->vm_opcode, svmp->vm_unique)); 731 732 /* insert at head of queue! */ 733 INSQUE(svmp->vm_chain, vcp->vc_requests); 734 selnotify(&(vcp->vc_selproc), 0); 735 } 736 } 737 738 else { /* If venus died (!VC_OPEN(vcp)) */ 739 if (codadebug) 740 myprintf(("vcclose woke op %d.%d flags %d\n", 741 vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags)); 742 743 error = ENODEV; 744 } 745 746 CODA_FREE(vmp, sizeof(struct vmsg)); 747 748 if (outstanding_upcalls > 0 && (--outstanding_upcalls == 0)) 749 wakeup(&outstanding_upcalls); 750 751 if (!error) 752 error = ((struct coda_out_hdr *)buffer)->result; 753 return(error); 754 } 755 756