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