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