| plan 9 kernel history: overview | file list | diff list |
1997/1205/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 | ||
| 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 */ Fcall reply; /* Incoming reply */ | |
| 1995/0107 | Mnt* m; /* Mount device during rpc */ | |
| 1991/0911 | Rendez r; /* Place to hang out */ | |
| 1995/0107 | char* rpc; /* I/O Data buffer */ | |
| 1991/0911 | char done; /* Rpc completed */ char flushed; /* Flush was sent */ | |
| 1992/0305 | ushort flushtag; /* Tag flush sent on */ | |
| 1991/0911 | char flush[MAXMSG]; /* Somewhere to build flush */ | |
| 1990/0227 | }; | |
| 1991/0911 | struct Mntalloc | |
| 1990/0227 | { Lock; | |
| 1995/0107 | Mnt* list; /* Mount devices in use */ Mnt* mntfree; /* Free list */ Mntrpc* rpcfree; | |
| 1994/1124 | ulong id; | |
| 1992/0620 | int rpctag; | |
| 1991/0911 | }mntalloc; | |
| 1990/0227 | ||
| 1994/0831 | #define MAXRPC (16*1024+MAXMSG) | |
| 1991/0911 | #define limit(n, max) (n > max ? max : n) | |
| 1990/0227 | ||
| 1993/0501 | void mattach(Mnt*, Chan*, char*); | |
| 1997/0327 | void mntauth(Mnt*, Mntrpc*, char*, ushort); | |
| 1992/0825 | Mnt* mntchk(Chan*); | |
| 1991/0911 | void mntdirfix(uchar*, Chan*); | |
| 1992/0825 | int mntflush(Mnt*, Mntrpc*); void mntfree(Mntrpc*); void mntgate(Mnt*); | |
| 1992/0320 | void mntpntfree(Mnt*); | |
| 1992/0825 | void mntqrm(Mnt*, Mntrpc*); | |
| 1993/0501 | Mntrpc* mntralloc(Chan*); | |
| 1997/0327 | long mntrdwr(int, Chan*, void*, long, ulong); long mnt9prdwr(int, Chan*, void*, long, ulong); | |
| 1992/0825 | void mntrpcread(Mnt*, Mntrpc*); void mountio(Mnt*, Mntrpc*); void mountmux(Mnt*, Mntrpc*); void mountrpc(Mnt*, Mntrpc*); int rpcattn(Mntrpc*); | |
| 1993/0501 | void mclose(Mnt*, Chan*); void mntrecover(Mnt*, Mntrpc*); Chan* mntchan(void); | |
| 1990/0227 | ||
| 1994/0513 | int defmaxmsg = MAXFDATA; | |
| 1991/0911 | enum | |
| 1990/0303 | { | |
| 1993/1011 | Tagspace = 1, Tagfls = 0x8000, Tagend = 0xfffe, | |
| 1991/0911 | }; | |
| 1990/0604 | ||
| 1997/0327 | static void | |
| 1991/0911 | mntreset(void) | |
| 1990/0227 | { | |
| 1991/0911 | mntalloc.id = 1; | |
| 1992/0620 | mntalloc.rpctag = Tagspace; | |
| 1993/1015 | cinit(); | |
| 1990/0604 | } | |
| 1997/0327 | static Chan* | |
| 1991/0911 | mntattach(char *muxattach) | |
| 1990/0227 | { | |
| 1992/0620 | Mnt *m; | |
| 1993/0321 | Chan *c, *mc; | |
| 1993/0501 | char buf[NAMELEN]; | |
| 1990/0227 | struct bogus{ Chan *chan; char *spec; | |
| 1993/1015 | int flags; | |
| 1990/0227 | }bogus; | |
| 1991/0911 | bogus = *((struct bogus *)muxattach); | |
| 1992/0620 | c = bogus.chan; lock(&mntalloc); for(m = mntalloc.list; m; m = m->list) { | |
| 1993/1016 | if(m->c == c && m->id) { | |
| 1991/0911 | lock(m); | |
| 1992/0620 | if(m->id && m->ref > 0 && m->c == c) { | |
| 1991/0911 | m->ref++; unlock(m); | |
| 1997/1205 | unlock(&mntalloc); | |
| 1993/0501 | c = mntchan(); if(waserror()) { chanfree(c); nexterror(); } mattach(m, c, bogus.spec); poperror(); | |
| 1993/1016 | if(bogus.flags&MCACHE) c->flag |= CCACHE; | |
| 1993/0501 | return c; | |
| 1991/0911 | } unlock(m); } | |
| 1991/0901 | } | |
| 1993/1015 | ||
| 1991/0911 | m = mntalloc.mntfree; | |
| 1992/0620 | if(m != 0) mntalloc.mntfree = m->list; else { m = malloc(sizeof(Mnt)); if(m == 0) { unlock(&mntalloc); exhausted("mount devices"); } m->flushbase = Tagfls; m->flushtag = Tagfls; } m->list = mntalloc.list; mntalloc.list = m; | |
| 1991/0911 | m->id = mntalloc.id++; unlock(&mntalloc); | |
| 1992/0620 | ||
| 1997/1205 | lock(m); | |
| 1991/0904 | m->ref = 1; | |
| 1991/0911 | m->queue = 0; m->rip = 0; | |
| 1992/0620 | m->c = c; | |
| 1991/1011 | m->c->flag |= CMSG; | |
| 1995/0508 | if(strncmp(bogus.spec, "mntblk=", 7) == 0) { m->blocksize = strtoul(bogus.spec+7, 0, 0); if(m->blocksize > MAXFDATA) m->blocksize = MAXFDATA; print("mount blk %d\n", m->blocksize); | |
| 1994/0831 | bogus.spec = ""; } else m->blocksize = defmaxmsg; | |
| 1993/1016 | m->flags = bogus.flags & ~MCACHE; | |
| 1991/0911 | incref(m->c); | |
| 1993/0501 | sprint(buf, "#M%d", m->id); m->tree.root = ptenter(&m->tree, 0, buf); | |
| 1990/0227 | unlock(m); | |
| 1990/0604 | ||
| 1993/0501 | c = mntchan(); | |
| 1992/0320 | if(waserror()) { | |
| 1993/0501 | mclose(m, c); /* Close must not be called since it will * call mnt recursively */ chanfree(c); | |
| 1992/0320 | nexterror(); } | |
| 1993/0501 | mattach(m, c, bogus.spec); poperror(); | |
| 1993/0321 | ||
| 1993/0808 | /* * Detect a recursive mount for a mount point served by exportfs. | |
| 1995/0202 | * If CHDIR is clear in the returned qid, the foreign server is | |
| 1993/0808 | * requesting the mount point be folded into the connection * to the exportfs. In this case the remote mount driver does * the multiplexing. */ mc = m->c; | |
| 1993/0323 | if(mc->type == devno('M', 0) && (c->qid.path&CHDIR) == 0) { | |
| 1993/0501 | mclose(m, c); | |
| 1993/0323 | c->qid.path |= CHDIR; | |
| 1993/0321 | c->mntptr = mc->mntptr; | |
| 1993/0501 | c->mchan = c->mntptr->c; | |
| 1993/0321 | c->mqid = c->qid; | |
| 1993/0501 | c->path = c->mntptr->tree.root; incref(c->path); | |
| 1993/0321 | incref(c->mntptr); } | |
| 1993/1016 | if(bogus.flags & MCACHE) c->flag |= CCACHE; | |
| 1992/0320 | return c; | |
| 1991/0911 | } | |
| 1990/0604 | ||
| 1993/0501 | Chan* mntchan(void) | |
| 1991/0911 | { Chan *c; | |
| 1993/0501 | c = devattach('M', 0); | |
| 1991/0918 | lock(&mntalloc); c->dev = mntalloc.id++; unlock(&mntalloc); | |
| 1993/0501 | return c; } void mattach(Mnt *m, Chan *c, char *spec) { ulong id; Mntrpc *r; r = mntralloc(0); | |
| 1992/0620 | c->mntptr = m; | |
| 1991/0911 | ||
| 1994/1212 | if(waserror()) { | |
| 1992/0314 | mntfree(r); nexterror(); } | |
| 1991/0911 | r->request.type = Tattach; r->request.fid = c->fid; | |
| 1993/0501 | memmove(r->request.uname, up->user, NAMELEN); | |
| 1991/0911 | strncpy(r->request.aname, spec, NAMELEN); | |
| 1993/0330 | id = authrequest(m->c->session, &r->request); | |
| 1991/0911 | mountrpc(m, r); | |
| 1993/0330 | authreply(m->c->session, id, &r->reply); | |
| 1991/0911 | c->qid = r->reply.qid; c->mchan = m->c; | |
| 1990/0303 | c->mqid = c->qid; | |
| 1993/0501 | c->path = m->tree.root; incref(c->path); | |
| 1990/0227 | poperror(); | |
| 1991/0911 | mntfree(r); | |
| 1992/0318 | } | |
| 1997/0327 | static Chan* | |
| 1990/0227 | mntclone(Chan *c, Chan *nc) { Mnt *m; | |
| 1991/0911 | Mntrpc *r; int alloc = 0; | |
| 1990/0227 | ||
| 1991/0911 | m = mntchk(c); | |
| 1993/0501 | r = mntralloc(c); | |
| 1991/0911 | if(nc == 0) { | |
| 1990/0227 | nc = newchan(); | |
| 1991/0911 | alloc = 1; | |
| 1990/0227 | } | |
| 1992/0824 | if(waserror()) { | |
| 1991/0911 | mntfree(r); if(alloc) | |
| 1997/0327 | cclose(nc); | |
| 1990/0227 | nexterror(); } | |
| 1991/0911 | r->request.type = Tclone; r->request.fid = c->fid; r->request.newfid = nc->fid; mountrpc(m, r); | |
| 1993/0304 | devclone(c, nc); | |
| 1990/0303 | nc->mqid = c->qid; | |
| 1991/0904 | incref(m); | |
| 1991/0911 | ||
| 1992/0312 | USED(alloc); | |
| 1991/0911 | poperror(); mntfree(r); | |
| 1990/0227 | return nc; } | |
| 1997/0327 | static int | |
| 1990/0227 | mntwalk(Chan *c, char *name) { Mnt *m; | |
| 1993/0501 | Path *op; | |
| 1991/0911 | Mntrpc *r; | |
| 1990/0227 | ||
| 1991/0911 | m = mntchk(c); | |
| 1993/0501 | r = mntralloc(c); | |
| 1991/0911 | if(waserror()) { mntfree(r); return 0; | |
| 1990/0227 | } | |
| 1991/0911 | r->request.type = Twalk; r->request.fid = c->fid; strncpy(r->request.name, name, NAMELEN); mountrpc(m, r); c->qid = r->reply.qid; | |
| 1993/0501 | op = c->path; c->path = ptenter(&m->tree, op, name); | |
| 1993/0808 | ||
| 1993/0501 | decref(op); | |
| 1991/0911 | ||
| 1990/0227 | poperror(); | |
| 1991/0911 | mntfree(r); return 1; | |
| 1990/0227 | } | |
| 1997/0327 | static void | |
| 1990/0227 | mntstat(Chan *c, char *dp) { Mnt *m; | |
| 1991/0911 | Mntrpc *r; | |
| 1990/0227 | ||
| 1991/0911 | m = mntchk(c); | |
| 1993/0501 | r = mntralloc(c); | |
| 1991/0911 | if(waserror()) { mntfree(r); | |
| 1990/0227 | nexterror(); } | |
| 1991/0911 | r->request.type = Tstat; r->request.fid = c->fid; mountrpc(m, r); memmove(dp, r->reply.stat, DIRLEN); mntdirfix((uchar*)dp, c); | |
| 1990/0227 | poperror(); | |
| 1991/0911 | mntfree(r); | |
| 1990/0227 | } | |
| 1997/0327 | static Chan* | |
| 1990/0227 | mntopen(Chan *c, int omode) { Mnt *m; | |
| 1991/0911 | Mntrpc *r; | |
| 1990/0227 | ||
| 1991/0911 | m = mntchk(c); | |
| 1993/0501 | r = mntralloc(c); | |
| 1991/0911 | if(waserror()) { mntfree(r); | |
| 1990/0227 | nexterror(); } | |
| 1991/0911 | r->request.type = Topen; r->request.fid = c->fid; r->request.mode = omode; mountrpc(m, r); c->qid = r->reply.qid; | |
| 1990/0227 | c->offset = 0; c->mode = openmode(omode); c->flag |= COPEN; | |
| 1991/0911 | poperror(); mntfree(r); | |
| 1993/1015 | ||
| 1993/1016 | if(c->flag & CCACHE) | |
| 1993/1015 | copen(c); | |
| 1990/0227 | return c; } | |
| 1997/0327 | static void | |
| 1990/0227 | mntcreate(Chan *c, char *name, int omode, ulong perm) { Mnt *m; | |
| 1991/0911 | Mntrpc *r; | |
| 1990/0227 | ||
| 1991/0911 | m = mntchk(c); | |
| 1993/0501 | r = mntralloc(c); | |
| 1991/0911 | if(waserror()) { mntfree(r); | |
| 1990/0227 | nexterror(); } | |
| 1991/0911 | r->request.type = Tcreate; r->request.fid = c->fid; r->request.mode = omode; r->request.perm = perm; strncpy(r->request.name, name, NAMELEN); mountrpc(m, r); c->qid = r->reply.qid; | |
| 1990/0227 | c->flag |= COPEN; c->mode = openmode(omode); | |
| 1991/0911 | poperror(); mntfree(r); | |
| 1993/1015 | ||
| 1993/1016 | if(c->flag & CCACHE) | |
| 1993/1015 | copen(c); | |
| 1990/0227 | } | |
| 1997/0327 | static void | |
| 1990/0604 | mntclunk(Chan *c, int t) | |
| 1990/0227 | { Mnt *m; | |
| 1991/1004 | Mntrpc *r; | |
| 1991/0911 | m = mntchk(c); | |
| 1993/0501 | r = mntralloc(c); | |
| 1991/0911 | if(waserror()){ | |
| 1993/0501 | mntfree(r); mclose(m, c); | |
| 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); mclose(m, c); | |
| 1991/1004 | poperror(); } void | |
| 1993/0501 | mclose(Mnt *m, Chan *c) | |
| 1991/1004 | { | |
| 1993/0321 | Mntrpc *q, *r; | |
| 1991/1004 | ||
| 1993/0321 | if(decref(m) != 0) return; | |
| 1993/0501 | c->path = 0; ptclose(&m->tree); | |
| 1993/0321 | for(q = m->queue; q; q = r) { r = q->list; q->flushed = 0; mntfree(q); } m->id = 0; | |
| 1997/0327 | cclose(m->c); | |
| 1993/0321 | mntpntfree(m); } void | |
| 1992/0320 | mntpntfree(Mnt *m) { | |
| 1992/0620 | Mnt *f, **l; | |
| 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; unlock(&mntalloc); | |
| 1990/0227 | } | |
| 1997/0327 | static void | |
| 1990/0604 | mntclose(Chan *c) { mntclunk(c, Tclunk); } | |
| 1997/0327 | static void | |
| 1991/0911 | mntremove(Chan *c) | |
| 1990/0227 | { | |
| 1991/0911 | mntclunk(c, Tremove); } | |
| 1997/0327 | static void | |
| 1991/0911 | mntwstat(Chan *c, char *dp) { | |
| 1990/0227 | Mnt *m; | |
| 1991/0911 | Mntrpc *r; | |
| 1990/0227 | ||
| 1991/0911 | m = mntchk(c); | |
| 1993/0501 | r = mntralloc(c); | |
| 1991/0911 | if(waserror()) { mntfree(r); | |
| 1990/0227 | nexterror(); } | |
| 1991/0911 | r->request.type = Twstat; r->request.fid = c->fid; memmove(r->request.stat, dp, DIRLEN); mountrpc(m, r); | |
| 1990/0227 | poperror(); | |
| 1991/0911 | mntfree(r); | |
| 1990/0227 | } long | |
| 1994/0405 | mntread9p(Chan *c, void *buf, long n, ulong offset) { | |
| 1995/0129 | return mnt9prdwr(Tread, c, buf, n, offset); | |
| 1994/0405 | } | |
| 1997/0327 | static long | |
| 1991/0411 | mntread(Chan *c, void *buf, long n, ulong offset) | |
| 1990/0227 | { | |
| 1991/0911 | uchar *p, *e; | |
| 1995/0204 | int nc, cache, isdir; | |
| 1990/0227 | ||
| 1995/0204 | isdir = 0; cache = c->flag & CCACHE; if(c->qid.path & CHDIR) { cache = 0; isdir = 1; } | |
| 1995/0129 | p = buf; | |
| 1995/0204 | if(cache) { | |
| 1993/1015 | nc = cread(c, buf, n, offset); if(nc > 0) { | |
| 1993/1102 | n -= nc; if(n == 0) return nc; | |
| 1995/0129 | p += nc; | |
| 1993/1015 | offset += nc; } | |
| 1995/0129 | n = mntrdwr(Tread, c, p, n, offset); cupdate(c, p, n, offset); return n + nc; | |
| 1993/1014 | } | |
| 1995/0129 | n = mntrdwr(Tread, c, buf, n, offset); | |
| 1995/0204 | if(isdir) { for(e = &p[n]; p < e; p += DIRLEN) mntdirfix(p, c); } | |
| 1993/1014 | ||
| 1990/0227 | return n; } long | |
| 1994/0402 | mntwrite9p(Chan *c, void *buf, long n, ulong offset) { | |
| 1995/0129 | return mnt9prdwr(Twrite, c, buf, n, offset); | |
| 1994/0402 | } | |
| 1997/0327 | static long | |
| 1991/0411 | mntwrite(Chan *c, void *buf, long n, ulong offset) | |
| 1990/0227 | { | |
| 1995/0129 | return mntrdwr(Twrite, c, buf, n, offset); | |
| 1995/0108 | } long | |
| 1995/0129 | mnt9prdwr(int type, Chan *c, void *buf, long n, ulong offset) | |
| 1990/0227 | { | |
| 1993/1016 | Mnt *m; | |
| 1995/0129 | ulong nr; Mntrpc *r; if(n > MAXRPC-32) { if(type == Twrite) error("write9p too long"); n = MAXRPC-32; } m = mntchk(c); r = mntralloc(c); if(waserror()) { mntfree(r); nexterror(); } r->request.type = type; r->request.fid = c->fid; r->request.offset = offset; r->request.data = buf; r->request.count = n; mountrpc(m, r); nr = r->reply.count; if(nr > r->request.count) nr = r->request.count; if(type == Tread) memmove(buf, r->reply.data, nr); poperror(); mntfree(r); return nr; } long mntrdwr(int type, Chan *c, void *buf, long n, ulong offset) { Mnt *m; | |
| 1993/1016 | Mntrpc *r; | |
| 1991/0911 | char *uba; | |
| 1993/1015 | int cache; | |
| 1992/0825 | ulong cnt, nr; | |
| 1990/0227 | ||
| 1993/1016 | m = mntchk(c); | |
| 1991/0911 | uba = buf; | |
| 1993/0907 | cnt = 0; | |
| 1993/1016 | cache = c->flag & CCACHE; | |
| 1995/0206 | if(c->qid.path & CHDIR) | |
| 1995/0204 | cache = 0; | |
| 1993/0907 | for(;;) { | |
| 1993/0501 | r = mntralloc(c); | |
| 1991/0911 | if(waserror()) { mntfree(r); nexterror(); } r->request.type = type; r->request.fid = c->fid; r->request.offset = offset; r->request.data = uba; | |
| 1995/0129 | r->request.count = limit(n, m->blocksize); | |
| 1991/0911 | mountrpc(m, r); nr = r->reply.count; | |
| 1993/0907 | if(nr > r->request.count) nr = r->request.count; | |
| 1993/1015 | ||
| 1991/0911 | if(type == Tread) memmove(uba, r->reply.data, nr); | |
| 1993/1015 | else if(cache) | |
| 1993/1016 | cwrite(c, (uchar*)uba, nr, offset); | |
| 1993/1015 | ||
| 1991/0911 | poperror(); mntfree(r); offset += nr; uba += nr; cnt += nr; | |
| 1993/0907 | n -= nr; | |
| 1993/1102 | if(nr != r->request.count || n == 0 || up->nnote) | |
| 1991/0911 | break; | |
| 1990/0227 | } | |
| 1991/0911 | return cnt; | |
| 1990/0227 | } void | |
| 1991/0911 | mountrpc(Mnt *m, Mntrpc *r) | |
| 1990/0604 | { | |
| 1993/0501 | int t; r->reply.tag = 0; | |
| 1992/0613 | r->reply.type = 4; | |
| 1992/0620 | ||
| 1993/0501 | while(waserror()) { | |
| 1993/1016 | if((m->flags&MRECOV) == 0) | |
| 1993/0501 | nexterror(); mntrecover(m, r); } | |
| 1991/0911 | mountio(m, r); | |
| 1993/0501 | poperror(); | |
| 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; | |
| 1997/0405 | print("mnt: proc %s %d: mismatch rep 0x%lux T%d R%d rq %d fls %d rp %d\n", up->text, up->pid, | |
| 1993/1105 | r, r->request.type, r->reply.type, r->request.tag, | |
| 1993/0501 | r->flushtag, r->reply.tag); | |
| 1992/0113 | error(Emountrpc); | |
| 1990/1123 | } } void | |
| 1991/0911 | mountio(Mnt *m, Mntrpc *r) | |
| 1990/1123 | { | |
| 1991/0911 | int n; | |
| 1990/1124 | ||
| 1991/0911 | lock(m); | |
| 1992/0305 | r->flushed = 0; | |
| 1991/0911 | r->m = m; r->list = m->queue; m->queue = r; unlock(m); /* Transmit a file system rpc */ n = convS2M(&r->request, r->rpc); | |
| 1997/0327 | if(n < 0) panic("bad message type in mountio"); | |
| 1991/0911 | if(waserror()) { | |
| 1991/0925 | if(mntflush(m, r) == 0) nexterror(); | |
| 1991/0911 | } | |
| 1991/0925 | else { | |
| 1997/0408 | if(devtab[m->c->type]->dc == L'M'){ | |
| 1995/0129 | if(mnt9prdwr(Twrite, m->c, r->rpc, n, 0) != n) | |
| 1994/0402 | error(Emountrpc); }else{ | |
| 1997/0327 | if(devtab[m->c->type]->write(m->c, r->rpc, n, 0) != n) | |
| 1994/0402 | error(Emountrpc); } | |
| 1991/0925 | poperror(); } | |
| 1990/1124 | ||
| 1991/0911 | /* Gate readers onto the mount point one at a time */ for(;;) { lock(m); if(m->rip == 0) break; unlock(m); if(waserror()) { if(mntflush(m, r) == 0) nexterror(); continue; } sleep(&r->r, rpcattn, r); poperror(); if(r->done) return; | |
| 1990/1124 | } | |
| 1993/0501 | m->rip = up; | |
| 1991/0911 | unlock(m); while(r->done == 0) { mntrpcread(m, r); mountmux(m, r); } mntgate(m); | |
| 1990/1124 | } void | |
| 1991/0911 | mntrpcread(Mnt *m, Mntrpc *r) | |
| 1990/1124 | { | |
| 1993/1103 | int n; | |
| 1992/0505 | ||
| 1991/0911 | for(;;) { if(waserror()) { if(mntflush(m, r) == 0) { | |
| 1997/0327 | mntgate(m); | |
| 1991/0911 | nexterror(); } continue; | |
| 1990/0604 | } | |
| 1991/0911 | r->reply.type = 0; r->reply.tag = 0; | |
| 1997/0408 | if(devtab[m->c->type]->dc == L'M') | |
| 1995/0129 | n = mnt9prdwr(Tread, m->c, r->rpc, MAXRPC, 0); | |
| 1994/0405 | else | |
| 1997/0327 | n = devtab[m->c->type]->read(m->c, r->rpc, MAXRPC, 0); | |
| 1991/0911 | poperror(); | |
| 1993/1103 | if(n == 0) | |
| 1991/0911 | continue; | |
| 1992/0503 | ||
| 1991/0911 | if(convM2S(r->rpc, &r->reply, n) != 0) return; } | |
| 1990/0604 | } | |
| 1990/11211 | ||
| 1991/0911 | void 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 | ||
| 1990/0604 | void | |
| 1991/0911 | mountmux(Mnt *m, Mntrpc *r) | |
| 1990/0227 | { | |
| 1991/0911 | char *dp; | |
| 1992/0825 | Mntrpc **l, *q; | |
| 1990/0227 | ||
| 1991/0911 | lock(m); l = &m->queue; for(q = *l; q; q = q->list) { | |
| 1992/0305 | if(q->request.tag == r->reply.tag || q->flushed && q->flushtag == r->reply.tag) { | |
| 1991/0911 | *l = q->list; unlock(m); | |
| 1992/0305 | if(q != r) { /* Completed someone else */ dp = q->rpc; q->rpc = r->rpc; r->rpc = dp; | |
| 1993/0501 | q->reply = r->reply; | |
| 1992/0305 | q->done = 1; wakeup(&q->r); }else q->done = 1; | |
| 1991/0911 | return; } l = &q->list; | |
| 1990/0227 | } | |
| 1991/0911 | unlock(m); } | |
| 1990/0227 | ||
| 1991/0911 | int mntflush(Mnt *m, Mntrpc *r) { | |
| 1994/0828 | int n, l; | |
| 1992/0825 | Fcall flush; | |
| 1990/0511 | ||
| 1992/0305 | lock(m); r->flushtag = m->flushtag++; if(m->flushtag == Tagend) m->flushtag = m->flushbase; r->flushed = 1; unlock(m); | |
| 1990/0511 | ||
| 1991/0911 | flush.type = Tflush; flush.tag = r->flushtag; flush.oldtag = r->request.tag; n = convS2M(&flush, r->flush); | |
| 1997/0327 | if(n < 0) panic("bad message type in mntflush"); | |
| 1991/0911 | if(waserror()) { | |
| 1993/0501 | if(strcmp(up->error, Eintr) == 0) | |
| 1991/0911 | return 1; mntqrm(m, r); return 0; | |
| 1990/03081 | } | |
| 1997/0327 | l = devtab[m->c->type]->write(m->c, r->flush, n, 0); | |
| 1994/0828 | if(l != n) error(Ehungup); | |
| 1991/0911 | poperror(); return 1; } | |
| 1991/0901 | ||
| 1997/0327 | Mntrpc* | |
| 1993/0501 | mntralloc(Chan *c) | |
| 1991/0911 | { Mntrpc *new; | |
| 1991/0901 | ||
| 1992/0620 | lock(&mntalloc); new = mntalloc.rpcfree; if(new != 0) mntalloc.rpcfree = new->list; else { new = xalloc(sizeof(Mntrpc)+MAXRPC); if(new == 0) { | |
| 1991/0911 | unlock(&mntalloc); | |
| 1992/0620 | exhausted("mount rpc buffer"); | |
| 1991/0911 | } | |
| 1992/0620 | new->rpc = (char*)new+sizeof(Mntrpc); new->request.tag = mntalloc.rpctag++; | |
| 1991/0904 | } | |
| 1992/0620 | unlock(&mntalloc); | |
| 1993/0501 | new->c = c; | |
| 1992/0620 | new->done = 0; new->flushed = 0; | |
| 1997/0327 | new->flushtag = 0; | |
| 1992/0620 | return new; | |
| 1991/0911 | } void mntfree(Mntrpc *r) { lock(&mntalloc); r->list = mntalloc.rpcfree; mntalloc.rpcfree = r; unlock(&mntalloc); } void mntqrm(Mnt *m, Mntrpc *r) { Mntrpc **l, *f; lock(m); r->done = 1; r->flushed = 0; 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 | ||
| 1993/0501 | void recoverchan(Mnt *m, Chan *c) { int i, n, flg; Path *safe, *p, **pav; if(m->c == 0) error(Eshutdown); flg = c->flag; /* Don't recursively recover */ c->flag &= ~(COPEN|CRECOV); n = 0; for(p = c->path; p; p = p->parent) n++; pav = smalloc(sizeof(Path*)*n); i = n; for(p = c->path; p; p = p->parent) pav[--i] = p; safe = c->path; if(waserror()) { c->flag = flg; free(pav); nexterror(); } /* Attach the fid onto the file server (sets c->path to #Mxxx) */ mattach(m, c, c->xmnt->spec); poperror(); /* * c is now at the root so we free where * the chan was before the server connection was lost */ decref(safe); for(i = 1; i < n; i++) { if(mntwalk(c, pav[i]->elem) == 0) { free(pav); /* Shut down the channel */ c->dev = m->id-1; error(Erecover); } } free(pav); if(flg&COPEN) mntopen(c, c->mode); } | |
| 1997/0327 | Mnt* | |
| 1991/0911 | mntchk(Chan *c) { Mnt *m; | |
| 1992/0620 | m = c->mntptr; | |
| 1993/0501 | /* * Was it closed and reused */ if(m->id == 0 || m->id >= c->dev) | |
| 1990/11211 | error(Eshutdown); | |
| 1993/0501 | /* | |
| 1993/1011 | * Try and get the channel back after a crash | |
| 1993/0501 | */ if((c->flag&CRECOV) && m->recprog == 0) recoverchan(m, c); | |
| 1991/0911 | return m; | |
| 1990/0717 | } | |
| 1990/1220 | void | |
| 1991/0911 | mntdirfix(uchar *dirbuf, Chan *c) { | |
| 1997/0408 | int r; r = devtab[c->type]->dc; dirbuf[DIRLEN-4] = r>>0; dirbuf[DIRLEN-3] = r>>8; | |
| 1991/0911 | dirbuf[DIRLEN-2] = c->dev; dirbuf[DIRLEN-1] = c->dev>>8; } int rpcattn(Mntrpc *r) { return r->done || r->m->rip == 0; | |
| 1993/0501 | } int recdone(Mnt *m) { return m->recprog == 0; } void mntrecdel(Mnt *m, Mntrpc *r) { Mntrpc *f, **l; lock(m); l = &m->recwait; for(f = *l; f; f = f->list) { if(f == r) { *l = r->list; break; } } unlock(m); } void mntrecover(Mnt *m, Mntrpc *r) { char *ps; lock(m); if(m->recprog == 0) { m->recprog = 1; unlock(m); chanrec(m); /* * Send a message to boot via #/recover */ rootrecover(m->c->path, m->tree.root->elem); lock(m); } r->list = m->recwait; m->recwait = r; unlock(m); pprint("lost server connection, wait...\n"); ps = up->psstate; up->psstate = "Recover"; if(waserror()) { up->psstate = ps; mntrecdel(m, r); nexterror(); } sleep(&r->r, recdone, m); poperror(); r->done = 0; mntrecdel(m, r); | |
| 1994/1212 | if(r->c != 0) recoverchan(m, r->c); | |
| 1993/0501 | up->psstate = ps; } void mntrepl(char *buf) { int fd; Mnt *m; char *p; Chan *c1; Mntrpc *r; /* reply from boot is 'fd #M23' */ fd = strtoul(buf, &p, 0); p++; lock(&mntalloc); for(m = mntalloc.list; m; m = m->list) { if(strcmp(p, m->tree.root->elem) == 0) break; } unlock(&mntalloc); if(m == 0) error(Eunmount); c1 = fdtochan(fd, ORDWR, 0, 1); /* error check and inc ref */ /* If the channel was posted fix it up */ srvrecover(m->c, c1); lock(m); | |
| 1997/0327 | cclose(m->c); | |
| 1993/0501 | m->c = c1; m->recprog = 0; /* Wakeup partially complete rpc */ for(r = m->recwait; r; r = r->list) wakeup(&r->r); unlock(m); | |
| 1991/0911 | } | |
| 1997/0327 | Dev mntdevtab = { | |
| 1997/0409 | 'M', | |
| 1997/0408 | "mnt", | |
| 1997/0327 | mntreset, devinit, mntattach, mntclone, mntwalk, mntstat, mntopen, mntcreate, mntclose, mntread, devbread, mntwrite, devbwrite, mntremove, mntwstat, }; | |