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