58 59#include <sys/param.h> 60#include <sys/systm.h> 61#include <sys/ioccom.h> 62#include <sys/kernel.h> 63#include <sys/lock.h> 64#include <sys/malloc.h> 65#include <sys/file.h> /* must come after sys/malloc.h */ 66#include <sys/mount.h> 67#include <sys/mutex.h> 68#include <sys/poll.h> 69#include <sys/proc.h> 70 71#include <coda/coda.h> 72#include <coda/cnode.h> 73#include <coda/coda_namecache.h> 74#include <coda/coda_io.h> 75#include <coda/coda_psdev.h> 76 77#define CTL_C 78 79#ifdef CTL_C 80#include <sys/signalvar.h> 81#endif 82 83int coda_psdev_print_entry = 0; 84static 85int outstanding_upcalls = 0; 86int coda_call_sleep = PZERO - 1; 87#ifdef CTL_C 88int coda_pcatch = PCATCH; 89#else 90#endif 91 92#define ENTRY if(coda_psdev_print_entry) myprintf(("Entered %s\n",__func__)) 93 94void vcodaattach(int n); 95 96struct vmsg { 97 struct queue vm_chain; 98 caddr_t vm_data; 99 u_short vm_flags; 100 u_short vm_inSize; /* Size is at most 5000 bytes */ 101 u_short vm_outSize; 102 u_short vm_opcode; /* copied from data to save ptr lookup */ 103 int vm_unique; 104 caddr_t vm_sleep; /* Not used by Mach. */ 105}; 106 107#define VM_READ 1 108#define VM_WRITE 2 109#define VM_INTR 4 110 111/* vcodaattach: do nothing */ 112void 113vcodaattach(n) 114 int n; 115{ 116} 117 118int 119vc_nb_open(dev, flag, mode, td) 120 struct cdev *dev; 121 int flag; 122 int mode; 123 struct thread *td; /* NetBSD only */ 124{ 125 register struct vcomm *vcp; 126 127 ENTRY; 128 129 if (minor(dev) >= NVCODA || minor(dev) < 0) 130 return(ENXIO); 131 132 if (!coda_nc_initialized) 133 coda_nc_init(); 134 135 vcp = &coda_mnttbl[minor(dev)].mi_vcomm; 136 if (VC_OPEN(vcp)) 137 return(EBUSY); 138 139 bzero(&(vcp->vc_selproc), sizeof (struct selinfo)); 140 INIT_QUEUE(vcp->vc_requests); 141 INIT_QUEUE(vcp->vc_replys); 142 MARK_VC_OPEN(vcp); 143 144 coda_mnttbl[minor(dev)].mi_vfsp = NULL; 145 coda_mnttbl[minor(dev)].mi_rootvp = NULL; 146 147 return(0); 148} 149 150int 151vc_nb_close (dev, flag, mode, td) 152 struct cdev *dev; 153 int flag; 154 int mode; 155 struct thread *td; 156{ 157 register struct vcomm *vcp; 158 register struct vmsg *vmp, *nvmp = NULL; 159 struct coda_mntinfo *mi; 160 int err; 161 162 ENTRY; 163 164 if (minor(dev) >= NVCODA || minor(dev) < 0) 165 return(ENXIO); 166 167 mi = &coda_mnttbl[minor(dev)]; 168 vcp = &(mi->mi_vcomm); 169 170 if (!VC_OPEN(vcp)) 171 panic("vcclose: not open"); 172 173 /* prevent future operations on this vfs from succeeding by auto- 174 * unmounting any vfs mounted via this device. This frees user or 175 * sysadm from having to remember where all mount points are located. 176 * Put this before WAKEUPs to avoid queuing new messages between 177 * the WAKEUP and the unmount (which can happen if we're unlucky) 178 */ 179 if (!mi->mi_rootvp) { 180 /* just a simple open/close w no mount */ 181 MARK_VC_CLOSED(vcp); 182 return 0; 183 } 184 185 /* Let unmount know this is for real */ 186 VTOC(mi->mi_rootvp)->c_flags |= C_UNMOUNTING; 187 coda_unmounting(mi->mi_vfsp); 188 189 outstanding_upcalls = 0; 190 /* Wakeup clients so they can return. */ 191 for (vmp = (struct vmsg *)GETNEXT(vcp->vc_requests); 192 !EOQ(vmp, vcp->vc_requests); 193 vmp = nvmp) 194 { 195 nvmp = (struct vmsg *)GETNEXT(vmp->vm_chain); 196 /* Free signal request messages and don't wakeup cause 197 no one is waiting. */ 198 if (vmp->vm_opcode == CODA_SIGNAL) { 199 CODA_FREE((caddr_t)vmp->vm_data, (u_int)VC_IN_NO_DATA); 200 CODA_FREE((caddr_t)vmp, (u_int)sizeof(struct vmsg)); 201 continue; 202 } 203 outstanding_upcalls++; 204 wakeup(&vmp->vm_sleep); 205 } 206 207 for (vmp = (struct vmsg *)GETNEXT(vcp->vc_replys); 208 !EOQ(vmp, vcp->vc_replys); 209 vmp = (struct vmsg *)GETNEXT(vmp->vm_chain)) 210 { 211 outstanding_upcalls++; 212 wakeup(&vmp->vm_sleep); 213 } 214 215 MARK_VC_CLOSED(vcp); 216 217 if (outstanding_upcalls) { 218#ifdef CODA_VERBOSE 219 printf("presleep: outstanding_upcalls = %d\n", outstanding_upcalls); 220 (void) tsleep(&outstanding_upcalls, coda_call_sleep, "coda_umount", 0); 221 printf("postsleep: outstanding_upcalls = %d\n", outstanding_upcalls); 222#else 223 (void) tsleep(&outstanding_upcalls, coda_call_sleep, "coda_umount", 0); 224#endif 225 } 226 227 err = dounmount(mi->mi_vfsp, flag, td); 228 if (err) 229 myprintf(("Error %d unmounting vfs in vcclose(%d)\n", 230 err, minor(dev))); 231 return 0; 232} 233 234int 235vc_nb_read(dev, uiop, flag) 236 struct cdev *dev; 237 struct uio *uiop; 238 int flag; 239{ 240 register struct vcomm * vcp; 241 register struct vmsg *vmp; 242 int error = 0; 243 244 ENTRY; 245 246 if (minor(dev) >= NVCODA || minor(dev) < 0) 247 return(ENXIO); 248 249 vcp = &coda_mnttbl[minor(dev)].mi_vcomm; 250 /* Get message at head of request queue. */ 251 if (EMPTY(vcp->vc_requests)) 252 return(0); /* Nothing to read */ 253 254 vmp = (struct vmsg *)GETNEXT(vcp->vc_requests); 255 256 /* Move the input args into userspace */ 257 uiop->uio_rw = UIO_READ; 258 error = uiomove(vmp->vm_data, vmp->vm_inSize, uiop); 259 if (error) { 260 myprintf(("vcread: error (%d) on uiomove\n", error)); 261 error = EINVAL; 262 } 263 264#ifdef OLD_DIAGNOSTIC 265 if (vmp->vm_chain.forw == 0 || vmp->vm_chain.back == 0) 266 panic("vc_nb_read: bad chain"); 267#endif 268 269 REMQUE(vmp->vm_chain); 270 271 /* If request was a signal, free up the message and don't 272 enqueue it in the reply queue. */ 273 if (vmp->vm_opcode == CODA_SIGNAL) { 274 if (codadebug) 275 myprintf(("vcread: signal msg (%d, %d)\n", 276 vmp->vm_opcode, vmp->vm_unique)); 277 CODA_FREE((caddr_t)vmp->vm_data, (u_int)VC_IN_NO_DATA); 278 CODA_FREE((caddr_t)vmp, (u_int)sizeof(struct vmsg)); 279 return(error); 280 } 281 282 vmp->vm_flags |= VM_READ; 283 INSQUE(vmp->vm_chain, vcp->vc_replys); 284 285 return(error); 286} 287 288int 289vc_nb_write(dev, uiop, flag) 290 struct cdev *dev; 291 struct uio *uiop; 292 int flag; 293{ 294 register struct vcomm * vcp; 295 register struct vmsg *vmp; 296 struct coda_out_hdr *out; 297 u_long seq; 298 u_long opcode; 299 int buf[2]; 300 int error = 0; 301 302 ENTRY; 303 304 if (minor(dev) >= NVCODA || minor(dev) < 0) 305 return(ENXIO); 306 307 vcp = &coda_mnttbl[minor(dev)].mi_vcomm; 308 309 /* Peek at the opcode, unique without transfering the data. */ 310 uiop->uio_rw = UIO_WRITE; 311 error = uiomove((caddr_t)buf, sizeof(int) * 2, uiop); 312 if (error) { 313 myprintf(("vcwrite: error (%d) on uiomove\n", error)); 314 return(EINVAL); 315 } 316 317 opcode = buf[0]; 318 seq = buf[1]; 319 320 if (codadebug) 321 myprintf(("vcwrite got a call for %ld.%ld\n", opcode, seq)); 322 323 if (DOWNCALL(opcode)) { 324 union outputArgs pbuf; 325 326 /* get the rest of the data. */ 327 uiop->uio_rw = UIO_WRITE; 328 error = uiomove((caddr_t)&pbuf.coda_purgeuser.oh.result, sizeof(pbuf) - (sizeof(int)*2), uiop); 329 if (error) { 330 myprintf(("vcwrite: error (%d) on uiomove (Op %ld seq %ld)\n", 331 error, opcode, seq)); 332 return(EINVAL); 333 } 334 335 return handleDownCall(opcode, &pbuf); 336 } 337 338 /* Look for the message on the (waiting for) reply queue. */ 339 for (vmp = (struct vmsg *)GETNEXT(vcp->vc_replys); 340 !EOQ(vmp, vcp->vc_replys); 341 vmp = (struct vmsg *)GETNEXT(vmp->vm_chain)) 342 { 343 if (vmp->vm_unique == seq) break; 344 } 345 346 if (EOQ(vmp, vcp->vc_replys)) { 347 if (codadebug) 348 myprintf(("vcwrite: msg (%ld, %ld) not found\n", opcode, seq)); 349 350 return(ESRCH); 351 } 352 353 /* Remove the message from the reply queue */ 354 REMQUE(vmp->vm_chain); 355 356 /* move data into response buffer. */ 357 out = (struct coda_out_hdr *)vmp->vm_data; 358 /* Don't need to copy opcode and uniquifier. */ 359 360 /* get the rest of the data. */ 361 if (vmp->vm_outSize < uiop->uio_resid) { 362 myprintf(("vcwrite: more data than asked for (%d < %d)\n", 363 vmp->vm_outSize, uiop->uio_resid)); 364 wakeup(&vmp->vm_sleep); /* Notify caller of the error. */ 365 return(EINVAL); 366 } 367 368 buf[0] = uiop->uio_resid; /* Save this value. */ 369 uiop->uio_rw = UIO_WRITE; 370 error = uiomove((caddr_t) &out->result, vmp->vm_outSize - (sizeof(int) * 2), uiop); 371 if (error) { 372 myprintf(("vcwrite: error (%d) on uiomove (op %ld seq %ld)\n", 373 error, opcode, seq)); 374 return(EINVAL); 375 } 376 377 /* I don't think these are used, but just in case. */ 378 /* XXX - aren't these two already correct? -bnoble */ 379 out->opcode = opcode; 380 out->unique = seq; 381 vmp->vm_outSize = buf[0]; /* Amount of data transferred? */ 382 vmp->vm_flags |= VM_WRITE; 383 wakeup(&vmp->vm_sleep); 384 385 return(0); 386} 387 388int 389vc_nb_ioctl(dev, cmd, addr, flag, td) 390 struct cdev *dev; 391 u_long cmd; 392 caddr_t addr; 393 int flag; 394 struct thread *td; 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 442int 443vc_nb_poll(dev, events, td) 444 struct cdev *dev; 445 int events; 446 struct thread *td; 447{ 448 register struct vcomm *vcp; 449 int event_msk = 0; 450 451 ENTRY; 452 453 if (minor(dev) >= NVCODA || minor(dev) < 0) 454 return(ENXIO); 455 456 vcp = &coda_mnttbl[minor(dev)].mi_vcomm; 457 458 event_msk = events & (POLLIN|POLLRDNORM); 459 if (!event_msk) 460 return(0); 461 462 if (!EMPTY(vcp->vc_requests)) 463 return(events & (POLLIN|POLLRDNORM)); 464 465 selrecord(td, &(vcp->vc_selproc)); 466 467 return(0); 468} 469 470/* 471 * Statistics 472 */ 473struct coda_clstat coda_clstat; 474 475/* 476 * Key question: whether to sleep interuptably or uninteruptably when 477 * waiting for Venus. The former seems better (cause you can ^C a 478 * job), but then GNU-EMACS completion breaks. Use tsleep with no 479 * timeout, and no longjmp happens. But, when sleeping 480 * "uninterruptibly", we don't get told if it returns abnormally 481 * (e.g. kill -9). 482 */ 483 484int 485coda_call(mntinfo, inSize, outSize, buffer) 486 struct coda_mntinfo *mntinfo; int inSize; int *outSize; caddr_t buffer; 487{ 488 struct vcomm *vcp; 489 struct vmsg *vmp; 490 int error; 491#ifdef CTL_C 492 struct thread *td = curthread; 493 struct proc *p = td->td_proc; 494 sigset_t psig_omask; 495 sigset_t tempset; 496 int i; 497#endif 498 if (mntinfo == NULL) { 499 /* Unlikely, but could be a race condition with a dying warden */ 500 return ENODEV; 501 } 502 503 vcp = &(mntinfo->mi_vcomm); 504 505 coda_clstat.ncalls++; 506 coda_clstat.reqs[((struct coda_in_hdr *)buffer)->opcode]++; 507 508 if (!VC_OPEN(vcp)) 509 return(ENODEV); 510 511 CODA_ALLOC(vmp,struct vmsg *,sizeof(struct vmsg)); 512 /* Format the request message. */ 513 vmp->vm_data = buffer; 514 vmp->vm_flags = 0; 515 vmp->vm_inSize = inSize; 516 vmp->vm_outSize 517 = *outSize ? *outSize : inSize; /* |buffer| >= inSize */ 518 vmp->vm_opcode = ((struct coda_in_hdr *)buffer)->opcode; 519 vmp->vm_unique = ++vcp->vc_seq; 520 if (codadebug) 521 myprintf(("Doing a call for %d.%d\n", 522 vmp->vm_opcode, vmp->vm_unique)); 523 524 /* Fill in the common input args. */ 525 ((struct coda_in_hdr *)buffer)->unique = vmp->vm_unique; 526 527 /* Append msg to request queue and poke Venus. */ 528 INSQUE(vmp->vm_chain, vcp->vc_requests); 529 selwakeuppri(&(vcp->vc_selproc), coda_call_sleep); 530 531 /* We can be interrupted while we wait for Venus to process 532 * our request. If the interrupt occurs before Venus has read 533 * the request, we dequeue and return. If it occurs after the 534 * read but before the reply, we dequeue, send a signal 535 * message, and return. If it occurs after the reply we ignore 536 * it. In no case do we want to restart the syscall. If it 537 * was interrupted by a venus shutdown (vcclose), return 538 * ENODEV. */ 539 540 /* Ignore return, We have to check anyway */ 541#ifdef CTL_C 542 /* This is work in progress. Setting coda_pcatch lets tsleep reawaken 543 on a ^c or ^z. The problem is that emacs sets certain interrupts 544 as SA_RESTART. This means that we should exit sleep handle the 545 "signal" and then go to sleep again. Mostly this is done by letting 546 the syscall complete and be restarted. We are not idempotent and 547 can not do this. A better solution is necessary. 548 */ 549 i = 0; 550 PROC_LOCK(p); 551 psig_omask = td->td_sigmask; 552 do { 553 error = msleep(&vmp->vm_sleep, &p->p_mtx, 554 (coda_call_sleep|coda_pcatch), "coda_call", 555 hz*2); 556 if (error == 0) 557 break; 558 else if (error == EWOULDBLOCK) { 559#ifdef CODA_VERBOSE 560 printf("coda_call: tsleep TIMEOUT %d sec\n", 2+2*i); 561#endif 562 } 563 else { 564 SIGEMPTYSET(tempset); 565 SIGADDSET(tempset, SIGIO); 566 if (SIGSETEQ(td->td_siglist, tempset)) { 567 SIGADDSET(td->td_sigmask, SIGIO); 568#ifdef CODA_VERBOSE 569 printf("coda_call: tsleep returns %d SIGIO, cnt %d\n", 570 error, i); 571#endif 572 } else { 573 SIGDELSET(tempset, SIGIO); 574 SIGADDSET(tempset, SIGALRM); 575 if (SIGSETEQ(td->td_siglist, tempset)) { 576 SIGADDSET(td->td_sigmask, SIGALRM); 577#ifdef CODA_VERBOSE 578 printf("coda_call: tsleep returns %d SIGALRM, cnt %d\n", 579 error, i); 580#endif 581 } 582 else { 583#ifdef CODA_VERBOSE 584 printf("coda_call: tsleep returns %d, cnt %d\n", 585 error, i); 586#endif 587 588#if notyet 589 tempset = td->td_siglist; 590 SIGSETNAND(tempset, td->td_sigmask); 591 printf("coda_call: siglist = %p, sigmask = %p, mask %p\n", 592 td->td_siglist, td->td_sigmask, 593 tempset); 594 break; 595 SIGSETOR(td->td_sigmask, td->td_siglist); 596 tempset = td->td_siglist; 597 SIGSETNAND(tempset, td->td_sigmask); 598 printf("coda_call: new mask, siglist = %p, sigmask = %p, mask %p\n", 599 td->td_siglist, td->td_sigmask, 600 tempset); 601#endif 602 } 603 } 604 } 605 } while (error && i++ < 128 && VC_OPEN(vcp)); 606 td->td_sigmask = psig_omask; 607 signotify(td); 608 PROC_UNLOCK(p); 609#else 610 (void) tsleep(&vmp->vm_sleep, coda_call_sleep, "coda_call", 0); 611#endif 612 if (VC_OPEN(vcp)) { /* Venus is still alive */ 613 /* Op went through, interrupt or not... */ 614 if (vmp->vm_flags & VM_WRITE) { 615 error = 0; 616 *outSize = vmp->vm_outSize; 617 } 618 619 else if (!(vmp->vm_flags & VM_READ)) { 620 /* Interrupted before venus read it. */ 621#ifdef CODA_VERBOSE 622 if (1) 623#else 624 if (codadebug) 625#endif 626 myprintf(("interrupted before read: op = %d.%d, flags = %x\n", 627 vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags)); 628 REMQUE(vmp->vm_chain); 629 error = EINTR; 630 } 631 632 else { 633 /* (!(vmp->vm_flags & VM_WRITE)) means interrupted after 634 upcall started */ 635 /* Interrupted after start of upcall, send venus a signal */ 636 struct coda_in_hdr *dog; 637 struct vmsg *svmp; 638 639#ifdef CODA_VERBOSE 640 if (1) 641#else 642 if (codadebug) 643#endif 644 myprintf(("Sending Venus a signal: op = %d.%d, flags = %x\n", 645 vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags)); 646 647 REMQUE(vmp->vm_chain); 648 error = EINTR; 649 650 CODA_ALLOC(svmp, struct vmsg *, sizeof (struct vmsg)); 651 652 CODA_ALLOC((svmp->vm_data), char *, sizeof (struct coda_in_hdr)); 653 dog = (struct coda_in_hdr *)svmp->vm_data; 654 655 svmp->vm_flags = 0; 656 dog->opcode = svmp->vm_opcode = CODA_SIGNAL; 657 dog->unique = svmp->vm_unique = vmp->vm_unique; 658 svmp->vm_inSize = sizeof (struct coda_in_hdr); 659/*??? rvb */ svmp->vm_outSize = sizeof (struct coda_in_hdr); 660 661 if (codadebug) 662 myprintf(("coda_call: enqueing signal msg (%d, %d)\n", 663 svmp->vm_opcode, svmp->vm_unique)); 664 665 /* insert at head of queue! */ 666 INSQUE(svmp->vm_chain, vcp->vc_requests); 667 selwakeuppri(&(vcp->vc_selproc), coda_call_sleep); 668 } 669 } 670 671 else { /* If venus died (!VC_OPEN(vcp)) */ 672 if (codadebug) 673 myprintf(("vcclose woke op %d.%d flags %d\n", 674 vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags)); 675 676 error = ENODEV; 677 } 678 679 CODA_FREE(vmp, sizeof(struct vmsg)); 680 681 if (outstanding_upcalls > 0 && (--outstanding_upcalls == 0)) 682 wakeup(&outstanding_upcalls); 683 684 if (!error) 685 error = ((struct coda_out_hdr *)buffer)->result; 686 return(error); 687}
| 58 59#include <sys/param.h> 60#include <sys/systm.h> 61#include <sys/ioccom.h> 62#include <sys/kernel.h> 63#include <sys/lock.h> 64#include <sys/malloc.h> 65#include <sys/file.h> /* must come after sys/malloc.h */ 66#include <sys/mount.h> 67#include <sys/mutex.h> 68#include <sys/poll.h> 69#include <sys/proc.h> 70 71#include <coda/coda.h> 72#include <coda/cnode.h> 73#include <coda/coda_namecache.h> 74#include <coda/coda_io.h> 75#include <coda/coda_psdev.h> 76 77#define CTL_C 78 79#ifdef CTL_C 80#include <sys/signalvar.h> 81#endif 82 83int coda_psdev_print_entry = 0; 84static 85int outstanding_upcalls = 0; 86int coda_call_sleep = PZERO - 1; 87#ifdef CTL_C 88int coda_pcatch = PCATCH; 89#else 90#endif 91 92#define ENTRY if(coda_psdev_print_entry) myprintf(("Entered %s\n",__func__)) 93 94void vcodaattach(int n); 95 96struct vmsg { 97 struct queue vm_chain; 98 caddr_t vm_data; 99 u_short vm_flags; 100 u_short vm_inSize; /* Size is at most 5000 bytes */ 101 u_short vm_outSize; 102 u_short vm_opcode; /* copied from data to save ptr lookup */ 103 int vm_unique; 104 caddr_t vm_sleep; /* Not used by Mach. */ 105}; 106 107#define VM_READ 1 108#define VM_WRITE 2 109#define VM_INTR 4 110 111/* vcodaattach: do nothing */ 112void 113vcodaattach(n) 114 int n; 115{ 116} 117 118int 119vc_nb_open(dev, flag, mode, td) 120 struct cdev *dev; 121 int flag; 122 int mode; 123 struct thread *td; /* NetBSD only */ 124{ 125 register struct vcomm *vcp; 126 127 ENTRY; 128 129 if (minor(dev) >= NVCODA || minor(dev) < 0) 130 return(ENXIO); 131 132 if (!coda_nc_initialized) 133 coda_nc_init(); 134 135 vcp = &coda_mnttbl[minor(dev)].mi_vcomm; 136 if (VC_OPEN(vcp)) 137 return(EBUSY); 138 139 bzero(&(vcp->vc_selproc), sizeof (struct selinfo)); 140 INIT_QUEUE(vcp->vc_requests); 141 INIT_QUEUE(vcp->vc_replys); 142 MARK_VC_OPEN(vcp); 143 144 coda_mnttbl[minor(dev)].mi_vfsp = NULL; 145 coda_mnttbl[minor(dev)].mi_rootvp = NULL; 146 147 return(0); 148} 149 150int 151vc_nb_close (dev, flag, mode, td) 152 struct cdev *dev; 153 int flag; 154 int mode; 155 struct thread *td; 156{ 157 register struct vcomm *vcp; 158 register struct vmsg *vmp, *nvmp = NULL; 159 struct coda_mntinfo *mi; 160 int err; 161 162 ENTRY; 163 164 if (minor(dev) >= NVCODA || minor(dev) < 0) 165 return(ENXIO); 166 167 mi = &coda_mnttbl[minor(dev)]; 168 vcp = &(mi->mi_vcomm); 169 170 if (!VC_OPEN(vcp)) 171 panic("vcclose: not open"); 172 173 /* prevent future operations on this vfs from succeeding by auto- 174 * unmounting any vfs mounted via this device. This frees user or 175 * sysadm from having to remember where all mount points are located. 176 * Put this before WAKEUPs to avoid queuing new messages between 177 * the WAKEUP and the unmount (which can happen if we're unlucky) 178 */ 179 if (!mi->mi_rootvp) { 180 /* just a simple open/close w no mount */ 181 MARK_VC_CLOSED(vcp); 182 return 0; 183 } 184 185 /* Let unmount know this is for real */ 186 VTOC(mi->mi_rootvp)->c_flags |= C_UNMOUNTING; 187 coda_unmounting(mi->mi_vfsp); 188 189 outstanding_upcalls = 0; 190 /* Wakeup clients so they can return. */ 191 for (vmp = (struct vmsg *)GETNEXT(vcp->vc_requests); 192 !EOQ(vmp, vcp->vc_requests); 193 vmp = nvmp) 194 { 195 nvmp = (struct vmsg *)GETNEXT(vmp->vm_chain); 196 /* Free signal request messages and don't wakeup cause 197 no one is waiting. */ 198 if (vmp->vm_opcode == CODA_SIGNAL) { 199 CODA_FREE((caddr_t)vmp->vm_data, (u_int)VC_IN_NO_DATA); 200 CODA_FREE((caddr_t)vmp, (u_int)sizeof(struct vmsg)); 201 continue; 202 } 203 outstanding_upcalls++; 204 wakeup(&vmp->vm_sleep); 205 } 206 207 for (vmp = (struct vmsg *)GETNEXT(vcp->vc_replys); 208 !EOQ(vmp, vcp->vc_replys); 209 vmp = (struct vmsg *)GETNEXT(vmp->vm_chain)) 210 { 211 outstanding_upcalls++; 212 wakeup(&vmp->vm_sleep); 213 } 214 215 MARK_VC_CLOSED(vcp); 216 217 if (outstanding_upcalls) { 218#ifdef CODA_VERBOSE 219 printf("presleep: outstanding_upcalls = %d\n", outstanding_upcalls); 220 (void) tsleep(&outstanding_upcalls, coda_call_sleep, "coda_umount", 0); 221 printf("postsleep: outstanding_upcalls = %d\n", outstanding_upcalls); 222#else 223 (void) tsleep(&outstanding_upcalls, coda_call_sleep, "coda_umount", 0); 224#endif 225 } 226 227 err = dounmount(mi->mi_vfsp, flag, td); 228 if (err) 229 myprintf(("Error %d unmounting vfs in vcclose(%d)\n", 230 err, minor(dev))); 231 return 0; 232} 233 234int 235vc_nb_read(dev, uiop, flag) 236 struct cdev *dev; 237 struct uio *uiop; 238 int flag; 239{ 240 register struct vcomm * vcp; 241 register struct vmsg *vmp; 242 int error = 0; 243 244 ENTRY; 245 246 if (minor(dev) >= NVCODA || minor(dev) < 0) 247 return(ENXIO); 248 249 vcp = &coda_mnttbl[minor(dev)].mi_vcomm; 250 /* Get message at head of request queue. */ 251 if (EMPTY(vcp->vc_requests)) 252 return(0); /* Nothing to read */ 253 254 vmp = (struct vmsg *)GETNEXT(vcp->vc_requests); 255 256 /* Move the input args into userspace */ 257 uiop->uio_rw = UIO_READ; 258 error = uiomove(vmp->vm_data, vmp->vm_inSize, uiop); 259 if (error) { 260 myprintf(("vcread: error (%d) on uiomove\n", error)); 261 error = EINVAL; 262 } 263 264#ifdef OLD_DIAGNOSTIC 265 if (vmp->vm_chain.forw == 0 || vmp->vm_chain.back == 0) 266 panic("vc_nb_read: bad chain"); 267#endif 268 269 REMQUE(vmp->vm_chain); 270 271 /* If request was a signal, free up the message and don't 272 enqueue it in the reply queue. */ 273 if (vmp->vm_opcode == CODA_SIGNAL) { 274 if (codadebug) 275 myprintf(("vcread: signal msg (%d, %d)\n", 276 vmp->vm_opcode, vmp->vm_unique)); 277 CODA_FREE((caddr_t)vmp->vm_data, (u_int)VC_IN_NO_DATA); 278 CODA_FREE((caddr_t)vmp, (u_int)sizeof(struct vmsg)); 279 return(error); 280 } 281 282 vmp->vm_flags |= VM_READ; 283 INSQUE(vmp->vm_chain, vcp->vc_replys); 284 285 return(error); 286} 287 288int 289vc_nb_write(dev, uiop, flag) 290 struct cdev *dev; 291 struct uio *uiop; 292 int flag; 293{ 294 register struct vcomm * vcp; 295 register struct vmsg *vmp; 296 struct coda_out_hdr *out; 297 u_long seq; 298 u_long opcode; 299 int buf[2]; 300 int error = 0; 301 302 ENTRY; 303 304 if (minor(dev) >= NVCODA || minor(dev) < 0) 305 return(ENXIO); 306 307 vcp = &coda_mnttbl[minor(dev)].mi_vcomm; 308 309 /* Peek at the opcode, unique without transfering the data. */ 310 uiop->uio_rw = UIO_WRITE; 311 error = uiomove((caddr_t)buf, sizeof(int) * 2, uiop); 312 if (error) { 313 myprintf(("vcwrite: error (%d) on uiomove\n", error)); 314 return(EINVAL); 315 } 316 317 opcode = buf[0]; 318 seq = buf[1]; 319 320 if (codadebug) 321 myprintf(("vcwrite got a call for %ld.%ld\n", opcode, seq)); 322 323 if (DOWNCALL(opcode)) { 324 union outputArgs pbuf; 325 326 /* get the rest of the data. */ 327 uiop->uio_rw = UIO_WRITE; 328 error = uiomove((caddr_t)&pbuf.coda_purgeuser.oh.result, sizeof(pbuf) - (sizeof(int)*2), uiop); 329 if (error) { 330 myprintf(("vcwrite: error (%d) on uiomove (Op %ld seq %ld)\n", 331 error, opcode, seq)); 332 return(EINVAL); 333 } 334 335 return handleDownCall(opcode, &pbuf); 336 } 337 338 /* Look for the message on the (waiting for) reply queue. */ 339 for (vmp = (struct vmsg *)GETNEXT(vcp->vc_replys); 340 !EOQ(vmp, vcp->vc_replys); 341 vmp = (struct vmsg *)GETNEXT(vmp->vm_chain)) 342 { 343 if (vmp->vm_unique == seq) break; 344 } 345 346 if (EOQ(vmp, vcp->vc_replys)) { 347 if (codadebug) 348 myprintf(("vcwrite: msg (%ld, %ld) not found\n", opcode, seq)); 349 350 return(ESRCH); 351 } 352 353 /* Remove the message from the reply queue */ 354 REMQUE(vmp->vm_chain); 355 356 /* move data into response buffer. */ 357 out = (struct coda_out_hdr *)vmp->vm_data; 358 /* Don't need to copy opcode and uniquifier. */ 359 360 /* get the rest of the data. */ 361 if (vmp->vm_outSize < uiop->uio_resid) { 362 myprintf(("vcwrite: more data than asked for (%d < %d)\n", 363 vmp->vm_outSize, uiop->uio_resid)); 364 wakeup(&vmp->vm_sleep); /* Notify caller of the error. */ 365 return(EINVAL); 366 } 367 368 buf[0] = uiop->uio_resid; /* Save this value. */ 369 uiop->uio_rw = UIO_WRITE; 370 error = uiomove((caddr_t) &out->result, vmp->vm_outSize - (sizeof(int) * 2), uiop); 371 if (error) { 372 myprintf(("vcwrite: error (%d) on uiomove (op %ld seq %ld)\n", 373 error, opcode, seq)); 374 return(EINVAL); 375 } 376 377 /* I don't think these are used, but just in case. */ 378 /* XXX - aren't these two already correct? -bnoble */ 379 out->opcode = opcode; 380 out->unique = seq; 381 vmp->vm_outSize = buf[0]; /* Amount of data transferred? */ 382 vmp->vm_flags |= VM_WRITE; 383 wakeup(&vmp->vm_sleep); 384 385 return(0); 386} 387 388int 389vc_nb_ioctl(dev, cmd, addr, flag, td) 390 struct cdev *dev; 391 u_long cmd; 392 caddr_t addr; 393 int flag; 394 struct thread *td; 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 442int 443vc_nb_poll(dev, events, td) 444 struct cdev *dev; 445 int events; 446 struct thread *td; 447{ 448 register struct vcomm *vcp; 449 int event_msk = 0; 450 451 ENTRY; 452 453 if (minor(dev) >= NVCODA || minor(dev) < 0) 454 return(ENXIO); 455 456 vcp = &coda_mnttbl[minor(dev)].mi_vcomm; 457 458 event_msk = events & (POLLIN|POLLRDNORM); 459 if (!event_msk) 460 return(0); 461 462 if (!EMPTY(vcp->vc_requests)) 463 return(events & (POLLIN|POLLRDNORM)); 464 465 selrecord(td, &(vcp->vc_selproc)); 466 467 return(0); 468} 469 470/* 471 * Statistics 472 */ 473struct coda_clstat coda_clstat; 474 475/* 476 * Key question: whether to sleep interuptably or uninteruptably when 477 * waiting for Venus. The former seems better (cause you can ^C a 478 * job), but then GNU-EMACS completion breaks. Use tsleep with no 479 * timeout, and no longjmp happens. But, when sleeping 480 * "uninterruptibly", we don't get told if it returns abnormally 481 * (e.g. kill -9). 482 */ 483 484int 485coda_call(mntinfo, inSize, outSize, buffer) 486 struct coda_mntinfo *mntinfo; int inSize; int *outSize; caddr_t buffer; 487{ 488 struct vcomm *vcp; 489 struct vmsg *vmp; 490 int error; 491#ifdef CTL_C 492 struct thread *td = curthread; 493 struct proc *p = td->td_proc; 494 sigset_t psig_omask; 495 sigset_t tempset; 496 int i; 497#endif 498 if (mntinfo == NULL) { 499 /* Unlikely, but could be a race condition with a dying warden */ 500 return ENODEV; 501 } 502 503 vcp = &(mntinfo->mi_vcomm); 504 505 coda_clstat.ncalls++; 506 coda_clstat.reqs[((struct coda_in_hdr *)buffer)->opcode]++; 507 508 if (!VC_OPEN(vcp)) 509 return(ENODEV); 510 511 CODA_ALLOC(vmp,struct vmsg *,sizeof(struct vmsg)); 512 /* Format the request message. */ 513 vmp->vm_data = buffer; 514 vmp->vm_flags = 0; 515 vmp->vm_inSize = inSize; 516 vmp->vm_outSize 517 = *outSize ? *outSize : inSize; /* |buffer| >= inSize */ 518 vmp->vm_opcode = ((struct coda_in_hdr *)buffer)->opcode; 519 vmp->vm_unique = ++vcp->vc_seq; 520 if (codadebug) 521 myprintf(("Doing a call for %d.%d\n", 522 vmp->vm_opcode, vmp->vm_unique)); 523 524 /* Fill in the common input args. */ 525 ((struct coda_in_hdr *)buffer)->unique = vmp->vm_unique; 526 527 /* Append msg to request queue and poke Venus. */ 528 INSQUE(vmp->vm_chain, vcp->vc_requests); 529 selwakeuppri(&(vcp->vc_selproc), coda_call_sleep); 530 531 /* We can be interrupted while we wait for Venus to process 532 * our request. If the interrupt occurs before Venus has read 533 * the request, we dequeue and return. If it occurs after the 534 * read but before the reply, we dequeue, send a signal 535 * message, and return. If it occurs after the reply we ignore 536 * it. In no case do we want to restart the syscall. If it 537 * was interrupted by a venus shutdown (vcclose), return 538 * ENODEV. */ 539 540 /* Ignore return, We have to check anyway */ 541#ifdef CTL_C 542 /* This is work in progress. Setting coda_pcatch lets tsleep reawaken 543 on a ^c or ^z. The problem is that emacs sets certain interrupts 544 as SA_RESTART. This means that we should exit sleep handle the 545 "signal" and then go to sleep again. Mostly this is done by letting 546 the syscall complete and be restarted. We are not idempotent and 547 can not do this. A better solution is necessary. 548 */ 549 i = 0; 550 PROC_LOCK(p); 551 psig_omask = td->td_sigmask; 552 do { 553 error = msleep(&vmp->vm_sleep, &p->p_mtx, 554 (coda_call_sleep|coda_pcatch), "coda_call", 555 hz*2); 556 if (error == 0) 557 break; 558 else if (error == EWOULDBLOCK) { 559#ifdef CODA_VERBOSE 560 printf("coda_call: tsleep TIMEOUT %d sec\n", 2+2*i); 561#endif 562 } 563 else { 564 SIGEMPTYSET(tempset); 565 SIGADDSET(tempset, SIGIO); 566 if (SIGSETEQ(td->td_siglist, tempset)) { 567 SIGADDSET(td->td_sigmask, SIGIO); 568#ifdef CODA_VERBOSE 569 printf("coda_call: tsleep returns %d SIGIO, cnt %d\n", 570 error, i); 571#endif 572 } else { 573 SIGDELSET(tempset, SIGIO); 574 SIGADDSET(tempset, SIGALRM); 575 if (SIGSETEQ(td->td_siglist, tempset)) { 576 SIGADDSET(td->td_sigmask, SIGALRM); 577#ifdef CODA_VERBOSE 578 printf("coda_call: tsleep returns %d SIGALRM, cnt %d\n", 579 error, i); 580#endif 581 } 582 else { 583#ifdef CODA_VERBOSE 584 printf("coda_call: tsleep returns %d, cnt %d\n", 585 error, i); 586#endif 587 588#if notyet 589 tempset = td->td_siglist; 590 SIGSETNAND(tempset, td->td_sigmask); 591 printf("coda_call: siglist = %p, sigmask = %p, mask %p\n", 592 td->td_siglist, td->td_sigmask, 593 tempset); 594 break; 595 SIGSETOR(td->td_sigmask, td->td_siglist); 596 tempset = td->td_siglist; 597 SIGSETNAND(tempset, td->td_sigmask); 598 printf("coda_call: new mask, siglist = %p, sigmask = %p, mask %p\n", 599 td->td_siglist, td->td_sigmask, 600 tempset); 601#endif 602 } 603 } 604 } 605 } while (error && i++ < 128 && VC_OPEN(vcp)); 606 td->td_sigmask = psig_omask; 607 signotify(td); 608 PROC_UNLOCK(p); 609#else 610 (void) tsleep(&vmp->vm_sleep, coda_call_sleep, "coda_call", 0); 611#endif 612 if (VC_OPEN(vcp)) { /* Venus is still alive */ 613 /* Op went through, interrupt or not... */ 614 if (vmp->vm_flags & VM_WRITE) { 615 error = 0; 616 *outSize = vmp->vm_outSize; 617 } 618 619 else if (!(vmp->vm_flags & VM_READ)) { 620 /* Interrupted before venus read it. */ 621#ifdef CODA_VERBOSE 622 if (1) 623#else 624 if (codadebug) 625#endif 626 myprintf(("interrupted before read: op = %d.%d, flags = %x\n", 627 vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags)); 628 REMQUE(vmp->vm_chain); 629 error = EINTR; 630 } 631 632 else { 633 /* (!(vmp->vm_flags & VM_WRITE)) means interrupted after 634 upcall started */ 635 /* Interrupted after start of upcall, send venus a signal */ 636 struct coda_in_hdr *dog; 637 struct vmsg *svmp; 638 639#ifdef CODA_VERBOSE 640 if (1) 641#else 642 if (codadebug) 643#endif 644 myprintf(("Sending Venus a signal: op = %d.%d, flags = %x\n", 645 vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags)); 646 647 REMQUE(vmp->vm_chain); 648 error = EINTR; 649 650 CODA_ALLOC(svmp, struct vmsg *, sizeof (struct vmsg)); 651 652 CODA_ALLOC((svmp->vm_data), char *, sizeof (struct coda_in_hdr)); 653 dog = (struct coda_in_hdr *)svmp->vm_data; 654 655 svmp->vm_flags = 0; 656 dog->opcode = svmp->vm_opcode = CODA_SIGNAL; 657 dog->unique = svmp->vm_unique = vmp->vm_unique; 658 svmp->vm_inSize = sizeof (struct coda_in_hdr); 659/*??? rvb */ svmp->vm_outSize = sizeof (struct coda_in_hdr); 660 661 if (codadebug) 662 myprintf(("coda_call: enqueing signal msg (%d, %d)\n", 663 svmp->vm_opcode, svmp->vm_unique)); 664 665 /* insert at head of queue! */ 666 INSQUE(svmp->vm_chain, vcp->vc_requests); 667 selwakeuppri(&(vcp->vc_selproc), coda_call_sleep); 668 } 669 } 670 671 else { /* If venus died (!VC_OPEN(vcp)) */ 672 if (codadebug) 673 myprintf(("vcclose woke op %d.%d flags %d\n", 674 vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags)); 675 676 error = ENODEV; 677 } 678 679 CODA_FREE(vmp, sizeof(struct vmsg)); 680 681 if (outstanding_upcalls > 0 && (--outstanding_upcalls == 0)) 682 wakeup(&outstanding_upcalls); 683 684 if (!error) 685 error = ((struct coda_out_hdr *)buffer)->result; 686 return(error); 687}
|