1 #include "dat.h" 2 #include "fns.h" 3 #include "error.h" 4 5 /* 6 * References are managed as follows: 7 * The channel to the server - a network connection or pipe - has one 8 * reference for every Chan open on the server. The server channel has 9 * c->mux set to the Mnt used for muxing control to that server. Mnts 10 * have no reference count; they go away when c goes away. 11 * Each channel derived from the mount point has mchan set to c, 12 * and increfs/decrefs mchan to manage references on the server 13 * connection. 14 */ 15 16 #define MAXRPC (IOHDRSZ+8192) 17 18 struct Mntrpc 19 { 20 Chan* c; /* Channel for whom we are working */ 21 Mntrpc* list; /* Free/pending list */ 22 Fcall request; /* Outgoing file system protocol message */ 23 Fcall reply; /* Incoming reply */ 24 Mnt* m; /* Mount device during rpc */ 25 Rendez r; /* Place to hang out */ 26 uchar* rpc; /* I/O Data buffer */ 27 uint rpclen; /* len of buffer */ 28 Block *b; /* reply blocks */ 29 char done; /* Rpc completed */ 30 uvlong stime; /* start time for mnt statistics */ 31 ulong reqlen; /* request length for mnt statistics */ 32 ulong replen; /* reply length for mnt statistics */ 33 Mntrpc* flushed; /* message this one flushes */ 34 }; 35 36 enum 37 { 38 TAGSHIFT = 5, /* ulong has to be 32 bits */ 39 TAGMASK = (1<<TAGSHIFT)-1, 40 NMASK = (64*1024)>>TAGSHIFT, 41 }; 42 43 struct Mntalloc 44 { 45 Lock l; 46 Mnt* list; /* Mount devices in use */ 47 Mnt* mntfree; /* Free list */ 48 Mntrpc* rpcfree; 49 int nrpcfree; 50 int nrpcused; 51 ulong id; 52 ulong tagmask[NMASK]; 53 }mntalloc; 54 55 void mattach(Mnt*, Chan*, char*); 56 Mnt* mntchk(Chan*); 57 void mntdirfix(uchar*, Chan*); 58 Mntrpc* mntflushalloc(Mntrpc*, ulong); 59 void mntflushfree(Mnt*, Mntrpc*); 60 void mntfree(Mntrpc*); 61 void mntgate(Mnt*); 62 void mntpntfree(Mnt*); 63 void mntqrm(Mnt*, Mntrpc*); 64 Mntrpc* mntralloc(Chan*, ulong); 65 long mntrdwr(int, Chan*, void*, long, vlong); 66 int mntrpcread(Mnt*, Mntrpc*); 67 void mountio(Mnt*, Mntrpc*); 68 void mountmux(Mnt*, Mntrpc*); 69 void mountrpc(Mnt*, Mntrpc*); 70 int rpcattn(void*); 71 Chan* mntchan(void); 72 73 char Esbadstat[] = "invalid directory entry received from server"; 74 char Enoversion[] = "version not established for mount channel"; 75 76 77 void (*mntstats)(int, Chan*, uvlong, ulong); 78 79 static void 80 mntinit(void) 81 { 82 mntalloc.id = 1; 83 mntalloc.tagmask[0] = 1; /* don't allow 0 as a tag */ 84 mntalloc.tagmask[NMASK-1] = 0x80000000UL; /* don't allow NOTAG */ 85 fmtinstall('F', fcallfmt); 86 /* fmtinstall('D', dirfmt); */ 87 /* fmtinstall('M', dirmodefmt); */ 88 89 cinit(); 90 } 91 92 /* 93 * Version is not multiplexed: message sent only once per connection. 94 */ 95 long 96 mntversion(Chan *c, char *version, int msize, int returnlen) 97 { 98 Fcall f; 99 uchar *msg; 100 Mnt *m; 101 char *v; 102 long k, l; 103 uvlong oo; 104 char buf[128]; 105 106 qlock(&c->umqlock); /* make sure no one else does this until we've established ourselves */ 107 if(waserror()){ 108 qunlock(&c->umqlock); 109 nexterror(); 110 } 111 112 /* defaults */ 113 if(msize == 0) 114 msize = MAXRPC; 115 if(msize > c->iounit && c->iounit != 0) 116 msize = c->iounit; 117 v = version; 118 if(v == nil || v[0] == '\0') 119 v = VERSION9P; 120 121 /* validity */ 122 if(msize < 0) 123 error("bad iounit in version call"); 124 if(strncmp(v, VERSION9P, strlen(VERSION9P)) != 0) 125 error("bad 9P version specification"); 126 127 m = c->mux; 128 129 if(m != nil){ 130 qunlock(&c->umqlock); 131 poperror(); 132 133 strecpy(buf, buf+sizeof buf, m->version); 134 k = strlen(buf); 135 if(strncmp(buf, v, k) != 0){ 136 snprint(buf, sizeof buf, "incompatible 9P versions %s %s", m->version, v); 137 error(buf); 138 } 139 if(returnlen > 0){ 140 if(returnlen < k) 141 error(Eshort); 142 memmove(version, buf, k); 143 } 144 return k; 145 } 146 147 f.type = Tversion; 148 f.tag = NOTAG; 149 f.msize = msize; 150 f.version = v; 151 msg = malloc(8192+IOHDRSZ); 152 if(msg == nil) 153 exhausted("version memory"); 154 if(waserror()){ 155 free(msg); 156 nexterror(); 157 } 158 k = convS2M(&f, msg, 8192+IOHDRSZ); 159 if(k == 0) 160 error("bad fversion conversion on send"); 161 162 lock(&c->l); 163 oo = c->offset; 164 c->offset += k; 165 unlock(&c->l); 166 167 l = devtab[c->type]->write(c, msg, k, oo); 168 169 if(l < k){ 170 lock(&c->l); 171 c->offset -= k - l; 172 unlock(&c->l); 173 error("short write in fversion"); 174 } 175 176 /* message sent; receive and decode reply */ 177 k = devtab[c->type]->read(c, msg, 8192+IOHDRSZ, c->offset); 178 if(k <= 0) 179 error("EOF receiving fversion reply"); 180 181 lock(&c->l); 182 c->offset += k; 183 unlock(&c->l); 184 185 l = convM2S(msg, k, &f); 186 if(l != k) 187 error("bad fversion conversion on reply"); 188 if(f.type != Rversion){ 189 if(f.type == Rerror) 190 error(f.ename); 191 error("unexpected reply type in fversion"); 192 } 193 if(f.msize > msize) 194 error("server tries to increase msize in fversion"); 195 if(f.msize<256 || f.msize>1024*1024) 196 error("nonsense value of msize in fversion"); 197 if(strncmp(f.version, v, strlen(f.version)) != 0) 198 error("bad 9P version returned from server"); 199 200 /* now build Mnt associated with this connection */ 201 lock(&mntalloc.l); 202 m = mntalloc.mntfree; 203 if(m != 0) 204 mntalloc.mntfree = m->list; 205 else { 206 m = malloc(sizeof(Mnt)); 207 if(m == 0) { 208 unlock(&mntalloc.l); 209 exhausted("mount devices"); 210 } 211 } 212 m->list = mntalloc.list; 213 mntalloc.list = m; 214 m->version = nil; 215 kstrdup(&m->version, f.version); 216 m->id = mntalloc.id++; 217 m->q = qopen(10*MAXRPC, 0, nil, nil); 218 m->msize = f.msize; 219 unlock(&mntalloc.l); 220 221 poperror(); /* msg */ 222 free(msg); 223 224 lock(&m->l); 225 m->queue = 0; 226 m->rip = 0; 227 228 c->flag |= CMSG; 229 c->mux = m; 230 m->c = c; 231 unlock(&m->l); 232 233 poperror(); /* c */ 234 qunlock(&c->umqlock); 235 236 k = strlen(f.version); 237 if(returnlen > 0){ 238 if(returnlen < k) 239 error(Eshort); 240 memmove(version, f.version, k); 241 } 242 243 return k; 244 } 245 246 Chan* 247 mntauth(Chan *c, char *spec) 248 { 249 Mnt *m; 250 Mntrpc *r; 251 252 m = c->mux; 253 254 if(m == nil){ 255 mntversion(c, VERSION9P, MAXRPC, 0); 256 m = c->mux; 257 if(m == nil) 258 error(Enoversion); 259 } 260 261 c = mntchan(); 262 if(waserror()) { 263 /* Close must not be called since it will 264 * call mnt recursively 265 */ 266 chanfree(c); 267 nexterror(); 268 } 269 270 r = mntralloc(0, m->msize); 271 272 if(waserror()) { 273 mntfree(r); 274 nexterror(); 275 } 276 277 r->request.type = Tauth; 278 r->request.afid = c->fid; 279 r->request.uname = up->env->user; 280 r->request.aname = spec; 281 mountrpc(m, r); 282 283 c->qid = r->reply.aqid; 284 c->mchan = m->c; 285 incref(&m->c->r); 286 c->mqid = c->qid; 287 c->mode = ORDWR; 288 289 poperror(); /* r */ 290 mntfree(r); 291 292 poperror(); /* c */ 293 294 return c; 295 296 } 297 298 static Chan* 299 mntattach(char *muxattach) 300 { 301 Mnt *m; 302 Chan *c; 303 Mntrpc *r; 304 struct bogus{ 305 Chan *chan; 306 Chan *authchan; 307 char *spec; 308 int flags; 309 }bogus; 310 311 bogus = *((struct bogus *)muxattach); 312 c = bogus.chan; 313 314 m = c->mux; 315 316 if(m == nil){ 317 mntversion(c, nil, 0, 0); 318 m = c->mux; 319 if(m == nil) 320 error(Enoversion); 321 } 322 323 c = mntchan(); 324 if(waserror()) { 325 /* Close must not be called since it will 326 * call mnt recursively 327 */ 328 chanfree(c); 329 nexterror(); 330 } 331 332 r = mntralloc(0, m->msize); 333 334 if(waserror()) { 335 mntfree(r); 336 nexterror(); 337 } 338 339 r->request.type = Tattach; 340 r->request.fid = c->fid; 341 if(bogus.authchan == nil) 342 r->request.afid = NOFID; 343 else 344 r->request.afid = bogus.authchan->fid; 345 r->request.uname = up->env->user; 346 r->request.aname = bogus.spec; 347 mountrpc(m, r); 348 349 c->qid = r->reply.qid; 350 c->mchan = m->c; 351 incref(&m->c->r); 352 c->mqid = c->qid; 353 354 poperror(); /* r */ 355 mntfree(r); 356 357 poperror(); /* c */ 358 359 if(bogus.flags&MCACHE) 360 c->flag |= CCACHE; 361 return c; 362 } 363 364 Chan* 365 mntchan(void) 366 { 367 Chan *c; 368 369 c = devattach('M', 0); 370 lock(&mntalloc.l); 371 c->dev = mntalloc.id++; 372 unlock(&mntalloc.l); 373 374 if(c->mchan) 375 panic("mntchan non-zero %p", c->mchan); 376 return c; 377 } 378 379 static Walkqid* 380 mntwalk(Chan *c, Chan *nc, char **name, int nname) 381 { 382 volatile int alloc; 383 int i; 384 Mnt *m; 385 Mntrpc *r; 386 Walkqid *wq; 387 388 if(nc != nil) 389 print("mntwalk: nc != nil\n"); 390 if(nname > MAXWELEM) 391 error("devmnt: too many name elements"); 392 alloc = 0; 393 wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid)); 394 if(waserror()){ 395 if(alloc && wq->clone!=nil) 396 cclose(wq->clone); 397 free(wq); 398 return nil; 399 } 400 401 alloc = 0; 402 m = mntchk(c); 403 r = mntralloc(c, m->msize); 404 if(nc == nil){ 405 nc = devclone(c); 406 /* 407 * Until the other side accepts this fid, we can't mntclose it. 408 * Therefore set type to 0 for now; rootclose is known to be safe. 409 */ 410 nc->type = 0; 411 alloc = 1; 412 } 413 wq->clone = nc; 414 415 if(waserror()) { 416 mntfree(r); 417 nexterror(); 418 } 419 r->request.type = Twalk; 420 r->request.fid = c->fid; 421 r->request.newfid = nc->fid; 422 r->request.nwname = nname; 423 memmove(r->request.wname, name, nname*sizeof(char*)); 424 425 mountrpc(m, r); 426 427 if(r->reply.nwqid > nname) 428 error("too many QIDs returned by walk"); 429 if(r->reply.nwqid < nname){ 430 if(alloc) 431 cclose(nc); 432 wq->clone = nil; 433 if(r->reply.nwqid == 0){ 434 free(wq); 435 wq = nil; 436 goto Return; 437 } 438 } 439 440 /* move new fid onto mnt device and update its qid */ 441 if(wq->clone != nil){ 442 if(wq->clone != c){ 443 wq->clone->type = c->type; 444 wq->clone->mchan = c->mchan; 445 incref(&c->mchan->r); 446 } 447 if(r->reply.nwqid > 0) 448 wq->clone->qid = r->reply.wqid[r->reply.nwqid-1]; 449 } 450 wq->nqid = r->reply.nwqid; 451 for(i=0; i<wq->nqid; i++) 452 wq->qid[i] = r->reply.wqid[i]; 453 454 Return: 455 poperror(); 456 mntfree(r); 457 poperror(); 458 return wq; 459 } 460 461 static int 462 mntstat(Chan *c, uchar *dp, int n) 463 { 464 Mnt *m; 465 Mntrpc *r; 466 467 if(n < BIT16SZ) 468 error(Eshortstat); 469 m = mntchk(c); 470 r = mntralloc(c, m->msize); 471 if(waserror()) { 472 mntfree(r); 473 nexterror(); 474 } 475 r->request.type = Tstat; 476 r->request.fid = c->fid; 477 mountrpc(m, r); 478 479 if(r->reply.nstat > n){ 480 /* doesn't fit; just patch the count and return */ 481 PBIT16((uchar*)dp, r->reply.nstat); 482 n = BIT16SZ; 483 }else{ 484 n = r->reply.nstat; 485 memmove(dp, r->reply.stat, n); 486 validstat(dp, n); 487 mntdirfix(dp, c); 488 } 489 poperror(); 490 mntfree(r); 491 return n; 492 } 493 494 static Chan* 495 mntopencreate(int type, Chan *c, char *name, int omode, ulong perm) 496 { 497 Mnt *m; 498 Mntrpc *r; 499 500 m = mntchk(c); 501 r = mntralloc(c, m->msize); 502 if(waserror()) { 503 mntfree(r); 504 nexterror(); 505 } 506 r->request.type = type; 507 r->request.fid = c->fid; 508 r->request.mode = omode; 509 if(type == Tcreate){ 510 r->request.perm = perm; 511 r->request.name = name; 512 } 513 mountrpc(m, r); 514 515 c->qid = r->reply.qid; 516 c->offset = 0; 517 c->mode = openmode(omode); 518 c->iounit = r->reply.iounit; 519 if(c->iounit == 0 || c->iounit > m->msize-IOHDRSZ) 520 c->iounit = m->msize-IOHDRSZ; 521 c->flag |= COPEN; 522 poperror(); 523 mntfree(r); 524 525 if(c->flag & CCACHE) 526 copen(c); 527 528 return c; 529 } 530 531 static Chan* 532 mntopen(Chan *c, int omode) 533 { 534 return mntopencreate(Topen, c, nil, omode, 0); 535 } 536 537 static void 538 mntcreate(Chan *c, char *name, int omode, ulong perm) 539 { 540 mntopencreate(Tcreate, c, name, omode, perm); 541 } 542 543 static void 544 mntclunk(Chan *c, int t) 545 { 546 Mnt *m; 547 Mntrpc *r; 548 549 m = mntchk(c); 550 r = mntralloc(c, m->msize); 551 if(waserror()){ 552 mntfree(r); 553 nexterror(); 554 } 555 556 r->request.type = t; 557 r->request.fid = c->fid; 558 mountrpc(m, r); 559 mntfree(r); 560 poperror(); 561 } 562 563 void 564 muxclose(Mnt *m) 565 { 566 Mntrpc *q, *r; 567 568 for(q = m->queue; q; q = r) { 569 r = q->list; 570 mntfree(q); 571 } 572 m->id = 0; 573 free(m->version); 574 m->version = nil; 575 mntpntfree(m); 576 } 577 578 void 579 mntpntfree(Mnt *m) 580 { 581 Mnt *f, **l; 582 Queue *q; 583 584 lock(&mntalloc.l); 585 l = &mntalloc.list; 586 for(f = *l; f; f = f->list) { 587 if(f == m) { 588 *l = m->list; 589 break; 590 } 591 l = &f->list; 592 } 593 m->list = mntalloc.mntfree; 594 mntalloc.mntfree = m; 595 q = m->q; 596 unlock(&mntalloc.l); 597 598 qfree(q); 599 } 600 601 static void 602 mntclose(Chan *c) 603 { 604 mntclunk(c, Tclunk); 605 } 606 607 static void 608 mntremove(Chan *c) 609 { 610 mntclunk(c, Tremove); 611 } 612 613 static int 614 mntwstat(Chan *c, uchar *dp, int n) 615 { 616 Mnt *m; 617 Mntrpc *r; 618 619 m = mntchk(c); 620 r = mntralloc(c, m->msize); 621 if(waserror()) { 622 mntfree(r); 623 nexterror(); 624 } 625 r->request.type = Twstat; 626 r->request.fid = c->fid; 627 r->request.nstat = n; 628 r->request.stat = dp; 629 mountrpc(m, r); 630 poperror(); 631 mntfree(r); 632 return n; 633 } 634 635 static long 636 mntread(Chan *c, void *buf, long n, vlong off) 637 { 638 uchar *p, *e; 639 int nc, cache, isdir, dirlen; 640 641 isdir = 0; 642 cache = c->flag & CCACHE; 643 if(c->qid.type & QTDIR) { 644 cache = 0; 645 isdir = 1; 646 } 647 648 p = buf; 649 if(cache) { 650 nc = cread(c, buf, n, off); 651 if(nc > 0) { 652 n -= nc; 653 if(n == 0) 654 return nc; 655 p += nc; 656 off += nc; 657 } 658 n = mntrdwr(Tread, c, p, n, off); 659 cupdate(c, p, n, off); 660 return n + nc; 661 } 662 663 n = mntrdwr(Tread, c, buf, n, off); 664 if(isdir) { 665 for(e = &p[n]; p+BIT16SZ < e; p += dirlen){ 666 dirlen = BIT16SZ+GBIT16(p); 667 if(p+dirlen > e) 668 break; 669 validstat(p, dirlen); 670 mntdirfix(p, c); 671 } 672 if(p != e) 673 error(Esbadstat); 674 } 675 return n; 676 } 677 678 static long 679 mntwrite(Chan *c, void *buf, long n, vlong off) 680 { 681 return mntrdwr(Twrite, c, buf, n, off); 682 } 683 684 long 685 mntrdwr(int type, Chan *c, void *buf, long n, vlong off) 686 { 687 Mnt *m; 688 Mntrpc *r; /* TO DO: volatile struct { Mntrpc *r; } r; */ 689 char *uba; 690 int cache; 691 ulong cnt, nr, nreq; 692 693 m = mntchk(c); 694 uba = buf; 695 cnt = 0; 696 cache = c->flag & CCACHE; 697 if(c->qid.type & QTDIR) 698 cache = 0; 699 for(;;) { 700 r = mntralloc(c, m->msize); 701 if(waserror()) { 702 mntfree(r); 703 nexterror(); 704 } 705 r->request.type = type; 706 r->request.fid = c->fid; 707 r->request.offset = off; 708 r->request.data = uba; 709 nr = n; 710 if(nr > m->msize-IOHDRSZ) 711 nr = m->msize-IOHDRSZ; 712 r->request.count = nr; 713 mountrpc(m, r); 714 nreq = r->request.count; 715 nr = r->reply.count; 716 if(nr > nreq) 717 nr = nreq; 718 719 if(type == Tread) 720 r->b = bl2mem((uchar*)uba, r->b, nr); 721 else if(cache) 722 cwrite(c, (uchar*)uba, nr, off); 723 724 poperror(); 725 mntfree(r); 726 off += nr; 727 uba += nr; 728 cnt += nr; 729 n -= nr; 730 if(nr != nreq || n == 0 || up->killed) 731 break; 732 } 733 return cnt; 734 } 735 736 void 737 mountrpc(Mnt *m, Mntrpc *r) 738 { 739 char *sn, *cn; 740 int t; 741 742 r->reply.tag = 0; 743 r->reply.type = Tmax; /* can't ever be a valid message type */ 744 745 mountio(m, r); 746 747 t = r->reply.type; 748 switch(t) { 749 case Rerror: 750 error(r->reply.ename); 751 case Rflush: 752 error(Eintr); 753 default: 754 if(t == r->request.type+1) 755 break; 756 sn = "?"; 757 if(m->c->name != nil) 758 sn = m->c->name->s; 759 cn = "?"; 760 if(r->c != nil && r->c->name != nil) 761 cn = r->c->name->s; 762 print("mnt: proc %s %lud: mismatch from %s %s rep 0x%p tag %d fid %d T%d R%d rp %d\n", 763 up->text, up->pid, sn, cn, 764 r, r->request.tag, r->request.fid, r->request.type, 765 r->reply.type, r->reply.tag); 766 error(Emountrpc); 767 } 768 } 769 770 void 771 mountio(Mnt *m, Mntrpc *r) 772 { 773 int n; 774 775 while(waserror()) { 776 if(m->rip == up) 777 mntgate(m); 778 if(strcmp(up->env->errstr, Eintr) != 0){ 779 mntflushfree(m, r); 780 nexterror(); 781 } 782 r = mntflushalloc(r, m->msize); 783 } 784 785 lock(&m->l); 786 r->m = m; 787 r->list = m->queue; 788 m->queue = r; 789 unlock(&m->l); 790 791 /* Transmit a file system rpc */ 792 if(m->msize == 0) 793 panic("msize"); 794 n = convS2M(&r->request, r->rpc, m->msize); 795 if(n < 0) 796 panic("bad message type in mountio"); 797 if(devtab[m->c->type]->write(m->c, r->rpc, n, 0) != n) 798 error(Emountrpc); 799 /* r->stime = fastticks(nil); */ 800 r->reqlen = n; 801 802 /* Gate readers onto the mount point one at a time */ 803 for(;;) { 804 lock(&m->l); 805 if(m->rip == 0) 806 break; 807 unlock(&m->l); 808 Sleep(&r->r, rpcattn, r); 809 if(r->done){ 810 poperror(); 811 mntflushfree(m, r); 812 return; 813 } 814 } 815 m->rip = up; 816 unlock(&m->l); 817 while(r->done == 0) { 818 if(mntrpcread(m, r) < 0) 819 error(Emountrpc); 820 mountmux(m, r); 821 } 822 mntgate(m); 823 poperror(); 824 mntflushfree(m, r); 825 } 826 827 static int 828 doread(Mnt *m, int len) 829 { 830 Block *b; 831 832 while(qlen(m->q) < len){ 833 b = devtab[m->c->type]->bread(m->c, m->msize, 0); 834 if(b == nil) 835 return -1; 836 if(blocklen(b) == 0){ 837 freeblist(b); 838 return -1; 839 } 840 qaddlist(m->q, b); 841 } 842 return 0; 843 } 844 845 int 846 mntrpcread(Mnt *m, Mntrpc *r) 847 { 848 int i, t, len, hlen; 849 Block *b, **l, *nb; 850 851 r->reply.type = 0; 852 r->reply.tag = 0; 853 854 /* read at least length, type, and tag and pullup to a single block */ 855 if(doread(m, BIT32SZ+BIT8SZ+BIT16SZ) < 0) 856 return -1; 857 nb = pullupqueue(m->q, BIT32SZ+BIT8SZ+BIT16SZ); 858 859 /* read in the rest of the message, avoid ridiculous (for now) message sizes */ 860 len = GBIT32(nb->rp); 861 if(len > m->msize){ 862 qdiscard(m->q, qlen(m->q)); 863 return -1; 864 } 865 if(doread(m, len) < 0) 866 return -1; 867 868 /* pullup the header (i.e. everything except data) */ 869 t = nb->rp[BIT32SZ]; 870 switch(t){ 871 case Rread: 872 hlen = BIT32SZ+BIT8SZ+BIT16SZ+BIT32SZ; 873 break; 874 default: 875 hlen = len; 876 break; 877 } 878 nb = pullupqueue(m->q, hlen); 879 880 if(convM2S(nb->rp, len, &r->reply) <= 0){ 881 /* bad message, dump it */ 882 print("mntrpcread: convM2S failed\n"); 883 qdiscard(m->q, len); 884 return -1; 885 } 886 887 /* hang the data off of the fcall struct */ 888 l = &r->b; 889 *l = nil; 890 do { 891 b = qremove(m->q); 892 if(hlen > 0){ 893 b->rp += hlen; 894 len -= hlen; 895 hlen = 0; 896 } 897 i = BLEN(b); 898 if(i <= len){ 899 len -= i; 900 *l = b; 901 l = &(b->next); 902 } else { 903 /* split block and put unused bit back */ 904 nb = allocb(i-len); 905 memmove(nb->wp, b->rp+len, i-len); 906 b->wp = b->rp+len; 907 nb->wp += i-len; 908 qputback(m->q, nb); 909 *l = b; 910 return 0; 911 } 912 }while(len > 0); 913 914 return 0; 915 } 916 917 void 918 mntgate(Mnt *m) 919 { 920 Mntrpc *q; 921 922 lock(&m->l); 923 m->rip = 0; 924 for(q = m->queue; q; q = q->list) { 925 if(q->done == 0) 926 if(Wakeup(&q->r)) 927 break; 928 } 929 unlock(&m->l); 930 } 931 932 void 933 mountmux(Mnt *m, Mntrpc *r) 934 { 935 Mntrpc **l, *q; 936 937 lock(&m->l); 938 l = &m->queue; 939 for(q = *l; q; q = q->list) { 940 /* look for a reply to a message */ 941 if(q->request.tag == r->reply.tag) { 942 *l = q->list; 943 if(q != r) { 944 /* 945 * Completed someone else. 946 * Trade pointers to receive buffer. 947 */ 948 q->reply = r->reply; 949 q->b = r->b; 950 r->b = nil; 951 } 952 q->done = 1; 953 unlock(&m->l); 954 if(mntstats != nil) 955 (*mntstats)(q->request.type, 956 m->c, q->stime, 957 q->reqlen + r->replen); 958 if(q != r) 959 Wakeup(&q->r); 960 return; 961 } 962 l = &q->list; 963 } 964 unlock(&m->l); 965 if(r->reply.type == Rerror) 966 print("unexpected reply tag %ud; type %d (error %q)\n", r->reply.tag, r->reply.type, r->reply.ename); 967 else 968 print("unexpected reply tag %ud; type %d\n", r->reply.tag, r->reply.type); 969 } 970 971 /* 972 * Create a new flush request and chain the previous 973 * requests from it 974 */ 975 Mntrpc* 976 mntflushalloc(Mntrpc *r, ulong iounit) 977 { 978 Mntrpc *fr; 979 980 fr = mntralloc(0, iounit); 981 982 fr->request.type = Tflush; 983 if(r->request.type == Tflush) 984 fr->request.oldtag = r->request.oldtag; 985 else 986 fr->request.oldtag = r->request.tag; 987 fr->flushed = r; 988 989 return fr; 990 } 991 992 /* 993 * Free a chain of flushes. Remove each unanswered 994 * flush and the original message from the unanswered 995 * request queue. Mark the original message as done 996 * and if it hasn't been answered set the reply to to 997 * Rflush. 998 */ 999 void 1000 mntflushfree(Mnt *m, Mntrpc *r) 1001 { 1002 Mntrpc *fr; 1003 1004 while(r){ 1005 fr = r->flushed; 1006 if(!r->done){ 1007 r->reply.type = Rflush; 1008 mntqrm(m, r); 1009 } 1010 if(fr) 1011 mntfree(r); 1012 r = fr; 1013 } 1014 } 1015 1016 static int 1017 alloctag(void) 1018 { 1019 int i, j; 1020 ulong v; 1021 1022 for(i = 0; i < NMASK; i++){ 1023 v = mntalloc.tagmask[i]; 1024 if(v == ~0UL) 1025 continue; 1026 for(j = 0; j < 1<<TAGSHIFT; j++) 1027 if((v & (1<<j)) == 0){ 1028 mntalloc.tagmask[i] |= 1<<j; 1029 return (i<<TAGSHIFT) + j; 1030 } 1031 } 1032 /* panic("no devmnt tags left"); */ 1033 return NOTAG; 1034 } 1035 1036 static void 1037 freetag(int t) 1038 { 1039 mntalloc.tagmask[t>>TAGSHIFT] &= ~(1<<(t&TAGMASK)); 1040 } 1041 1042 Mntrpc* 1043 mntralloc(Chan *c, ulong msize) 1044 { 1045 Mntrpc *new; 1046 1047 lock(&mntalloc.l); 1048 new = mntalloc.rpcfree; 1049 if(new == nil){ 1050 new = malloc(sizeof(Mntrpc)); 1051 if(new == nil) { 1052 unlock(&mntalloc.l); 1053 exhausted("mount rpc header"); 1054 } 1055 /* 1056 * The header is split from the data buffer as 1057 * mountmux may swap the buffer with another header. 1058 */ 1059 new->rpc = mallocz(msize, 0); 1060 if(new->rpc == nil){ 1061 free(new); 1062 unlock(&mntalloc.l); 1063 exhausted("mount rpc buffer"); 1064 } 1065 new->rpclen = msize; 1066 new->request.tag = alloctag(); 1067 if(new->request.tag == NOTAG){ 1068 free(new); 1069 unlock(&mntalloc.l); 1070 exhausted("rpc tags"); 1071 } 1072 } 1073 else { 1074 mntalloc.rpcfree = new->list; 1075 mntalloc.nrpcfree--; 1076 if(new->rpclen < msize){ 1077 free(new->rpc); 1078 new->rpc = mallocz(msize, 0); 1079 if(new->rpc == nil){ 1080 free(new); 1081 mntalloc.nrpcused--; 1082 unlock(&mntalloc.l); 1083 exhausted("mount rpc buffer"); 1084 } 1085 new->rpclen = msize; 1086 } 1087 } 1088 mntalloc.nrpcused++; 1089 unlock(&mntalloc.l); 1090 new->c = c; 1091 new->done = 0; 1092 new->flushed = nil; 1093 new->b = nil; 1094 return new; 1095 } 1096 1097 void 1098 mntfree(Mntrpc *r) 1099 { 1100 if(r->b != nil) 1101 freeblist(r->b); 1102 lock(&mntalloc.l); 1103 if(mntalloc.nrpcfree >= 10){ 1104 free(r->rpc); 1105 freetag(r->request.tag); 1106 free(r); 1107 } 1108 else{ 1109 r->list = mntalloc.rpcfree; 1110 mntalloc.rpcfree = r; 1111 mntalloc.nrpcfree++; 1112 } 1113 mntalloc.nrpcused--; 1114 unlock(&mntalloc.l); 1115 } 1116 1117 void 1118 mntqrm(Mnt *m, Mntrpc *r) 1119 { 1120 Mntrpc **l, *f; 1121 1122 lock(&m->l); 1123 r->done = 1; 1124 1125 l = &m->queue; 1126 for(f = *l; f; f = f->list) { 1127 if(f == r) { 1128 *l = r->list; 1129 break; 1130 } 1131 l = &f->list; 1132 } 1133 unlock(&m->l); 1134 } 1135 1136 Mnt* 1137 mntchk(Chan *c) 1138 { 1139 Mnt *m; 1140 1141 /* This routine is mostly vestiges of prior lives; now it's just sanity checking */ 1142 1143 if(c->mchan == nil) 1144 panic("mntchk 1: nil mchan c %s\n", c2name(c)); 1145 1146 m = c->mchan->mux; 1147 1148 if(m == nil) 1149 print("mntchk 2: nil mux c %s c->mchan %s \n", c2name(c), c2name(c->mchan)); 1150 1151 /* 1152 * Was it closed and reused (was error(Eshutdown); now, it can't happen) 1153 */ 1154 if(m->id == 0 || m->id >= c->dev) 1155 panic("mntchk 3: can't happen"); 1156 1157 return m; 1158 } 1159 1160 /* 1161 * Rewrite channel type and dev for in-flight data to 1162 * reflect local values. These entries are known to be 1163 * the first two in the Dir encoding after the count. 1164 */ 1165 void 1166 mntdirfix(uchar *dirbuf, Chan *c) 1167 { 1168 uint r; 1169 1170 r = devtab[c->type]->dc; 1171 dirbuf += BIT16SZ; /* skip count */ 1172 PBIT16(dirbuf, r); 1173 dirbuf += BIT16SZ; 1174 PBIT32(dirbuf, c->dev); 1175 } 1176 1177 int 1178 rpcattn(void *v) 1179 { 1180 Mntrpc *r; 1181 1182 r = v; 1183 return r->done || r->m->rip == 0; 1184 } 1185 1186 Dev mntdevtab = { 1187 'M', 1188 "mnt", 1189 1190 mntinit, 1191 mntattach, 1192 mntwalk, 1193 mntstat, 1194 mntopen, 1195 mntcreate, 1196 mntclose, 1197 mntread, 1198 devbread, 1199 mntwrite, 1200 devbwrite, 1201 mntremove, 1202 mntwstat, 1203 }; 1204