]> git.lizzy.rs Git - plan9front.git/blobdiff - sys/src/9/port/devmnt.c
kernel: use 64-bit virtual entry point for expanded header, document behaviour in...
[plan9front.git] / sys / src / 9 / port / devmnt.c
index d073b70642a5361536aea727d39b222aec672874..a132b9a6ea21f0ffa3de4fb721d3b20e0485d0cb 100644 (file)
@@ -26,63 +26,59 @@ struct Mntrpc
        Fcall   reply;          /* Incoming reply */
        Mnt*    m;              /* Mount device during rpc */
        Rendez* z;              /* Place to hang out */
-       uchar*  rpc;            /* I/O Data buffer */
-       uint    rpclen;         /* len of buffer */
+       Block*  w;              /* copy of write rpc for cache */
        Block*  b;              /* reply blocks */
-       uvlong  stime;          /* start time for mnt statistics */
-       ulong   reqlen;         /* request length for mnt statistics */
-       ulong   replen;         /* reply length for mnt statistics */
        Mntrpc* flushed;        /* message this one flushes */
        char    done;           /* Rpc completed */
 };
 
 enum
 {
-       TAGSHIFT = 5,                   /* ulong has to be 32 bits */
+       TAGSHIFT = 5,
        TAGMASK = (1<<TAGSHIFT)-1,
        NMASK = (64*1024)>>TAGSHIFT,
 };
 
-struct Mntalloc
+static struct Mntalloc
 {
        Lock;
        Mnt*    list;           /* Mount devices in use */
        Mnt*    mntfree;        /* Free list */
        Mntrpc* rpcfree;
-       int     nrpcfree;
-       int     nrpcused;
+       ulong   nrpcfree;
+       ulong   nrpcused;
        ulong   id;
-       ulong   tagmask[NMASK];
-}mntalloc;
-
-Mnt*   mntchk(Chan*);
-void   mntdirfix(uchar*, Chan*);
-Mntrpc*        mntflushalloc(Mntrpc*, ulong);
-void   mntflushfree(Mnt*, Mntrpc*);
-void   mntfree(Mntrpc*);
-void   mntgate(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);
+       u32int  tagmask[NMASK];
+} mntalloc;
+
+static Chan*   mntchan(void);
+static Mnt*    mntchk(Chan*);
+static void    mntdirfix(uchar*, Chan*);
+static Mntrpc* mntflushalloc(Mntrpc*);
+static Mntrpc* mntflushfree(Mnt*, Mntrpc*);
+static void    mntfree(Mntrpc*);
+static void    mntgate(Mnt*);
+static void    mntqrm(Mnt*, Mntrpc*);
+static Mntrpc* mntralloc(Chan*);
+static long    mntrdwr(int, Chan*, void*, long, vlong);
+static int     mntrpcread(Mnt*, Mntrpc*);
+static void    mountio(Mnt*, Mntrpc*);
+static void    mountmux(Mnt*, Mntrpc*);
+static void    mountrpc(Mnt*, Mntrpc*);
+static int     rpcattn(void*);
+
+#define cachedchan(c) (((c)->flag & CCACHE) != 0 && (c)->mcp != nil)
 
 char   Esbadstat[] = "invalid directory entry received from server";
 char   Enoversion[] = "version not established for mount channel";
 
