📄 devmnt.c
字号:
mntalloc.mntfree = m; q = m->q; unlock(&mntalloc.lk); qfree(q);}static voidmntclose(Chan *c){ mntclunk(c, Tclunk);}static voidmntremove(Chan *c){ mntclunk(c, Tremove);}static intmntwstat(Chan *c, uchar *dp, int n){ Mnt *m; Mntrpc *r; m = mntchk(c); r = mntralloc(c, m->msize); if(waserror()) { mntfree(r); nexterror(); } r->request.type = Twstat; r->request.fid = c->fid; r->request.nstat = n; r->request.stat = dp; mountrpc(m, r); poperror(); mntfree(r); return n;}static longmntread(Chan *c, void *buf, long n, vlong off){ uchar *p, *e; int nc, cache, isdir, dirlen; isdir = 0; cache = c->flag & CCACHE; if(c->qid.type & QTDIR) { cache = 0; isdir = 1; } p = buf; if(cache) { nc = cread(c, buf, n, off); if(nc > 0) { n -= nc; if(n == 0) return nc; p += nc; off += nc; } n = mntrdwr(Tread, c, p, n, off); cupdate(c, p, n, off); return n + nc; } n = mntrdwr(Tread, c, buf, n, off); if(isdir) { for(e = &p[n]; p+BIT16SZ < e; p += dirlen){ dirlen = BIT16SZ+GBIT16(p); if(p+dirlen > e) break; validstat(p, dirlen); mntdirfix(p, c); } if(p != e) error(Esbadstat); } return n;}static longmntwrite(Chan *c, void *buf, long n, vlong off){ return mntrdwr(Twrite, c, buf, n, off);}longmntrdwr(int type, Chan *c, void *buf, long n, vlong off){ Mnt *m; Mntrpc *r; char *uba; int cache; ulong cnt, nr, nreq; m = mntchk(c); uba = buf; cnt = 0; cache = c->flag & CCACHE; if(c->qid.type & QTDIR) cache = 0; for(;;) { r = mntralloc(c, m->msize); if(waserror()) { mntfree(r); nexterror(); } r->request.type = type; r->request.fid = c->fid; r->request.offset = off; r->request.data = uba; nr = n; if(nr > m->msize-IOHDRSZ) nr = m->msize-IOHDRSZ; r->request.count = nr; mountrpc(m, r); nreq = r->request.count; nr = r->reply.count; if(nr > nreq) nr = nreq; if(type == Tread) r->b = bl2mem((uchar*)uba, r->b, nr); else if(cache) cwrite(c, (uchar*)uba, nr, off); poperror(); mntfree(r); off += nr; uba += nr; cnt += nr; n -= nr; if(nr != nreq || n == 0 || up->nnote) break; } return cnt;}voidmountrpc(Mnt *m, Mntrpc *r){ char *sn, *cn; int t; r->reply.tag = 0; r->reply.type = Tmax; /* can't ever be a valid message type */ mountio(m, r); t = r->reply.type; switch(t) { case Rerror: error(r->reply.ename); case Rflush: error(Eintr); default: if(t == r->request.type+1) break; sn = "?"; if(m->c->path != nil) sn = m->c->path->s; cn = "?"; if(r->c != nil && r->c->path != nil) cn = r->c->path->s; print("mnt: proc %s %lud: mismatch from %s %s rep 0x%lux tag %d fid %d T%d R%d rp %d\n", up->text, up->pid, sn, cn, r, r->request.tag, r->request.fid, r->request.type, r->reply.type, r->reply.tag); error(Emountrpc); }}voidmountio(Mnt *m, Mntrpc *r){ int n; while(waserror()) { if(m->rip == up) mntgate(m); if(strcmp(up->errstr, Eintr) != 0){ mntflushfree(m, r); nexterror(); } r = mntflushalloc(r, m->msize); } lock(&m->lk); r->m = m; r->list = m->queue; m->queue = r; unlock(&m->lk); /* Transmit a file system rpc */ if(m->msize == 0) panic("msize"); n = convS2M(&r->request, r->rpc, m->msize); if(n < 0) panic("bad message type in mountio"); if(devtab[m->c->type]->write(m->c, r->rpc, n, 0) != n) error(Emountrpc); r->stime = fastticks(nil); r->reqlen = n; /* Gate readers onto the mount point one at a time */ for(;;) { lock(&m->lk); if(m->rip == 0) break; unlock(&m->lk); sleep(&r->r, rpcattn, r); if(r->done){ poperror(); mntflushfree(m, r); return; } } m->rip = up; unlock(&m->lk); while(r->done == 0) { if(mntrpcread(m, r) < 0) error(Emountrpc); mountmux(m, r); } mntgate(m); poperror(); mntflushfree(m, r);}static intdoread(Mnt *m, int len){ Block *b; while(qlen(m->q) < len){ b = devtab[m->c->type]->bread(m->c, m->msize, 0); if(b == nil) return -1; if(blocklen(b) == 0){ freeblist(b); return -1; } qaddlist(m->q, b); } return 0;}intmntrpcread(Mnt *m, Mntrpc *r){ int i, t, len, hlen; Block *b, **l, *nb; r->reply.type = 0; r->reply.tag = 0; /* read at least length, type, and tag and pullup to a single block */ if(doread(m, BIT32SZ+BIT8SZ+BIT16SZ) < 0) return -1; nb = pullupqueue(m->q, BIT32SZ+BIT8SZ+BIT16SZ); /* read in the rest of the message, avoid ridiculous (for now) message sizes */ len = GBIT32(nb->rp); if(len > m->msize){ qdiscard(m->q, qlen(m->q)); return -1; } if(doread(m, len) < 0) return -1; /* pullup the header (i.e. everything except data) */ t = nb->rp[BIT32SZ]; switch(t){ case Rread: hlen = BIT32SZ+BIT8SZ+BIT16SZ+BIT32SZ; break; default: hlen = len; break; } nb = pullupqueue(m->q, hlen); if(convM2S(nb->rp, len, &r->reply) <= 0){ /* bad message, dump it */ print("mntrpcread: convM2S failed\n"); qdiscard(m->q, len); return -1; } /* hang the data off of the fcall struct */ l = &r->b; *l = nil; do { b = qremove(m->q); if(hlen > 0){ b->rp += hlen; len -= hlen; hlen = 0; } i = BLEN(b); if(i <= len){ len -= i; *l = b; l = &(b->next); } else { /* split block and put unused bit back */ nb = allocb(i-len); memmove(nb->wp, b->rp+len, i-len); b->wp = b->rp+len; nb->wp += i-len; qputback(m->q, nb); *l = b; return 0; } }while(len > 0); return 0;}voidmntgate(Mnt *m){ Mntrpc *q; lock(&m->lk); m->rip = 0; for(q = m->queue; q; q = q->list) { if(q->done == 0) if(wakeup(&q->r)) break; } unlock(&m->lk);}voidmountmux(Mnt *m, Mntrpc *r){ Mntrpc **l, *q; lock(&m->lk); l = &m->queue; for(q = *l; q; q = q->list) { /* look for a reply to a message */ if(q->request.tag == r->reply.tag) { *l = q->list; if(q != r) { /* * Completed someone else. * Trade pointers to receive buffer. */ q->reply = r->reply; q->b = r->b; r->b = nil; } q->done = 1; unlock(&m->lk); if(mntstats != nil) (*mntstats)(q->request.type, m->c, q->stime, q->reqlen + r->replen); if(q != r) wakeup(&q->r); return; } l = &q->list; } unlock(&m->lk); print("unexpected reply tag %ud; type %d\n", r->reply.tag, r->reply.type);}/* * Create a new flush request and chain the previous * requests from it */Mntrpc*mntflushalloc(Mntrpc *r, ulong iounit){ Mntrpc *fr; fr = mntralloc(0, iounit); fr->request.type = Tflush; if(r->request.type == Tflush) fr->request.oldtag = r->request.oldtag; else fr->request.oldtag = r->request.tag; fr->flushed = r; return fr;}/* * Free a chain of flushes. Remove each unanswered * flush and the original message from the unanswered * request queue. Mark the original message as done * and if it hasn't been answered set the reply to to * Rflush. */voidmntflushfree(Mnt *m, Mntrpc *r){ Mntrpc *fr; while(r){ fr = r->flushed; if(!r->done){ r->reply.type = Rflush; mntqrm(m, r); } if(fr) mntfree(r); r = fr; }}intalloctag(void){ int i, j; ulong v; for(i = 0; i < NMASK; i++){ v = mntalloc.tagmask[i]; if(v == ~0UL) continue; for(j = 0; j < 1<<TAGSHIFT; j++) if((v & (1<<j)) == 0){ mntalloc.tagmask[i] |= 1<<j; return (i<<TAGSHIFT) + j; } } panic("no friggin tags left"); return NOTAG;}voidfreetag(int t){ mntalloc.tagmask[t>>TAGSHIFT] &= ~(1<<(t&TAGMASK));}Mntrpc*mntralloc(Chan *c, ulong msize){ Mntrpc *new; lock(&mntalloc.lk); new = mntalloc.rpcfree; if(new == nil){ new = malloc(sizeof(Mntrpc)); if(new == nil) { unlock(&mntalloc.lk); exhausted("mount rpc header"); } /* * The header is split from the data buffer as * mountmux may swap the buffer with another header. */ new->rpc = mallocz(msize, 0); if(new->rpc == nil){ free(new); unlock(&mntalloc.lk); exhausted("mount rpc buffer"); } new->rpclen = msize; new->request.tag = alloctag(); } else { mntalloc.rpcfree = new->list; mntalloc.nrpcfree--; if(new->rpclen < msize){ free(new->rpc); new->rpc = mallocz(msize, 0); if(new->rpc == nil){ free(new); mntalloc.nrpcused--; unlock(&mntalloc.lk); exhausted("mount rpc buffer"); } new->rpclen = msize; } } mntalloc.nrpcused++; unlock(&mntalloc.lk); new->c = c; new->done = 0; new->flushed = nil; new->b = nil; return new;}voidmntfree(Mntrpc *r){ if(r->b != nil) freeblist(r->b); lock(&mntalloc.lk); if(mntalloc.nrpcfree >= 10){ free(r->rpc); free(r); freetag(r->request.tag); } else{ r->list = mntalloc.rpcfree; mntalloc.rpcfree = r; mntalloc.nrpcfree++; } mntalloc.nrpcused--; unlock(&mntalloc.lk);}voidmntqrm(Mnt *m, Mntrpc *r){ Mntrpc **l, *f; lock(&m->lk); r->done = 1; l = &m->queue; for(f = *l; f; f = f->list) { if(f == r) { *l = r->list; break; } l = &f->list; } unlock(&m->lk);}Mnt*mntchk(Chan *c){ Mnt *m; /* This routine is mostly vestiges of prior lives; now it's just sanity checking */ if(c->mchan == nil) panic("mntchk 1: nil mchan c %s\n", chanpath(c)); m = c->mchan->mux; if(m == nil) print("mntchk 2: nil mux c %s c->mchan %s \n", chanpath(c), chanpath(c->mchan)); /* * Was it closed and reused (was error(Eshutdown); now, it cannot happen) */ if(m->id == 0 || m->id >= c->dev) panic("mntchk 3: can't happen"); return m;}/* * Rewrite channel type and dev for in-flight data to * reflect local values. These entries are known to be * the first two in the Dir encoding after the count. */voidmntdirfix(uchar *dirbuf, Chan *c){ uint r; r = devtab[c->type]->dc; dirbuf += BIT16SZ; /* skip count */ PBIT16(dirbuf, r); dirbuf += BIT16SZ; PBIT32(dirbuf, c->dev);}intrpcattn(void *v){ Mntrpc *r; r = v; return r->done || r->m->rip == 0;}Dev mntdevtab = { 'M', "mnt", mntreset, devinit, devshutdown, mntattach, mntwalk, mntstat, mntopen, mntcreate, mntclose, mntread, devbread, mntwrite, devbwrite, mntremove, mntwstat,};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -