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