-void   (*mntstats)(int, Chan*, uvlong, ulong);
-
 
 static void
 mntreset(void)
 {
        mntalloc.id = 1;
        mntalloc.tagmask[0] = 1;                        /* don't allow 0 as a tag */
-       mntalloc.tagmask[NMASK-1] = 0x80000000UL;       /* don't allow NOTAG */
+       mntalloc.tagmask[NMASK-1] = 0x80000000;         /* don't allow NOTAG */
        fmtinstall('F', fcallfmt);
        fmtinstall('D', dirfmt);
 /* We can't install %M since eipfmt does and is used in the kernel [sape] */
@@ -93,7 +89,7 @@ mntreset(void)
 /*
  * Version is not multiplexed: message sent only once per connection.
  */
-long
+int
 mntversion(Chan *c, char *version, int msize, int returnlen)
 {
        Fcall f;
@@ -167,7 +163,6 @@ mntversion(Chan *c, char *version, int msize, int returnlen)
        unlock(c);
 
        l = devtab[c->type]->write(c, msg, k, oo);
-
        if(l < k){
                lock(c);
                c->offset -= k - l;
@@ -176,13 +171,14 @@ mntversion(Chan *c, char *version, int msize, int returnlen)
        }
 
        /* 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);
+       for(k = 0; k < BIT32SZ || (k < GBIT32(msg) && k < 8192+IOHDRSZ); k += l){
+               l = devtab[c->type]->read(c, msg+k, 8192+IOHDRSZ-k, c->offset);
+               if(l <= 0)
+                       error("EOF receiving fversion reply");
+               lock(c);
+               c->offset += l;
+               unlock(c);
+       }
 
        l = convM2S(msg, k, &f);
        if(l != k)
@@ -213,16 +209,17 @@ mntversion(Chan *c, char *version, int msize, int returnlen)
        /* now build Mnt associated with this connection */
        lock(&mntalloc);
        m = mntalloc.mntfree;
-       if(m != 0)
+       if(m != nil)
                mntalloc.mntfree = m->list;
        else {
+               unlock(&mntalloc);
                m = malloc(sizeof(Mnt));
-               if(m == 0) {
+               if(m == nil) {
                        qfree(q);
                        free(v);
-                       unlock(&mntalloc);
                        exhausted("mount devices");
                }
+               lock(&mntalloc);
        }
        m->list = mntalloc.list;
        mntalloc.list = m;
@@ -239,8 +236,8 @@ mntversion(Chan *c, char *version, int msize, int returnlen)
        free(msg);
 
        lock(m);
-       m->queue = 0;
-       m->rip = 0;
+       m->queue = nil;
+       m->rip = nil;
 
        c->flag |= CMSG;
        c->mux = m;
@@ -260,9 +257,8 @@ mntauth(Chan *c, char *spec)
        Mntrpc *r;
 
        m = c->mux;
-
        if(m == nil){
-               mntversion(c, VERSION9P, MAXRPC, 0);
+               mntversion(c, nil, 0, 0);
                m = c->mux;
                if(m == nil)
                        error(Enoversion);
@@ -277,8 +273,7 @@ mntauth(Chan *c, char *spec)
                nexterror();
        }
 
-       r = mntralloc(0, m->msize);
-
+       r = mntralloc(c);
        if(waserror()) {
                mntfree(r);
                nexterror();
@@ -295,6 +290,7 @@ mntauth(Chan *c, char *spec)
        incref(m->c);
        c->mqid = c->qid;
        c->mode = ORDWR;
+       c->iounit = m->msize-IOHDRSZ;
 
        poperror();     /* r */
        mntfree(r);
@@ -305,24 +301,16 @@ mntauth(Chan *c, char *spec)
 
 }
 
-static Chan*
-mntattach(char *muxattach)
+Chan*
+mntattach(Chan *c, Chan *ac, char *spec, int flags)
 {
        Mnt *m;
-       Chan *c;
        Mntrpc *r;
-       struct bogus{
-               Chan    *chan;
-               Chan    *authchan;
-               char    *spec;
-               int     flags;
-       }bogus;
 
-       bogus = *((struct bogus *)muxattach);
-       c = bogus.chan;
+       if(ac != nil && ac->mchan != c)
+               error(Ebadusefd);
 
        m = c->mux;
-
        if(m == nil){
                mntversion(c, nil, 0, 0);
                m = c->mux;
@@ -339,21 +327,19 @@ mntattach(char *muxattach)
                nexterror();
        }
 
-       r = mntralloc(0, m->msize);
-
+       r = mntralloc(c);
        if(waserror()) {
                mntfree(r);
                nexterror();
        }
-
        r->request.type = Tattach;
        r->request.fid = c->fid;
-       if(bogus.authchan == nil)
+       if(ac == nil)
                r->request.afid = NOFID;
        else
-               r->request.afid = bogus.authchan->fid;
+               r->request.afid = ac->fid;
        r->request.uname = up->user;
-       r->request.aname = bogus.spec;
+       r->request.aname = spec;
        mountrpc(m, r);
 
        c->qid = r->reply.qid;
@@ -366,12 +352,19 @@ mntattach(char *muxattach)
 
        poperror();     /* c */
 
-       if(bogus.flags&MCACHE)
+       if(flags&MCACHE)
                c->flag |= CCACHE;
        return c;
 }
 
-Chan*
+static Chan*
+noattach(char *)
+{
+       error(Enoattach);
+       return nil;
+}
+
+static Chan*
 mntchan(void)
 {
        Chan *c;
@@ -381,7 +374,7 @@ mntchan(void)
        c->dev = mntalloc.id++;
        unlock(&mntalloc);
 
-       if(c->mchan)
+       if(c->mchan != nil)
                panic("mntchan non-zero %p", c->mchan);
        return c;
 }
@@ -409,7 +402,7 @@ mntwalk(Chan *c, Chan *nc, char **name, int nname)
 
        alloc = 0;
        m = mntchk(c);
-       r = mntralloc(c, m->msize);
+       r = mntralloc(c);
        if(nc == nil){
                nc = devclone(c);
                /*
@@ -477,7 +470,7 @@ mntstat(Chan *c, uchar *dp, int n)
        if(n < BIT16SZ)
                error(Eshortstat);
        m = mntchk(c);
-       r = mntralloc(c, m->msize);
+       r = mntralloc(c);
        if(waserror()) {
                mntfree(r);
                nexterror();
@@ -507,7 +500,7 @@ mntopencreate(int type, Chan *c, char *name, int omode, ulong perm)
        Mntrpc *r;
 
        m = mntchk(c);
-       r = mntralloc(c, m->msize);
+       r = mntralloc(c);
        if(waserror()) {
                mntfree(r);
                nexterror();
@@ -531,8 +524,11 @@ mntopencreate(int type, Chan *c, char *name, int omode, ulong perm)
        poperror();
        mntfree(r);
 
-       if(c->flag & CCACHE)
-               copen(c);
+       if(c->flag & CCACHE){
+               if(copen(c))
+               if(type == Tcreate || (omode&OTRUNC) != 0)
+                       ctrunc(c);
+       }
 
        return c;
 }
@@ -555,13 +551,13 @@ mntclunk(Chan *c, int t)
        Mnt *m;
        Mntrpc *r;
 
+       cclunk(c);
        m = mntchk(c);
-       r = mntralloc(c, m->msize);
-       if(waserror()){
+       r = mntralloc(c);
+       if(waserror()) {
                mntfree(r);
                nexterror();
        }
-
        r->request.type = t;
        r->request.fid = c->fid;
        mountrpc(m, r);
@@ -587,7 +583,7 @@ muxclose(Mnt *m)
 
        lock(&mntalloc);
        l = &mntalloc.list;
-       for(f = *l; f; f = f->list) {
+       for(f = *l; f != nil; f = f->list) {
                if(f == m) {
                        *l = m->list;
                        break;
@@ -618,7 +614,7 @@ mntwstat(Chan *c, uchar *dp, int n)
        Mntrpc *r;
 
        m = mntchk(c);
-       r = mntralloc(c, m->msize);
+       r = mntralloc(c);
        if(waserror()) {
                mntfree(r);
                nexterror();
@@ -630,6 +626,11 @@ mntwstat(Chan *c, uchar *dp, int n)
        mountrpc(m, r);
        poperror();
        mntfree(r);
+
+       if(c->flag & CCACHE)
+       if(GBIT64(&dp[STATFIXLEN-4*BIT16SZ-BIT64SZ]) != ~0ULL)
+               ctrunc(c);
+
        return n;
 }
 
@@ -637,32 +638,11 @@ static long
 mntread(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;
-       }
+       int dirlen;
 
        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) {
+       n = mntrdwr(Tread, c, p, n, off);
+       if(c->qid.type & QTDIR) {
                for(e = &p[n]; p+BIT16SZ < e; p += dirlen){
                        dirlen = BIT16SZ+GBIT16(p);
                        if(p+dirlen > e)
@@ -682,23 +662,69 @@ mntwrite(Chan *c, void *buf, long n, vlong off)
        return mntrdwr(Twrite, c, buf, n, off);
 }
 
-long
+static void
+mntcache(Mntrpc *r)
+{
+       ulong n, m;
+       vlong off;
+       Block *b;
+       Chan *c;
+
+       c = r->c;
+       if(!cachedchan(c))
+               return;
+       off = r->request.offset;
+       switch(r->reply.type){
+       case Rread:
+               m = r->reply.count;
+               if(m > r->request.count)
+                       m = r->request.count;
+               for(b = r->b; m > 0 && b != nil; m -= n, b = b->next) {
+                       n = BLEN(b);
+                       if(m < n)
+                               n = m;
+                       cupdate(c, b->rp, n, off);
+                       off += n;
+               }
+               break;
+       case Rwrite:
+               b = r->w;
+               if(convM2S(b->rp, BLEN(b), &r->request) == 0)
+                       panic("convM2S");
+               m = r->reply.count;
+               if(m > r->request.count)
+                       m = r->request.count;
+               cwrite(c, (uchar*)r->request.data, m, off);
+               break;
+       }
+}
+
+static long
 mntrdwr(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);
+               nreq = n;
+               if(nreq > c->iounit)
+                       nreq = c->iounit;
+
+               if(type == Tread && cachedchan(c)) {
+                       nr = cread(c, (uchar*)uba, nreq, off);
+                       if(nr > 0) {
+                               nreq = nr;
+                               goto Next;
+                       }
+               }
+
+               r = mntralloc(c);
                if(waserror()) {
                        mntfree(r);
                        nexterror();
@@ -707,23 +733,18 @@ mntrdwr(int type, Chan *c, void *buf, long n, vlong off)
                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;
+               r->request.count = nreq;
                mountrpc(m, r);
-               nreq = r->request.count;
+               mntcache(r);
                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();
+                       nr = readblist(r->b, (uchar*)uba, nr, 0);
                mntfree(r);
+               poperror();
+
+       Next:
                off += nr;
                uba += nr;
                cnt += nr;
@@ -734,10 +755,232 @@ mntrdwr(int type, Chan *c, void *buf, long n, vlong off)
        return cnt;
 }
 
+static int
+mntprocwork(void *a)
+{
+       Mntproc *p = a;
+       return p->f != nil;
+}
+
+static void
+mntproc(void *a)
+{
+       Mntproc *p = a;
+       Chan *c;
+       Mnt *m;
+
+       while(waserror())
+               ;
+
+       m = p->m;
+       for(;;){
+               tsleep(p, mntprocwork, p, 500);
+
+               lock(m);
+               if(p->f == nil){
+                       p->m = nil;
+                       unlock(m);
+                       pexit("no work", 1);
+               }
+               c = p->r->c;
+               unlock(m);
+
+               (*p->f)(p->r, p->a);
+
+               lock(m);
+               p->r = nil;
+               p->a = nil;
+               p->f = nil;
+               unlock(m);
+
+               cclose(c);
+       }
+}
+
+static int
+mntdefer(void (*f)(Mntrpc*, void*), Mntrpc *r, void *a)
+{
+       Mntproc *p;
+       Mnt *m;
+       int i;
+
+       m = mntchk(r->c);
+       lock(m);
+       for(i = 0; i < nelem(m->defered); i++){
+               p = &m->defered[i];
+               if(p->f != nil)
+                       continue;
+
+               incref(r->c);
+               r->m = m;
+               p->r = r;
+               p->a = a;
+               p->f = f;
+
+               if(p->m == nil){
+                       p->m = m;
+                       unlock(m);
+                       kproc("mntproc", mntproc, p);
+               } else {
+                       unlock(m);
+                       wakeup(p);
+               }
+               return 1;
+       }
+       unlock(m);
+       return 0;
+}
+
+static void
+rahproc(Mntrpc *r, void *a)
+{
+       Mntrah *rah = a;
+
+       if(!waserror()){
+               mountrpc(r->m, r);
+               poperror();
+       }
+       r->done = 2;
+       wakeup(rah);
+}
+
+static int
+rahdone(void *v)
+{
+       Mntrpc *r = v;
+       return r->done == 2;
+}
+
+static Mntrpc*
+rahfindrpc(Mntrah *rah, vlong off)
+{
+       Mntrpc *r;
+       int i, n;
+       vlong o;
+
+       for(i=0; i<nelem(rah->r); i++){
+               if((r = rah->r[i]) == nil)
+                       continue;
+               n = r->request.count;
+               o = r->request.offset;
+               if(off >= o && off < o+n)
+                       return r;
+       }
+       return nil;
+}
+
 void
+mntrahinit(Mntrah *rah)
+{
+       Mntrpc *r;
+       int i;
+
+       while(waserror())
+               ;
+
+       for(i=0; i<nelem(rah->r); i++){
+               if((r = rah->r[i]) != nil){
+                       while(!rahdone(r))
+                               sleep(rah, rahdone, r);
+                       rah->r[i] = nil;
+                       mntfree(r);
+               }
+       }
+       rah->i = 0;
+
+       rah->off = 0;
+       rah->seq = 0;
+
+       poperror();
+}
+
+long
+mntrahread(Mntrah *rah, Chan *c, uchar *buf, long len, vlong off)
+{
+       Mntrpc *r, **rr;
+       vlong o, w, e;
+       long n, tot;
+
+       if(len <= 0)
+               return 0;
+       if(off != rah->off){
+               rah->off = off;
+               if(rahfindrpc(rah, off) == nil)
+                       rah->seq = 0;
+       }
+       rah->off += len;
+       rah->seq += len;
+       if(rah->seq >= 2*c->iounit){
+               w = (off / c->iounit) * c->iounit;
+               e = w + rah->seq;
+               for(o = w; o < e; o += c->iounit){
+                       if(rahfindrpc(rah, o) != nil)
+                               continue;
+
+                       rr = &rah->r[rah->i % nelem(rah->r)];
+                       if((r = *rr) != nil){
+                               if(!rahdone(r) || (r->request.offset >= w && r->request.offset < e))
+                                       break;
+                               *rr = nil;
+                               mntfree(r);
+                       }
+
+                       r = mntralloc(c);
+                       r->request.type = Tread;
+                       r->request.fid = c->fid;
+                       r->request.offset = o;
+                       r->request.count = c->iounit;
+                       if(!mntdefer(rahproc, r, rah)){
+                               mntfree(r);
+                               break;
+                       }
+                       *rr = r;
+                       rah->i++;
+               }
+       }
+
+       tot = 0;
+       while(len > 0 && (r = rahfindrpc(rah, off)) != nil){
+               while(!rahdone(r))
+                       sleep(rah, rahdone, r);
+
+               switch(r->reply.type){
+               default:
+                       error(Emountrpc);
+               case Rflush:
+                       error(Eintr);
+               case Rerror:
+                       error(r->reply.ename);
+               case Rread:
+                       break;
+               }
+               mntcache(r);
+               n = r->request.count;
+               o = r->request.offset;
+               if(r->reply.count < n)
+                       n = r->reply.count;
+               n -= (off - o);
+               if(n <= 0)
+                       break;
+               if(len < n)
+                       n = len;
+               n = readblist(r->b, buf, n, off - o);
+               buf += n;
+               off += n;
+               tot += n;
+               len -= n;
+       }
+       if(tot > 0){
+               rah->off -= len;
+               rah->seq -= len;
+       }
+
+       return tot;
+}
+
+static void
 mountrpc(Mnt *m, Mntrpc *r)
 {
-       char *sn, *cn;
        int t;
 
        r->reply.tag = 0;
@@ -754,29 +997,25 @@ mountrpc(Mnt *m, Mntrpc *r)
        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 %#p tag %d fid %d T%d R%d rp %d\n",
-                       up->text, up->pid, sn, cn,
+                       up->text, up->pid, chanpath(m->c), chanpath(r->c),
                        r, r->request.tag, r->request.fid, r->request.type,
                        r->reply.type, r->reply.tag);
                error(Emountrpc);
        }
 }
 
-void
+static void
 mountio(Mnt *m, Mntrpc *r)
 {
+       Block *b;
        int n;
 
        while(waserror()) {
                if(m->rip == up)
                        mntgate(m);
-               if(strcmp(up->errstr, Eintr) != 0){
+               if(strcmp(up->errstr, Eintr) != 0 || waserror()){
+                       r = mntflushfree(m, r);
                        switch(r->request.type){
                        case Tremove:
                        case Tclunk:
@@ -784,10 +1023,10 @@ mountio(Mnt *m, Mntrpc *r)
                                if(strcmp(up->errstr, Ehungup) != 0)
                                        r->c->fid = 0;
                        }
-                       mntflushfree(m, r);
                        nexterror();
                }
-               r = mntflushalloc(r, m->msize);
+               r = mntflushalloc(r);
+               poperror();
        }
 
        lock(m);
@@ -798,28 +1037,32 @@ mountio(Mnt *m, Mntrpc *r)
        unlock(m);
 
        /* Transmit a file system rpc */
-       if(m->msize == 0)
-               panic("msize");
-       n = convS2M(&r->request, r->rpc, m->msize);
-       if(n <= 0){
+       n = sizeS2M(&r->request);
+       b = allocb(n);
+       if(waserror()){
+               freeb(b);
+               nexterror();
+       }
+       n = convS2M(&r->request, b->wp, n);
+       if(n <= 0 || n > m->msize) {
                print("mountio: proc %s %lud: convS2M returned %d for tag %d fid %d T%d\n",
                        up->text, up->pid, n, r->request.tag, r->request.fid, r->request.type);
                error(Emountrpc);
        }
-               
-       if(devtab[m->c->type]->write(m->c, r->rpc, n, 0) != n)
-               error(Emountrpc);
-       r->stime = fastticks(nil);
-       r->reqlen = n;
+       b->wp += n;
+       if(r->request.type == Twrite && cachedchan(r->c))
+               r->w = copyblock(b, n);
+       poperror();
+       devtab[m->c->type]->bwrite(m->c, b, 0);
 
        /* Gate readers onto the mount point one at a time */
        for(;;) {
                lock(m);
-               if(m->rip == 0)
+               if(m->rip == nil)
                        break;
                unlock(m);
                sleep(r->z, rpcattn, r);
-               if(r->done){
+               if(r->done) {
                        poperror();
                        mntflushfree(m, r);
                        return;
@@ -844,18 +1087,13 @@ doread(Mnt *m, int len)
 
        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);
+               if(b == nil || qaddlist(m->q, b) == 0)
                        return -1;
-               }
-               qaddlist(m->q, b);
        }
        return 0;
 }
 
-int
+static int
 mntrpcread(Mnt *m, Mntrpc *r)
 {
        int i, t, len, hlen;
@@ -927,14 +1165,14 @@ mntrpcread(Mnt *m, Mntrpc *r)
        return 0;
 }
 
-void
+static void
 mntgate(Mnt *m)
 {
        Mntrpc *q;
 
        lock(m);
-       m->rip = 0;
-       for(q = m->queue; q; q = q->list) {
+       m->rip = nil;
+       for(q = m->queue; q != nil; q = q->list) {
                if(q->done == 0)
                if(wakeup(q->z))
                        break;
@@ -942,7 +1180,7 @@ mntgate(Mnt *m)
        unlock(m);
 }
 
-void
+static void
 mountmux(Mnt *m, Mntrpc *r)
 {
        Mntrpc **l, *q;
@@ -950,48 +1188,46 @@ mountmux(Mnt *m, Mntrpc *r)
 
        lock(m);
        l = &m->queue;
-       for(q = *l; q; q = q->list) {
+       for(q = *l; q != nil; q = q->list) {
                /* look for a reply to a message */
                if(q->request.tag == r->reply.tag) {
                        *l = q->list;
-                       if(mntstats != nil)
-                               (*mntstats)(q->request.type,
-                                       m->c, q->stime,
-                                       q->reqlen + r->replen);
-                       if(q != r) {
-                               /*
-                                * Completed someone else.
-                                * Trade pointers to receive buffer.
-                                */
-                               q->reply = r->reply;
-                               q->b = r->b;
-                               r->b = nil;
-                               z = q->z;
-                       } else
-                               z = nil;
-                       q->done = 1;    /* hands off */
-                       if(z != nil)
-                               wakeup(z);
+                       if(q == r) {
+                               q->done = 1;
+                               unlock(m);
+                               return;
+                       }
+                       /*
+                        * Completed someone else.
+                        * Trade pointers to receive buffer.
+                        */
+                       q->reply = r->reply;
+                       q->b = r->b;
+                       r->b = nil;
+                       z = q->z;
+                       coherence();
+                       q->done = 1;
+                       wakeup(z);
                        unlock(m);
                        return;
                }
                l = &q->list;
        }
        unlock(m);
-       print("unexpected reply tag %ud; type %d\n", r->reply.tag, r->reply.type);
+       print("mnt: unexpected reply from %s tag %ud; type %d\n",
+               chanpath(m->c), r->reply.tag, r->reply.type);
 }
 
 /*
  * Create a new flush request and chain the previous
  * requests from it
  */
-Mntrpc*
-mntflushalloc(Mntrpc *r, ulong iounit)
+static Mntrpc*
+mntflushalloc(Mntrpc *r)
 {
        Mntrpc *fr;
 
-       fr = mntralloc(0, iounit);
-
+       fr = mntralloc(r->c);
        fr->request.type = Tflush;
        if(r->request.type == Tflush)
                fr->request.oldtag = r->request.oldtag;
@@ -1007,91 +1243,73 @@ mntflushalloc(Mntrpc *r, ulong iounit)
  *  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.
+ *  Rflush. Return the original rpc.
  */
-void
+static Mntrpc*
 mntflushfree(Mnt *m, Mntrpc *r)
 {
        Mntrpc *fr;
 
-       while(r){
+       while(r != nil){
                fr = r->flushed;
                if(!r->done){
                        r->reply.type = Rflush;
                        mntqrm(m, r);
                }
-               if(fr)
-                       mntfree(r);
+               if(fr == nil)
+                       break;
+               mntfree(r);
                r = fr;
        }
+       return r;
 }
 
-int
+static int
 alloctag(void)
 {
        int i, j;
-       ulong v;
+       u32int v;
 
        for(i = 0; i < NMASK; i++){
                v = mntalloc.tagmask[i];
-               if(v == ~0UL)
+               if(v == -1)
                        continue;
-               for(j = 0; j < 1<<TAGSHIFT; j++)
-                       if((v & (1<<j)) == 0){
-                               mntalloc.tagmask[i] |= 1<<j;
-                               return (i<<TAGSHIFT) + j;
-                       }
+               for(j = 0; (v & 1) != 0; j++)
+                       v >>= 1;
+               mntalloc.tagmask[i] |= 1<<j;
+               return i<<TAGSHIFT | j;
        }
        panic("no friggin tags left");
        return NOTAG;
 }
 
-void
+static void
 freetag(int t)
 {
        mntalloc.tagmask[t>>TAGSHIFT] &= ~(1<<(t&TAGMASK));
 }
 
-Mntrpc*
-mntralloc(Chan *c, ulong msize)
+static Mntrpc*
+mntralloc(Chan *c)
 {
        Mntrpc *new;
 
-       lock(&mntalloc);
-       new = mntalloc.rpcfree;
-       if(new == nil){
+       if(mntalloc.nrpcfree == 0) {
+       Alloc:
                new = malloc(sizeof(Mntrpc));
-               if(new == nil) {
-                       unlock(&mntalloc);
+               if(new == nil)
                        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);
+               lock(&mntalloc);
+               new->request.tag = alloctag();
+       } else {
+               lock(&mntalloc);
+               new = mntalloc.rpcfree;
+               if(new == nil) {
                        unlock(&mntalloc);
-                       exhausted("mount rpc buffer");
+                       goto Alloc;
                }
-               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);
-                               exhausted("mount rpc buffer");
-                       }
-                       new->rpclen = msize;
-               }
        }
        mntalloc.nrpcused++;
        unlock(&mntalloc);
@@ -1099,30 +1317,30 @@ mntralloc(Chan *c, ulong msize)
        new->done = 0;
        new->flushed = nil;
        new->b = nil;
+       new->w = nil;
        return new;
 }
 
-void
+static void
 mntfree(Mntrpc *r)
 {
-       if(r->b != nil)
-               freeblist(r->b);
+       freeb(r->w);
+       freeblist(r->b);
        lock(&mntalloc);
-       if(mntalloc.nrpcfree >= 10){
-               free(r->rpc);
-               freetag(r->request.tag);
-               free(r);
-       }
-       else{
+       mntalloc.nrpcused--;
+       if(mntalloc.nrpcfree < 32) {
                r->list = mntalloc.rpcfree;
                mntalloc.rpcfree = r;
                mntalloc.nrpcfree++;
+               unlock(&mntalloc);
+               return;
        }
-       mntalloc.nrpcused--;
+       freetag(r->request.tag);
        unlock(&mntalloc);
+       free(r);
 }
 
-void
+static void
 mntqrm(Mnt *m, Mntrpc *r)
 {
        Mntrpc **l, *f;
@@ -1131,7 +1349,7 @@ mntqrm(Mnt *m, Mntrpc *r)
        r->done = 1;
 
        l = &m->queue;
-       for(f = *l; f; f = f->list) {
+       for(f = *l; f != nil; f = f->list) {
                if(f == r) {
                        *l = r->list;
                        break;
@@ -1141,18 +1359,16 @@ mntqrm(Mnt *m, Mntrpc *r)
        unlock(m);
 }
 
-Mnt*
+static 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", 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));
 
@@ -1170,7 +1386,7 @@ mntchk(Chan *c)
  * reflect local values.  These entries are known to be
  * the first two in the Dir encoding after the count.
  */
-void
+static void
 mntdirfix(uchar *dirbuf, Chan *c)
 {
        uint r;
@@ -1182,13 +1398,13 @@ mntdirfix(uchar *dirbuf, Chan *c)
        PBIT32(dirbuf, c->dev);
 }
 
-int
+static int
 rpcattn(void *v)
 {
        Mntrpc *r;
 
        r = v;
-       return r->done || r->m->rip == 0;
+       return r->done || r->m->rip == nil;
 }
 
 Dev mntdevtab = {
@@ -1198,7 +1414,7 @@ Dev mntdevtab = {
        mntreset,
        devinit,
        devshutdown,
-       mntattach,
+       noattach,
        mntwalk,
        mntstat,
        mntopen,