| plan 9 kernel history: overview | file list | diff list |
2002/0615/port/devmnt.c (diff list | history)
| port/devmnt.c on 1990/0227 | ||
| 1990/0227 | #include "u.h" | |
| 1992/0321 | #include "../port/lib.h" | |
| 1990/0227 | #include "mem.h" #include "dat.h" #include "fns.h" | |
| 1992/0111 | #include "../port/error.h" | |
| 1990/0227 | ||
| 2001/0819 | /* * References are managed as follows: * The channel to the server - a network connection or pipe - has one * reference for every Chan open on the server. The server channel has * c->mux set to the Mnt used for muxing control to that server. Mnts * have no reference count; they go away when c goes away. * Each channel derived from the mount point has mchan set to c, * and increfs/decrefs mchan to manage references on the server * connection. */ | |
| 2001/0527 | #define MAXRPC (IOHDRSZ+8192) | |
| 1991/0911 | struct Mntrpc | |
| 1990/0227 | { | |
| 1995/0107 | Chan* c; /* Channel for whom we are working */ Mntrpc* list; /* Free/pending list */ | |
| 1991/0911 | Fcall request; /* Outgoing file system protocol message */ | |
| 2001/0619 | Fcall reply; /* Incoming reply */ | |
| 1995/0107 | Mnt* m; /* Mount device during rpc */ | |
| 1991/0911 | Rendez r; /* Place to hang out */ | |
| 2001/0527 | uchar* rpc; /* I/O Data buffer */ | |
| 2001/0819 | uint rpclen; /* len of buffer */ | |
| 2001/0619 | Block *b; /* reply blocks */ | |
| 1991/0911 | char done; /* Rpc completed */ | |
| 1998/0917 | uvlong stime; /* start time for mnt statistics */ ulong reqlen; /* request length for mnt statistics */ ulong replen; /* reply length for mnt statistics */ | |
| 2000/0105 | Mntrpc* flushed; /* message this one flushes */ | |
| 1990/0227 | }; | |
| 1991/0911 | struct Mntalloc | |
| 1990/0227 | { Lock; | |
| 1995/0107 | Mnt* list; /* Mount devices in use */ Mnt* mntfree; /* Free list */ Mntrpc* rpcfree; | |
| 1999/0212 | int nrpcfree; int nrpcused; | |
| 1994/1124 | ulong id; | |
| 1992/0620 | int rpctag; | |
| 1991/0911 | }mntalloc; | |
| 1990/0227 | ||
| 2001/0527 | void mattach(Mnt*, Chan*, char*); Mnt* mntchk(Chan*); void mntdirfix(uchar*, Chan*); Mntrpc* mntflushalloc(Mntrpc*, ulong); void mntflushfree(Mnt*, Mntrpc*); void mntfree(Mntrpc*); void mntgate(Mnt*); void mntpntfree(Mnt*); void mntqrm(Mnt*, Mntrpc*); Mntrpc* mntralloc(Chan*, ulong); long mntrdwr(int, Chan*, void*, long, vlong); int mntrpcread(Mnt*, Mntrpc*); void mountio(Mnt*, Mntrpc*); void mountmux(Mnt*, Mntrpc*); void mountrpc(Mnt*, Mntrpc*); int rpcattn(void*); Chan* mntchan(void); | |
| 1990/0227 | ||
| 2001/0527 | char Esbadstat[] = "invalid directory entry received from server"; | |
| 2001/0819 | char Enoversion[] = "version not established for mount channel"; | |
| 2001/0527 | ||
| 1998/0917 | void (*mntstats)(int, Chan*, uvlong, ulong); | |
| 1994/0513 | ||
| 1991/0911 | enum | |
| 1990/0303 | { | |
| 1993/1011 | Tagspace = 1, | |
| 1991/0911 | }; | |
| 1990/0604 | ||
| 1997/0327 | static void | |
| 1991/0911 | mntreset(void) | |
| 1990/0227 | { | |
| 1991/0911 | mntalloc.id = 1; | |
| 1992/0620 | mntalloc.rpctag = Tagspace; | |
| 2002/0217 | fmtinstall('F', fcallfmt); fmtinstall('D', dirfmt); | |
| 2002/0615 | /* fmtinstall('M', dirmodefmt); No! Clashes with eipfmt [sape] */ | |
| 1993/1015 | cinit(); | |
| 1990/0604 | } | |
| 2001/0819 | /* * Version is not multiplexed: message sent only once per connection. */ long mntversion(Chan *c, char *version, int msize, int returnlen) | |
| 1990/0227 | { | |
| 2001/0819 | Fcall f; uchar *msg; | |
| 1992/0620 | Mnt *m; | |
| 2001/0819 | char *v; long k, l; uvlong oo; char buf[128]; | |
| 1990/0227 | ||
| 2001/0819 | qlock(&c->umqlock); /* make sure no one else does this until we've established ourselves */ if(waserror()){ qunlock(&c->umqlock); nexterror(); } | |
| 1992/0620 | ||
| 2001/0819 | /* defaults */ if(msize == 0) | |
| 2001/0820 | msize = MAXRPC; if(msize > c->iounit && c->iounit != 0) msize = c->iounit; | |
| 2001/0819 | v = version; if(v == nil || v[0] == '\0') v = VERSION9P; /* validity */ if(msize < 0) error("bad iounit in version call"); if(strncmp(v, VERSION9P, strlen(VERSION9P)) != 0) error("bad 9P version specification"); m = c->mux; if(m != nil){ qunlock(&c->umqlock); poperror(); strecpy(buf, buf+sizeof buf, m->version); k = strlen(buf); if(strncmp(buf, v, k) != 0){ snprint(buf, sizeof buf, "incompatible 9P versions %s %s", m->version, v); error(buf); | |
| 1991/0911 | } | |
| 2001/0819 | if(returnlen > 0){ if(returnlen < k) error(Eshort); memmove(version, buf, k); } return k; | |
| 1991/0901 | } | |
| 1993/1015 | ||
| 2001/0819 | f.type = Tversion; f.tag = NOTAG; f.msize = msize; f.version = v; msg = malloc(8192+IOHDRSZ); if(msg == nil) exhausted("version memory"); if(waserror()){ free(msg); nexterror(); } k = convS2M(&f, msg, 8192+IOHDRSZ); if(k == 0) error("bad fversion conversion on send"); lock(c); oo = c->offset; c->offset += k; unlock(c); l = devtab[c->type]->write(c, msg, k, oo); if(l < k){ lock(c); c->offset -= k - l; unlock(c); error("short write in fversion"); } /* message sent; receive and decode reply */ k = devtab[c->type]->read(c, msg, 8192+IOHDRSZ, c->offset); if(k <= 0) error("EOF receiving fversion reply"); lock(c); c->offset += k; unlock(c); l = convM2S(msg, k, &f); if(l != k) error("bad fversion conversion on reply"); | |
| 2001/0918 | if(f.type != Rversion){ if(f.type == Rerror) error(f.ename); | |
| 2001/0819 | error("unexpected reply type in fversion"); | |
| 2001/0918 | } | |
| 2001/0819 | if(f.msize > msize) error("server tries to increase msize in fversion"); if(f.msize<256 || f.msize>1024*1024) error("nonsense value of msize in fversion"); if(strncmp(f.version, v, strlen(f.version)) != 0) error("bad 9P version returned from server"); /* now build Mnt associated with this connection */ lock(&mntalloc); | |
| 1991/0911 | m = mntalloc.mntfree; | |
| 1992/0620 | if(m != 0) | |
| 1998/0512 | mntalloc.mntfree = m->list; | |
| 1992/0620 | else { m = malloc(sizeof(Mnt)); if(m == 0) { unlock(&mntalloc); exhausted("mount devices"); } } m->list = mntalloc.list; mntalloc.list = m; | |
| 2001/0820 | m->version = nil; | |
| 2001/0819 | kstrdup(&m->version, f.version); | |
| 1991/0911 | m->id = mntalloc.id++; | |
| 2001/0619 | m->q = qopen(10*MAXRPC, 0, nil, nil); | |
| 2001/0820 | m->msize = f.msize; | |
| 1991/0911 | unlock(&mntalloc); | |
| 1992/0620 | ||
| 2001/0819 | poperror(); /* msg */ free(msg); | |
| 1997/1205 | lock(m); | |
| 1991/0911 | m->queue = 0; m->rip = 0; | |
| 2001/0819 | c->flag |= CMSG; c->mux = m; | |
| 1992/0620 | m->c = c; | |
| 2001/0819 | unlock(m); | |
| 1991/0911 | ||
| 2001/0819 | poperror(); /* c */ qunlock(&c->umqlock); | |
| 1993/0501 | ||
| 2001/0819 | k = strlen(f.version); if(returnlen > 0){ if(returnlen < k) error(Eshort); memmove(version, f.version, k); } | |
| 1990/0604 | ||
| 2001/0819 | return k; } Chan* mntauth(Chan *c, char *spec) { Mnt *m; Mntrpc *r; m = c->mux; if(m == nil){ mntversion(c, VERSION9P, MAXRPC, 0); m = c->mux; if(m == nil) error(Enoversion); } | |
| 1993/0501 | c = mntchan(); | |
| 1992/0320 | if(waserror()) { | |
| 2001/0527 | /* Close must not be called since it will * call mnt recursively */ chanfree(c); | |
| 1992/0320 | nexterror(); } | |
| 2001/0820 | r = mntralloc(0, m->msize); | |
| 1993/0321 | ||
| 2001/0819 | if(waserror()) { mntfree(r); nexterror(); } | |
| 1993/1016 | ||
| 2001/0819 | r->request.type = Tauth; r->request.afid = c->fid; r->request.uname = up->user; r->request.aname = spec; mountrpc(m, r); | |
| 1990/0604 | ||
| 2001/0819 | c->qid = r->reply.aqid; c->mchan = m->c; incref(m->c); c->mqid = c->qid; c->mode = ORDWR; | |
| 1991/0911 | ||
| 2001/0819 | poperror(); /* r */ mntfree(r); | |
| 1993/0501 | ||
| 2001/0819 | poperror(); /* c */ | |
| 1993/0501 | return c; | |
| 2001/0819 | ||
| 1993/0501 | } | |
| 2001/0819 | static Chan* mntattach(char *muxattach) | |
| 1993/0501 | { | |
| 2001/0819 | Mnt *m; Chan *c; | |
| 1993/0501 | Mntrpc *r; | |
| 2001/0819 | struct bogus{ Chan *chan; Chan *authchan; char *spec; int flags; }bogus; | |
| 1993/0501 | ||
| 2001/0819 | bogus = *((struct bogus *)muxattach); c = bogus.chan; m = c->mux; if(m == nil){ mntversion(c, nil, 0, 0); m = c->mux; if(m == nil) error(Enoversion); } c = mntchan(); if(waserror()) { /* Close must not be called since it will * call mnt recursively */ chanfree(c); nexterror(); } | |
| 2001/0820 | r = mntralloc(0, m->msize); | |
| 1991/0911 | ||
| 1994/1212 | if(waserror()) { | |
| 1992/0314 | mntfree(r); nexterror(); } | |
| 1991/0911 | r->request.type = Tattach; r->request.fid = c->fid; | |
| 2001/0819 | if(bogus.authchan == nil) r->request.afid = NOFID; else r->request.afid = bogus.authchan->fid; | |
| 2001/0527 | r->request.uname = up->user; | |
| 2001/0819 | r->request.aname = bogus.spec; | |
| 1991/0911 | mountrpc(m, r); c->qid = r->reply.qid; c->mchan = m->c; | |
| 2001/0819 | incref(m->c); | |
| 1990/0303 | c->mqid = c->qid; | |
| 1993/0501 | ||
| 2001/0819 | poperror(); /* r */ | |
| 1991/0911 | mntfree(r); | |
| 2001/0819 | poperror(); /* c */ if(bogus.flags&MCACHE) c->flag |= CCACHE; return c; | |
| 1992/0318 | } | |
| 2001/0819 | Chan* mntchan(void) { Chan *c; c = devattach('M', 0); lock(&mntalloc); c->dev = mntalloc.id++; unlock(&mntalloc); if(c->mchan) panic("mntchan non-zero %p", c->mchan); return c; } | |
| 2001/0527 | static Walkqid* mntwalk(Chan *c, Chan *nc, char **name, int nname) | |
| 1990/0227 | { | |
| 2001/0527 | int i, alloc; | |
| 1990/0227 | Mnt *m; | |
| 1991/0911 | Mntrpc *r; | |
| 2001/0527 | Walkqid *wq; | |
| 2001/0601 | ||
| 2001/0819 | if(nc != nil) print("mntwalk: nc != nil\n"); | |
| 2001/0527 | if(nname > MAXWELEM) error("devmnt: too many name elements"); alloc = 0; wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid)); if(waserror()){ if(alloc && wq->clone!=nil) cclose(wq->clone); free(wq); return nil; } alloc = 0; | |
| 1991/0911 | m = mntchk(c); | |
| 2001/0820 | r = mntralloc(c, m->msize); | |
| 2001/0527 | if(nc == nil){ nc = devclone(c); /* * Until the other side accepts this fid, we can't mntclose it. * Therefore set type to 0 for now; rootclose is known to be safe. */ nc->type = 0; | |
| 1991/0911 | alloc = 1; | |
| 1990/0227 | } | |
| 2001/0527 | wq->clone = nc; | |
| 1992/0824 | if(waserror()) { | |
| 1991/0911 | mntfree(r); | |
| 1990/0227 | nexterror(); } | |
| 2001/0527 | r->request.type = Twalk; | |
| 1991/0911 | r->request.fid = c->fid; r->request.newfid = nc->fid; | |
| 2001/0527 | r->request.nwname = nname; memmove(r->request.wname, name, nname*sizeof(char*)); | |
| 1991/0911 | mountrpc(m, r); | |
| 2001/0527 | if(r->reply.nwqid > nname) error("too many QIDs returned by walk"); if(r->reply.nwqid < nname){ if(alloc) cclose(nc); wq->clone = nil; if(r->reply.nwqid == 0){ free(wq); wq = nil; goto Return; } } | |
| 1991/0911 | ||
| 2001/0527 | /* move new fid onto mnt device and update its qid */ if(wq->clone != nil){ if(wq->clone != c){ wq->clone->type = c->type; | |
| 2001/0819 | wq->clone->mchan = c->mchan; incref(c->mchan); | |
| 2001/0527 | } if(r->reply.nwqid > 0) wq->clone->qid = r->reply.wqid[r->reply.nwqid-1]; | |
| 1990/0227 | } | |
| 2001/0527 | wq->nqid = r->reply.nwqid; for(i=0; i<wq->nqid; i++) wq->qid[i] = r->reply.wqid[i]; | |
| 1991/0911 | ||
| 2001/0527 | Return: | |
| 1990/0227 | poperror(); | |
| 1991/0911 | mntfree(r); | |
| 2001/0527 | poperror(); return wq; | |
| 1990/0227 | } | |
| 2001/0527 | static int mntstat(Chan *c, uchar *dp, int n) | |
| 1990/0227 | { Mnt *m; | |
| 1991/0911 | Mntrpc *r; | |
| 1990/0227 | ||
| 2001/0527 | if(n < BIT16SZ) error(Eshortstat); | |
| 1991/0911 | m = mntchk(c); | |
| 2001/0820 | r = mntralloc(c, m->msize); | |
| 1991/0911 | if(waserror()) { mntfree(r); | |
| 1990/0227 | nexterror(); } | |
| 1991/0911 | r->request.type = Tstat; r->request.fid = c->fid; mountrpc(m, r); | |
| 2001/0527 | if(r->reply.nstat >= 1<<(8*BIT16SZ)) error("returned stat buffer count too large"); if(r->reply.nstat > n){ /* doesn't fit; just patch the count and return */ PBIT16((uchar*)dp, r->reply.nstat); n = BIT16SZ; }else{ n = r->reply.nstat; memmove(dp, r->reply.stat, n); validstat(dp, n); mntdirfix(dp, c); } | |
| 1990/0227 | poperror(); | |
| 1991/0911 | mntfree(r); | |
| 2001/0527 | return n; | |
| 1990/0227 | } | |
| 1997/0327 | static Chan* | |
| 2001/0527 | mntopencreate(int type, Chan *c, char *name, int omode, ulong perm) | |
| 1990/0227 | { Mnt *m; | |
| 1991/0911 | Mntrpc *r; | |
| 1990/0227 | ||
| 1991/0911 | m = mntchk(c); | |
| 2001/0820 | r = mntralloc(c, m->msize); | |
| 1991/0911 | if(waserror()) { mntfree(r); | |
| 1990/0227 | nexterror(); } | |
| 2001/0527 | r->request.type = type; | |
| 1991/0911 | r->request.fid = c->fid; r->request.mode = omode; | |
| 2001/0527 | if(type == Tcreate){ r->request.perm = perm; r->request.name = name; } | |
| 1991/0911 | mountrpc(m, r); c->qid = r->reply.qid; | |
| 1990/0227 | c->offset = 0; c->mode = openmode(omode); | |
| 2001/0527 | c->iounit = r->reply.iounit; | |
| 2001/1206 | if(c->iounit == 0 || c->iounit > m->msize-IOHDRSZ) | |
| 2001/0820 | c->iounit = m->msize-IOHDRSZ; | |
| 1990/0227 | c->flag |= COPEN; | |
| 1991/0911 | poperror(); mntfree(r); | |
| 1993/1015 | ||
| 1993/1016 | if(c->flag & CCACHE) | |
| 1993/1015 | copen(c); | |
| 1990/0227 | return c; } | |
| 2001/0527 | static Chan* mntopen(Chan *c, int omode) { return mntopencreate(Topen, c, nil, omode, 0); } | |
| 1998/0512 | static void | |
| 1990/0227 | mntcreate(Chan *c, char *name, int omode, ulong perm) { | |
| 2001/0527 | mntopencreate(Tcreate, c, name, omode, perm); | |
| 1990/0227 | } | |
| 1998/0512 | static void | |
| 1990/0604 | mntclunk(Chan *c, int t) | |
| 1990/0227 | { Mnt *m; | |
| 1991/1004 | Mntrpc *r; | |
| 1998/0512 | ||
| 1991/0911 | m = mntchk(c); | |
| 2001/0820 | r = mntralloc(c, m->msize); | |
| 1991/0911 | if(waserror()){ | |
| 1993/0501 | mntfree(r); | |
| 1991/1004 | nexterror(); | |
| 1991/0911 | } | |
| 1990/0227 | ||
| 1991/0911 | r->request.type = t; r->request.fid = c->fid; mountrpc(m, r); | |
| 1993/0501 | mntfree(r); | |
| 1991/1004 | poperror(); } | |
| 2001/0527 | void | |
| 2001/0819 | muxclose(Mnt *m) | |
| 1991/1004 | { | |
| 1993/0321 | Mntrpc *q, *r; | |
| 1991/1004 | ||
| 1993/0321 | for(q = m->queue; q; q = r) { r = q->list; mntfree(q); } m->id = 0; | |
| 2001/0820 | free(m->version); m->version = nil; | |
| 1993/0321 | mntpntfree(m); } | |
| 2001/0527 | void | |
| 1992/0320 | mntpntfree(Mnt *m) { | |
| 1992/0620 | Mnt *f, **l; | |
| 2001/0619 | Queue *q; | |
| 1992/0620 | ||
| 1992/0320 | lock(&mntalloc); | |
| 1992/0620 | l = &mntalloc.list; for(f = *l; f; f = f->list) { if(f == m) { *l = m->list; break; } l = &f->list; } | |
| 1992/0320 | m->list = mntalloc.mntfree; mntalloc.mntfree = m; | |
| 2001/0619 | q = m->q; | |
| 1992/0320 | unlock(&mntalloc); | |
| 2001/0619 | qfree(q); | |
| 1990/0227 | } | |
| 1997/0327 | static void | |
| 1990/0604 | mntclose(Chan *c) { mntclunk(c, Tclunk); } | |
| 1998/0512 | static void | |
| 1991/0911 | mntremove(Chan *c) | |
| 1990/0227 | { | |
| 1991/0911 | mntclunk(c, Tremove); } | |
| 2001/0527 | static int mntwstat(Chan *c, uchar *dp, int n) | |
| 1991/0911 | { | |
| 1990/0227 | Mnt *m; | |
| 1991/0911 | Mntrpc *r; | |
| 1990/0227 | ||
| 1991/0911 | m = mntchk(c); | |
| 2001/0820 | r = mntralloc(c, m->msize); | |
| 1991/0911 | if(waserror()) { mntfree(r); | |
| 1990/0227 | nexterror(); } | |
| 1991/0911 | r->request.type = Twstat; r->request.fid = c->fid; | |
| 2001/0527 | r->request.nstat = n; r->request.stat = dp; | |
| 1991/0911 | mountrpc(m, r); | |
| 1990/0227 | poperror(); | |
| 1991/0911 | mntfree(r); | |
| 2001/0527 | return n; | |
| 1990/0227 | } | |
| 1998/0512 | static long | |
| 1998/0319 | mntread(Chan *c, void *buf, long n, vlong off) | |
| 1990/0227 | { | |
| 1991/0911 | uchar *p, *e; | |
| 2001/0527 | int nc, cache, isdir, dirlen; | |
| 1990/0227 | ||
| 1995/0204 | isdir = 0; cache = c->flag & CCACHE; | |
| 2001/0527 | if(c->qid.type & QTDIR) { | |
| 1995/0204 | cache = 0; isdir = 1; } | |
| 1995/0129 | p = buf; | |
| 1995/0204 | if(cache) { | |
| 1998/0327 | nc = cread(c, buf, n, off); | |
| 1993/1015 | if(nc > 0) { | |
| 1993/1102 | n -= nc; if(n == 0) return nc; | |
| 1995/0129 | p += nc; | |
| 1998/0327 | off += nc; | |
| 1993/1015 | } | |
| 1998/0327 | n = mntrdwr(Tread, c, p, n, off); cupdate(c, p, n, off); | |
| 1995/0129 | return n + nc; | |
| 1993/1014 | } | |
| 1998/0327 | n = mntrdwr(Tread, c, buf, n, off); | |
| 1995/0204 | if(isdir) { | |
| 2001/0527 | for(e = &p[n]; p+BIT16SZ < e; p += dirlen){ dirlen = BIT16SZ+GBIT16(p); if(p+dirlen > e) break; validstat(p, dirlen); | |
| 1995/0204 | mntdirfix(p, c); | |
| 2001/0527 | } if(p != e) error(Esbadstat); | |
| 1995/0204 | } | |
| 1990/0227 | return n; } | |
| 1998/0512 | static long | |
| 1998/0319 | mntwrite(Chan *c, void *buf, long n, vlong off) | |
| 1990/0227 | { | |
| 1998/0327 | return mntrdwr(Twrite, c, buf, n, off); | |
| 1995/0108 | } | |
| 2001/0527 | long | |
| 1998/0327 | mntrdwr(int type, Chan *c, void *buf, long n, vlong off) | |
| 1995/0129 | { Mnt *m; | |
| 1993/1016 | Mntrpc *r; | |
| 1991/0911 | char *uba; | |
| 1993/1015 | int cache; | |
| 1998/0908 | ulong cnt, nr, nreq; | |
| 1990/0227 | ||
| 1993/1016 | m = mntchk(c); | |
| 1991/0911 | uba = buf; | |
| 1993/0907 | cnt = 0; | |
| 1993/1016 | cache = c->flag & CCACHE; | |
| 2001/0527 | if(c->qid.type & QTDIR) | |
| 1995/0204 | cache = 0; | |
| 1993/0907 | for(;;) { | |
| 2001/0820 | r = mntralloc(c, m->msize); | |
| 1991/0911 | if(waserror()) { mntfree(r); nexterror(); } r->request.type = type; r->request.fid = c->fid; | |
| 1998/0327 | r->request.offset = off; | |
| 1991/0911 | r->request.data = uba; | |
| 2001/0527 | nr = n; | |
| 2001/0820 | if(nr > m->msize-IOHDRSZ) nr = m->msize-IOHDRSZ; | |
| 2001/0527 | r->request.count = nr; | |
| 1991/0911 | mountrpc(m, r); | |
| 1998/0908 | nreq = r->request.count; | |
| 1991/0911 | nr = r->reply.count; | |
| 1998/0908 | if(nr > nreq) nr = nreq; | |
| 1993/1015 | ||
| 1991/0911 | if(type == Tread) | |
| 2001/0619 | r->b = bl2mem((uchar*)uba, r->b, nr); | |
| 1993/1015 | else if(cache) | |
| 1998/0327 | cwrite(c, (uchar*)uba, nr, off); | |
| 1993/1015 | ||
| 1991/0911 | poperror(); mntfree(r); | |
| 1998/0327 | off += nr; | |
| 1991/0911 | uba += nr; cnt += nr; | |
| 1993/0907 | n -= nr; | |
| 1998/0908 | if(nr != nreq || n == 0 || up->nnote) | |
| 1991/0911 | break; | |
| 1990/0227 | } | |
| 1991/0911 | return cnt; | |
| 1990/0227 | } | |
| 2001/0527 | void | |
| 1991/0911 | mountrpc(Mnt *m, Mntrpc *r) | |
| 1990/0604 | { | |
| 2001/0503 | char *sn, *cn; | |
| 1993/0501 | int t; r->reply.tag = 0; | |
| 2000/0102 | r->reply.type = Tmax; /* can't ever be a valid message type */ | |
| 1992/0620 | ||
| 1991/0911 | mountio(m, r); | |
| 1992/0620 | ||
| 1993/0501 | t = r->reply.type; switch(t) { case Rerror: error(r->reply.ename); case Rflush: | |
| 1992/0111 | error(Eintr); | |
| 1993/0501 | default: if(t == r->request.type+1) break; | |
| 2001/0503 | sn = "?"; if(m->c->name != nil) sn = m->c->name->s; cn = "?"; if(r->c != nil && r->c->name != nil) cn = r->c->name->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); | |
| 1992/0113 | error(Emountrpc); | |
| 1990/1123 | } } | |
| 2001/0527 | void | |
| 1991/0911 | mountio(Mnt *m, Mntrpc *r) | |
| 1990/1123 | { | |
| 1991/0911 | int n; | |
| 1990/1124 | ||
| 2000/0105 | while(waserror()) { if(m->rip == up) mntgate(m); | |
| 2001/0924 | if(strcmp(up->errstr, Eintr) != 0){ | |
| 2000/0105 | mntflushfree(m, r); nexterror(); } | |
| 2001/0820 | r = mntflushalloc(r, m->msize); | |
| 2000/0105 | } | |
| 1991/0911 | lock(m); r->m = m; r->list = m->queue; m->queue = r; unlock(m); /* Transmit a file system rpc */ | |
| 2001/0820 | if(m->msize == 0) panic("msize"); n = convS2M(&r->request, r->rpc, m->msize); | |
| 1997/0327 | if(n < 0) panic("bad message type in mountio"); | |
| 2001/0527 | if(devtab[m->c->type]->write(m->c, r->rpc, n, 0) != n) error(Emountrpc); | |
| 2000/0104 | r->stime = fastticks(nil); r->reqlen = n; | |
| 1990/1124 | ||
| 1991/0911 | /* Gate readers onto the mount point one at a time */ for(;;) { lock(m); if(m->rip == 0) break; unlock(m); sleep(&r->r, rpcattn, r); | |
| 2000/0104 | if(r->done){ poperror(); | |
| 2000/0105 | mntflushfree(m, r); | |
| 1991/0911 | return; | |
| 2000/0104 | } | |
| 1990/1124 | } | |
| 1993/0501 | m->rip = up; | |
| 1991/0911 | unlock(m); while(r->done == 0) { | |
| 2001/0527 | if(mntrpcread(m, r) < 0) error(Emountrpc); | |
| 1991/0911 | mountmux(m, r); } mntgate(m); | |
| 2000/0104 | poperror(); | |
| 2000/0105 | mntflushfree(m, r); | |
| 1990/1124 | } | |
| 2001/0527 | int | |
| 1991/0911 | mntrpcread(Mnt *m, Mntrpc *r) | |
| 1990/1124 | { | |
| 2001/0619 | int i, t, len, hlen; Block *b, **l, *nb; | |
| 1992/0505 | ||
| 2001/0527 | r->reply.type = 0; r->reply.tag = 0; | |
| 2001/0619 | /* read at least length, type, and tag and pullup to a single block */ while(qlen(m->q) < BIT32SZ+BIT8SZ+BIT16SZ){ | |
| 2002/0615 | b = devtab[m->c->type]->bread(m->c, m->msize, 0); | |
| 2001/0619 | if(b == nil) return -1; | |
| 2001/0825 | qaddlist(m->q, b); | |
| 2001/0527 | } | |
| 2001/0619 | nb = pullupqueue(m->q, BIT32SZ+BIT8SZ+BIT16SZ); len = GBIT32(nb->rp); /* read in the rest of the message */ while(qlen(m->q) < len){ | |
| 2002/0615 | b = devtab[m->c->type]->bread(m->c, m->msize, 0); | |
| 2001/0619 | if(b == nil) return -1; | |
| 2001/0825 | qaddlist(m->q, b); | |
| 2001/0527 | } | |
| 2001/0619 | /* 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; | |
| 2001/0527 | } | |
| 2001/0619 | nb = pullupqueue(m->q, hlen); | |
| 1992/0503 | ||
| 2001/0619 | if(convM2S(nb->rp, len, &r->reply) <= 0){ /* bad message, dump it */ print("mntrpcread: convM2S failed\n"); qdiscard(m->q, len); | |
| 2001/0527 | return -1; | |
| 1991/0911 | } | |
| 2001/0619 | /* 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); | |
| 2001/0527 | return 0; | |
| 1990/0604 | } | |
| 1990/11211 | ||
| 2001/0527 | void | |
| 1991/0911 | mntgate(Mnt *m) | |
| 1990/0717 | { | |
| 1991/0911 | Mntrpc *q; lock(m); m->rip = 0; | |
| 1993/0501 | for(q = m->queue; q; q = q->list) { | |
| 1997/0220 | if(q->done == 0) if(wakeup(&q->r)) break; | |
| 1993/0501 | } | |
| 1991/0911 | unlock(m); | |
| 1990/0717 | } | |
| 1990/11211 | ||
| 2001/0527 | void | |
| 1991/0911 | mountmux(Mnt *m, Mntrpc *r) | |
| 1990/0227 | { | |
| 1992/0825 | Mntrpc **l, *q; | |
| 1990/0227 | ||
| 1991/0911 | lock(m); l = &m->queue; for(q = *l; q; q = q->list) { | |
| 2000/0105 | /* look for a reply to a message */ | |
| 2000/0104 | if(q->request.tag == r->reply.tag) { | |
| 1991/0911 | *l = q->list; | |
| 1999/0212 | if(q != r) { /* * Completed someone else. * Trade pointers to receive buffer. */ | |
| 1993/0501 | q->reply = r->reply; | |
| 2001/0619 | q->b = r->b; r->b = nil; | |
| 1998/0916 | } | |
| 2000/0102 | q->done = 1; unlock(m); | |
| 2000/0101 | if(mntstats != nil) (*mntstats)(q->request.type, m->c, q->stime, q->reqlen + r->replen); if(q != r) wakeup(&q->r); | |
| 1991/0911 | return; } l = &q->list; | |
| 1990/0227 | } | |
| 1991/0911 | unlock(m); | |
| 2001/0527 | print("unexpected reply tag %ud; type %d\n", r->reply.tag, r->reply.type); | |
| 1991/0911 | } | |
| 1990/0227 | ||
| 2000/0105 | /* * Create a new flush request and chain the previous * requests from it */ | |
| 2001/0527 | Mntrpc* mntflushalloc(Mntrpc *r, ulong iounit) | |
| 1991/0911 | { | |
| 2000/0104 | Mntrpc *fr; | |
| 1990/0511 | ||
| 2001/0527 | fr = mntralloc(0, iounit); | |
| 1990/0511 | ||
| 2000/0104 | fr->request.type = Tflush; if(r->request.type == Tflush) fr->request.oldtag = r->request.oldtag; else fr->request.oldtag = r->request.tag; | |
| 2000/0105 | fr->flushed = r; | |
| 1991/0911 | ||
| 2000/0105 | return fr; } | |
| 2000/0104 | ||
| 2000/0105 | /* * 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. */ | |
| 2001/0527 | void | |
| 2000/0105 | mntflushfree(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; | |
| 1990/03081 | } | |
| 1991/0911 | } | |
| 1991/0901 | ||
| 2001/0527 | Mntrpc* | |
| 2001/0820 | mntralloc(Chan *c, ulong msize) | |
| 1991/0911 | { Mntrpc *new; | |
| 1991/0901 | ||
| 1992/0620 | lock(&mntalloc); new = mntalloc.rpcfree; | |
| 1999/0212 | if(new == nil){ new = malloc(sizeof(Mntrpc)); if(new == nil) { | |
| 1991/0911 | unlock(&mntalloc); | |
| 1999/0212 | exhausted("mount rpc header"); } /* * The header is split from the data buffer as * mountmux may swap the buffer with another header. */ | |
| 2001/0820 | new->rpc = mallocz(msize, 0); | |
| 1999/0212 | if(new->rpc == nil){ free(new); unlock(&mntalloc); | |
| 1992/0620 | exhausted("mount rpc buffer"); | |
| 1991/0911 | } | |
| 2001/0820 | new->rpclen = msize; | |
| 1992/0620 | new->request.tag = mntalloc.rpctag++; | |
| 1991/0904 | } | |
| 1999/0212 | else { mntalloc.rpcfree = new->list; mntalloc.nrpcfree--; | |
| 2001/0820 | if(new->rpclen < msize){ | |
| 2001/0819 | free(new->rpc); | |
| 2001/0820 | new->rpc = mallocz(msize, 0); | |
| 2001/0819 | if(new->rpc == nil){ free(new); mntalloc.nrpcused--; unlock(&mntalloc); exhausted("mount rpc buffer"); } | |
| 2001/0820 | new->rpclen = msize; | |
| 2001/0819 | } | |
| 1999/0212 | } mntalloc.nrpcused++; | |
| 1992/0620 | unlock(&mntalloc); | |
| 1993/0501 | new->c = c; | |
| 1992/0620 | new->done = 0; | |
| 2000/0105 | new->flushed = nil; | |
| 2001/0619 | new->b = nil; | |
| 1992/0620 | return new; | |
| 1991/0911 | } | |
| 2001/0527 | void | |
| 1991/0911 | mntfree(Mntrpc *r) { | |
| 2001/0619 | if(r->b != nil) freeblist(r->b); | |
| 1991/0911 | lock(&mntalloc); | |
| 1999/0212 | if(mntalloc.nrpcfree >= 10){ free(r->rpc); free(r); } else{ r->list = mntalloc.rpcfree; mntalloc.rpcfree = r; mntalloc.nrpcfree++; } mntalloc.nrpcused--; | |
| 1991/0911 | unlock(&mntalloc); } | |
| 2001/0527 | void | |
| 1991/0911 | mntqrm(Mnt *m, Mntrpc *r) { Mntrpc **l, *f; lock(m); r->done = 1; l = &m->queue; for(f = *l; f; f = f->list) { if(f == r) { *l = r->list; break; | |
| 1990/0703 | } | |
| 1991/0911 | l = &f->list; | |
| 1990/0227 | } | |
| 1991/0911 | unlock(m); } | |
| 1990/0227 | ||
| 2001/0527 | Mnt* | |
| 1991/0911 | mntchk(Chan *c) { Mnt *m; | |
| 2001/0819 | /* This routine is mostly vestiges of prior lives; now it's just sanity checking */ | |
| 1993/0501 | ||
| 2001/0819 | if(c->mchan == nil) panic("mntchk 1: nil mchan c %s\n", c2name(c)); m = c->mchan->mux; if(m == nil) print("mntchk 2: nil mux c %s c->mchan %s \n", c2name(c), c2name(c->mchan)); | |
| 1993/0501 | /* | |
| 2001/0819 | * Was it closed and reused (was error(Eshutdown); now, it can't happen) | |
| 1993/0501 | */ if(m->id == 0 || m->id >= c->dev) | |
| 2001/0819 | panic("mntchk 3: can't happen"); | |
| 1993/0501 | ||
| 1991/0911 | return m; | |
| 1990/0717 | } | |
| 2001/0527 | /* * 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. */ void | |
| 1991/0911 | mntdirfix(uchar *dirbuf, Chan *c) { | |
| 2001/0527 | uint r; | |
| 1997/0408 | r = devtab[c->type]->dc; | |
| 2001/0527 | dirbuf += BIT16SZ; /* skip count */ PBIT16(dirbuf, r); dirbuf += BIT16SZ; PBIT32(dirbuf, c->dev); | |
| 1991/0911 | } | |
| 2001/0527 | int | |
| 1999/0320 | rpcattn(void *v) | |
| 1991/0911 | { | |
| 1999/0320 | Mntrpc *r; r = v; | |
| 1991/0911 | return r->done || r->m->rip == 0; } | |
| 1997/0327 | Dev mntdevtab = { | |
| 1997/0409 | 'M', | |
| 1997/0408 | "mnt", | |
| 1997/0327 | mntreset, devinit, | |
| 2002/0109 | devshutdown, | |
| 1997/0327 | mntattach, mntwalk, mntstat, mntopen, mntcreate, mntclose, mntread, devbread, mntwrite, devbwrite, mntremove, mntwstat, }; | |