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