|
|
1.1 ! root 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.