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