1 #include "u.h" 2 #include "../port/lib.h" 3 #include "mem.h" 4 #include "dat.h" 5 #include "fns.h" 6 #include "../port/error.h" 7 #include "devtab.h" 8 9 typedef struct Mntrpc Mntrpc; 10 struct Mntrpc 11 { 12 Mntrpc *list; /* Free/pending list */ 13 Fcall request; /* Outgoing file system protocol message */ 14 Fcall reply; /* Incoming reply */ 15 Mnt *m; /* Mount device during rpc */ 16 Rendez r; /* Place to hang out */ 17 char *rpc; /* I/O Data buffer */ 18 char done; /* Rpc completed */ 19 char flushed; /* Flush was sent */ 20 ushort flushtag; /* Tag flush sent on */ 21 char flush[MAXMSG]; /* Somewhere to build flush */ 22 }; 23 24 struct Mnt 25 { 26 int reads; /* counters for debugging */ 27 int writes; 28 int readerrs; 29 int badlen; 30 int goodconv; 31 int noone; 32 33 Ref; /* Count of attached channels */ 34 Chan *c; /* Channel to file service */ 35 Proc *rip; /* Reader in progress */ 36 Mntrpc *queue; /* Queue of pending requests on this channel */ 37 ulong id; /* Multiplexor id for channel check */ 38 Mnt *list; /* Free list */ 39 char mux; /* Set if the device does the multiplexing */ 40 int blocksize; /* read/write block size */ 41 ushort flushtag; /* Tag to send flush on */ 42 ushort flushbase; /* Base tag of flush window for this buffer */ 43 }; 44 45 struct Mntalloc 46 { 47 Lock; 48 Mnt *list; /* Mount devices in used */ 49 Mnt *mntfree; /* Free list */ 50 Mntrpc *rpcfree; 51 int id; 52 int rpctag; 53 }mntalloc; 54 55 #define MAXRPC (MAXFDATA+MAXMSG) 56 #define limit(n, max) (n > max ? max : n) 57 58 Chan* mattach(Mnt*, char*); 59 Mnt* mntchk(Chan*); 60 void mntdirfix(uchar*, Chan*); 61 void mntdoclunk(Mnt *, Mntrpc *); 62 int mntflush(Mnt*, Mntrpc*); 63 void mntfree(Mntrpc*); 64 void mntgate(Mnt*); 65 void mntpntfree(Mnt*); 66 void mntqrm(Mnt*, Mntrpc*); 67 Mntrpc* mntralloc(void); 68 long mntrdwr(int , Chan*, void*,long , ulong); 69 void mntrpcread(Mnt*, Mntrpc*); 70 void mountio(Mnt*, Mntrpc*); 71 void mountmux(Mnt*, Mntrpc*); 72 void mountrpc(Mnt*, Mntrpc*); 73 int rpcattn(Mntrpc*); 74 void mclose(Mnt*); 75 76 static int defblocksize = MAXFDATA; 77 78 enum 79 { 80 Tagspace = 1, 81 Tagfls = 0x8000, 82 Tagend = 0xfffe, 83 84 ALIGN = 256, /* Vme block mode alignment */ 85 }; 86 87 void 88 mntblocksize(int s) 89 { 90 if(s < 256 || s > MAXFDATA) 91 return; 92 defblocksize = s; 93 } 94 95 void 96 mntreset(void) 97 { 98 mntalloc.id = 1; 99 mntalloc.rpctag = Tagspace; 100 } 101 102 void 103 mntinit(void) 104 { 105 } 106 107 Chan* 108 mntattach(char *muxattach) 109 { 110 Mnt *m; 111 Chan *c, *mc; 112 struct bogus{ 113 Chan *chan; 114 char *spec; 115 }bogus; 116 117 bogus = *((struct bogus *)muxattach); 118 c = bogus.chan; 119 120 lock(&mntalloc); 121 for(m = mntalloc.list; m; m = m->list) { 122 if(m->c == c && m->id) { 123 lock(m); 124 if(m->id && m->ref > 0 && m->c == c) { 125 unlock(&mntalloc); 126 m->ref++; 127 unlock(m); 128 return mattach(m, bogus.spec); 129 } 130 unlock(m); 131 } 132 } 133 134 m = mntalloc.mntfree; 135 if(m != 0) 136 mntalloc.mntfree = m->list; 137 else { 138 m = malloc(sizeof(Mnt)); 139 if(m == 0) { 140 unlock(&mntalloc); 141 exhausted("mount devices"); 142 } 143 m->flushbase = Tagfls; 144 m->flushtag = Tagfls; 145 } 146 m->list = mntalloc.list; 147 mntalloc.list = m; 148 m->id = mntalloc.id++; 149 lock(m); 150 unlock(&mntalloc); 151 152 m->ref = 1; 153 m->queue = 0; 154 m->rip = 0; 155 m->c = c; 156 m->c->flag |= CMSG; 157 m->blocksize = defblocksize; 158 159 switch(devchar[m->c->type]) { 160 default: 161 m->mux = 0; 162 break; 163 case 'C': /* Cyclone */ 164 m->mux = 1; 165 break; 166 } 167 incref(m->c); 168 unlock(m); 169 170 if(waserror()) { 171 mclose(m); 172 nexterror(); 173 } 174 175 c = mattach(m, bogus.spec); 176 177 /* 178 * If exportfs mounts on behalf of a local devmnt, the mount 179 * point is folded onto the original channel to preserve a single 180 * fid/tag space. CHDIR is cleared by exportfs to indicate it 181 * is supplying the mount. 182 */ 183 mc = m->c; 184 if(mc->type == devno('M', 0) && (c->qid.path&CHDIR) == 0) { 185 c->qid.path |= CHDIR; 186 c->mntptr = mc->mntptr; 187 c->mchan = mc->mntptr->c; 188 c->mqid = c->qid; 189 incref(c->mntptr); 190 mclose(m); 191 } 192 193 poperror(); 194 return c; 195 } 196 197 Chan * 198 mattach(Mnt *m, char *spec) 199 { 200 Chan *c; 201 Mntrpc *r; 202 ulong id; 203 204 r = mntralloc(); 205 c = devattach('M', spec); 206 lock(&mntalloc); 207 c->dev = mntalloc.id++; 208 unlock(&mntalloc); 209 c->mntptr = m; 210 211 if(waserror()){ 212 mntfree(r); 213 /* Close must not be called since 214 * it will call mnt recursively 215 */ 216 chanfree(c); 217 nexterror(); 218 } 219 220 r->request.type = Tattach; 221 r->request.fid = c->fid; 222 memmove(r->request.uname, u->p->user, NAMELEN); 223 strncpy(r->request.aname, spec, NAMELEN); 224 id = authrequest(m->c->session, &r->request); 225 mountrpc(m, r); 226 authreply(m->c->session, id, &r->reply); 227 228 c->qid = r->reply.qid; 229 c->mchan = m->c; 230 c->mqid = c->qid; 231 poperror(); 232 mntfree(r); 233 return c; 234 } 235 236 Chan* 237 mntclone(Chan *c, Chan *nc) 238 { 239 Mnt *m; 240 Mntrpc *r; 241 int alloc = 0; 242 243 m = mntchk(c); 244 r = mntralloc(); 245 if(nc == 0) { 246 nc = newchan(); 247 alloc = 1; 248 } 249 if(waserror()) { 250 mntfree(r); 251 if(alloc) 252 close(nc); 253 nexterror(); 254 } 255 256 r->request.type = Tclone; 257 r->request.fid = c->fid; 258 r->request.newfid = nc->fid; 259 mountrpc(m, r); 260 261 devclone(c, nc); 262 nc->mqid = c->qid; 263 incref(m); 264 265 USED(alloc); 266 poperror(); 267 mntfree(r); 268 return nc; 269 } 270 271 int 272 mntwalk(Chan *c, char *name) 273 { 274 Mnt *m; 275 Mntrpc *r; 276 277 m = mntchk(c); 278 r = mntralloc(); 279 if(waserror()) { 280 mntfree(r); 281 return 0; 282 } 283 r->request.type = Twalk; 284 r->request.fid = c->fid; 285 strncpy(r->request.name, name, NAMELEN); 286 mountrpc(m, r); 287 288 c->qid = r->reply.qid; 289 290 poperror(); 291 mntfree(r); 292 return 1; 293 } 294 295 void 296 mntstat(Chan *c, char *dp) 297 { 298 Mnt *m; 299 Mntrpc *r; 300 301 m = mntchk(c); 302 r = mntralloc(); 303 if(waserror()) { 304 mntfree(r); 305 nexterror(); 306 } 307 r->request.type = Tstat; 308 r->request.fid = c->fid; 309 mountrpc(m, r); 310 311 memmove(dp, r->reply.stat, DIRLEN); 312 mntdirfix((uchar*)dp, c); 313 poperror(); 314 mntfree(r); 315 } 316 317 Chan* 318 mntopen(Chan *c, int omode) 319 { 320 Mnt *m; 321 Mntrpc *r; 322 323 m = mntchk(c); 324 r = mntralloc(); 325 if(waserror()) { 326 mntfree(r); 327 nexterror(); 328 } 329 r->request.type = Topen; 330 r->request.fid = c->fid; 331 r->request.mode = omode; 332 mountrpc(m, r); 333 334 c->qid = r->reply.qid; 335 c->offset = 0; 336 c->mode = openmode(omode); 337 c->flag |= COPEN; 338 poperror(); 339 mntfree(r); 340 return c; 341 } 342 343 void 344 mntcreate(Chan *c, char *name, int omode, ulong perm) 345 { 346 Mnt *m; 347 Mntrpc *r; 348 349 m = mntchk(c); 350 r = mntralloc(); 351 if(waserror()) { 352 mntfree(r); 353 nexterror(); 354 } 355 r->request.type = Tcreate; 356 r->request.fid = c->fid; 357 r->request.mode = omode; 358 r->request.perm = perm; 359 strncpy(r->request.name, name, NAMELEN); 360 mountrpc(m, r); 361 362 c->qid = r->reply.qid; 363 c->flag |= COPEN; 364 c->mode = openmode(omode); 365 poperror(); 366 mntfree(r); 367 } 368 369 void 370 mntclunk(Chan *c, int t) 371 { 372 Mnt *m; 373 Mntrpc *r; 374 375 m = mntchk(c); 376 r = mntralloc(); 377 if(waserror()){ 378 mntdoclunk(m, r); 379 nexterror(); 380 } 381 382 r->request.type = t; 383 r->request.fid = c->fid; 384 mountrpc(m, r); 385 mntdoclunk(m, r); 386 poperror(); 387 } 388 389 void 390 mclose(Mnt *m) 391 { 392 Mntrpc *q, *r; 393 394 if(decref(m) != 0) 395 return; 396 397 for(q = m->queue; q; q = r) { 398 r = q->list; 399 q->flushed = 0; 400 mntfree(q); 401 } 402 m->id = 0; 403 close(m->c); 404 mntpntfree(m); 405 } 406 407 void 408 mntdoclunk(Mnt *m, Mntrpc *r) 409 { 410 mntfree(r); 411 mclose(m); 412 } 413 414 void 415 mntpntfree(Mnt *m) 416 { 417 Mnt *f, **l; 418 419 lock(&mntalloc); 420 l = &mntalloc.list; 421 for(f = *l; f; f = f->list) { 422 if(f == m) { 423 *l = m->list; 424 break; 425 } 426 l = &f->list; 427 } 428 429 m->list = mntalloc.mntfree; 430 mntalloc.mntfree = m; 431 unlock(&mntalloc); 432 } 433 434 void 435 mntclose(Chan *c) 436 { 437 mntclunk(c, Tclunk); 438 } 439 440 void 441 mntremove(Chan *c) 442 { 443 mntclunk(c, Tremove); 444 } 445 446 void 447 mntwstat(Chan *c, char *dp) 448 { 449 Mnt *m; 450 Mntrpc *r; 451 452 m = mntchk(c); 453 r = mntralloc(); 454 if(waserror()) { 455 mntfree(r); 456 nexterror(); 457 } 458 r->request.type = Twstat; 459 r->request.fid = c->fid; 460 memmove(r->request.stat, dp, DIRLEN); 461 mountrpc(m, r); 462 poperror(); 463 mntfree(r); 464 } 465 466 long 467 mntread(Chan *c, void *buf, long n, ulong offset) 468 { 469 uchar *p, *e; 470 471 n = mntrdwr(Tread, c, buf, n, offset); 472 if(c->qid.path & CHDIR) 473 for(p = (uchar*)buf, e = &p[n]; p < e; p += DIRLEN) 474 mntdirfix(p, c); 475 476 return n; 477 } 478 479 long 480 mntwrite(Chan *c, void *buf, long n, ulong offset) 481 { 482 return mntrdwr(Twrite, c, buf, n, offset); 483 } 484 485 long 486 mntrdwr(int type, Chan *c, void *buf, long n, ulong offset) 487 { 488 Mnt *m; 489 Mntrpc *r; 490 char *uba; 491 ulong cnt, nr; 492 493 m = mntchk(c); 494 uba = buf; 495 cnt = 0; 496 for(;;) { 497 r = mntralloc(); 498 if(waserror()) { 499 mntfree(r); 500 nexterror(); 501 } 502 r->request.type = type; 503 r->request.fid = c->fid; 504 r->request.offset = offset; 505 r->request.data = uba; 506 r->request.count = limit(n, m->blocksize); 507 mountrpc(m, r); 508 nr = r->reply.count; 509 if(nr > r->request.count) 510 nr = r->request.count; 511 if(type == Tread) 512 memmove(uba, r->reply.data, nr); 513 poperror(); 514 mntfree(r); 515 offset += nr; 516 uba += nr; 517 cnt += nr; 518 n -= nr; 519 if(nr != r->request.count || n == 0 || u->nnote) 520 break; 521 } 522 return cnt; 523 } 524 525 void 526 mountrpc(Mnt *m, Mntrpc *r) 527 { 528 r->reply.tag = 0; /* poison the old values */ 529 r->reply.type = 4; 530 531 mountio(m, r); 532 if(r->reply.type == Rerror) 533 error(r->reply.ename); 534 535 if(r->reply.type == Rflush) 536 error(Eintr); 537 538 if(r->reply.type != r->request.type+1) { 539 print("mnt: mismatched reply 0x%lux T%d R%d tags req %d fls %d rep %d\n", 540 r, r->request.type, r->reply.type, r->request.tag, 541 r->flushtag, r->reply.tag); 542 543 error(Emountrpc); 544 } 545 } 546 547 void 548 mountio(Mnt *m, Mntrpc *r) 549 { 550 int n; 551 552 lock(m); 553 r->flushed = 0; 554 r->m = m; 555 r->list = m->queue; 556 m->queue = r; 557 unlock(m); 558 559 /* Transmit a file system rpc */ 560 n = convS2M(&r->request, r->rpc); 561 if(waserror()) { 562 if(mntflush(m, r) == 0) 563 nexterror(); 564 } 565 else { 566 if((*devtab[m->c->type].write)(m->c, r->rpc, n, 0) != n) 567 error(Emountrpc); 568 m->writes++; 569 poperror(); 570 } 571 if(m->mux) { 572 mntqrm(m, r); 573 mntrpcread(m, r); 574 return; 575 } 576 577 /* Gate readers onto the mount point one at a time */ 578 for(;;) { 579 lock(m); 580 if(m->rip == 0) 581 break; 582 unlock(m); 583 if(waserror()) { 584 if(mntflush(m, r) == 0) 585 nexterror(); 586 continue; 587 } 588 sleep(&r->r, rpcattn, r); 589 poperror(); 590 if(r->done) 591 return; 592 } 593 m->rip = u->p; 594 unlock(m); 595 while(r->done == 0) { 596 mntrpcread(m, r); 597 mountmux(m, r); 598 } 599 mntgate(m); 600 } 601 602 void 603 mntrpcread(Mnt *m, Mntrpc *r) 604 { 605 int n; 606 607 for(;;) { 608 if(waserror()) { 609 m->readerrs++; 610 if(mntflush(m, r) == 0) { 611 if(m->mux == 0) 612 mntgate(m); 613 nexterror(); 614 } 615 continue; 616 } 617 r->reply.type = 0; 618 r->reply.tag = 0; 619 n = (*devtab[m->c->type].read)(m->c, r->rpc, MAXRPC, 0); 620 poperror(); 621 m->reads++; 622 if(n == 0){ 623 m->badlen++; 624 continue; 625 } 626 627 if(convM2S(r->rpc, &r->reply, n) != 0){ 628 m->goodconv++; 629 return; 630 } 631 } 632 } 633 634 void 635 mntgate(Mnt *m) 636 { 637 Mntrpc *q; 638 639 lock(m); 640 m->rip = 0; 641 for(q = m->queue; q; q = q->list) 642 if(q->done == 0) { 643 lock(&q->r); 644 if(q->r.p) { 645 unlock(&q->r); 646 unlock(m); 647 wakeup(&q->r); 648 return; 649 } 650 unlock(&q->r); 651 } 652 unlock(m); 653 } 654 655 void 656 mountmux(Mnt *m, Mntrpc *r) 657 { 658 char *dp; 659 Mntrpc **l, *q; 660 661 lock(m); 662 l = &m->queue; 663 for(q = *l; q; q = q->list) { 664 if(q->request.tag == r->reply.tag 665 || q->flushed && q->flushtag == r->reply.tag) { 666 *l = q->list; 667 unlock(m); 668 if(q != r) { /* Completed someone else */ 669 dp = q->rpc; 670 q->rpc = r->rpc; 671 r->rpc = dp; 672 memmove(&q->reply, &r->reply, sizeof(Fcall)); 673 q->done = 1; 674 wakeup(&q->r); 675 }else 676 q->done = 1; 677 return; 678 } 679 l = &q->list; 680 } 681 m->noone++; 682 unlock(m); 683 } 684 685 int 686 mntflush(Mnt *m, Mntrpc *r) 687 { 688 int n; 689 Fcall flush; 690 691 lock(m); 692 r->flushtag = m->flushtag++; 693 if(m->flushtag == Tagend) 694 m->flushtag = m->flushbase; 695 r->flushed = 1; 696 unlock(m); 697 698 flush.type = Tflush; 699 flush.tag = r->flushtag; 700 flush.oldtag = r->request.tag; 701 n = convS2M(&flush, r->flush); 702 703 if(waserror()) { 704 if(strcmp(u->error, Eintr) == 0) 705 return 1; 706 mntqrm(m, r); 707 return 0; 708 } 709 (*devtab[m->c->type].write)(m->c, r->flush, n, 0); 710 poperror(); 711 return 1; 712 } 713 714 Mntrpc * 715 mntralloc(void) 716 { 717 Mntrpc *new; 718 719 lock(&mntalloc); 720 new = mntalloc.rpcfree; 721 if(new != 0) 722 mntalloc.rpcfree = new->list; 723 else { 724 new = xalloc(sizeof(Mntrpc)+MAXRPC); 725 if(new == 0) { 726 unlock(&mntalloc); 727 exhausted("mount rpc buffer"); 728 } 729 new->rpc = (char*)new+sizeof(Mntrpc); 730 new->request.tag = mntalloc.rpctag++; 731 } 732 unlock(&mntalloc); 733 new->done = 0; 734 new->flushed = 0; 735 return new; 736 } 737 738 void 739 mntfree(Mntrpc *r) 740 { 741 lock(&mntalloc); 742 r->list = mntalloc.rpcfree; 743 mntalloc.rpcfree = r; 744 unlock(&mntalloc); 745 } 746 747 void 748 mntqrm(Mnt *m, Mntrpc *r) 749 { 750 Mntrpc **l, *f; 751 752 lock(m); 753 r->done = 1; 754 r->flushed = 0; 755 756 l = &m->queue; 757 for(f = *l; f; f = f->list) { 758 if(f == r) { 759 *l = r->list; 760 break; 761 } 762 l = &f->list; 763 } 764 unlock(m); 765 } 766 767 Mnt * 768 mntchk(Chan *c) 769 { 770 Mnt *m; 771 772 m = c->mntptr; 773 /* Was it closed and reused ? */ 774 if(m->id == 0 || m->id >= c->dev) /* Sanity check */ 775 error(Eshutdown); 776 return m; 777 } 778 779 void 780 mntdirfix(uchar *dirbuf, Chan *c) 781 { 782 dirbuf[DIRLEN-4] = devchar[c->type]>>0; 783 dirbuf[DIRLEN-3] = devchar[c->type]>>8; 784 dirbuf[DIRLEN-2] = c->dev; 785 dirbuf[DIRLEN-1] = c->dev>>8; 786 } 787 788 int 789 rpcattn(Mntrpc *r) 790 { 791 return r->done || r->m->rip == 0; 792 } 793