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