]> git.lizzy.rs Git - plan9front.git/blobdiff - sys/src/9/port/chan.c
import E script from bell labs
[plan9front.git] / sys / src / 9 / port / chan.c
index 61c0dc2e380ae21fce7ed3d244160713d567b754..add9ece907ddc079b6ea3b39d98054c4758edc73 100644 (file)
@@ -5,16 +5,13 @@
 #include       "fns.h"
 #include       "../port/error.h"
 
-int chandebug=0;               /* toggled by sysr1 */
-#define DBG if(chandebug)iprint
-
 enum
 {
        PATHSLOP        = 20,
        PATHMSLOP       = 20,
 };
 
-struct
+static struct Chanalloc
 {
        Lock;
        int     fid;
@@ -38,43 +35,6 @@ struct Elemlist
 
 #define SEP(c) ((c) == 0 || (c) == '/')
 
-static void
-dumpmount(void)                /* DEBUGGING */
-{
-       Pgrp *pg;
-       Mount *t;
-       Mhead **h, **he, *f;
-
-       if(up == nil){
-               print("no process for dumpmount\n");
-               return;
-       }
-       pg = up->pgrp;
-       if(pg == nil){
-               print("no pgrp for dumpmount\n");
-               return;
-       }
-       rlock(&pg->ns);
-       if(waserror()){
-               runlock(&pg->ns);
-               nexterror();
-       }
-
-       he = &pg->mnthash[MNTHASH];
-       for(h = pg->mnthash; h < he; h++){
-               for(f = *h; f; f = f->hash){
-                       print("head: %#p: %s %#llux.%lud %C %lud -> \n", f,
-                               f->from->path->s, f->from->qid.path,
-                               f->from->qid.vers, devtab[f->from->type]->dc,
-                               f->from->dev);
-                       for(t = f->mount; t; t = t->next)
-                               print("\t%#p: %s (umh %#p) (path %#.8llux dev %C %lud)\n", t, t->to->path->s, t->to->umh, t->to->qid.path, devtab[t->to->type]->dc, t->to->dev);
-               }
-       }
-       poperror();
-       runlock(&pg->ns);
-}
-
 char*
 chanpath(Chan *c)
 {
@@ -96,26 +56,27 @@ isdotdot(char *p)
 long
 incref(Ref *r)
 {
-       long x;
+       long old, new;
 
-       lock(r);
-       x = ++r->ref;
-       unlock(r);
-       return x;
+       do {
+               old = r->ref;
+               new = old+1;
+       } while(!cmpswap(&r->ref, old, new));
+       return new;
 }
 
 long
 decref(Ref *r)
 {
-       long x;
-
-       lock(r);
-       x = --r->ref;
-       unlock(r);
-       if(x < 0)
-               panic("decref pc=%#p", getcallerpc(&r));
-
-       return x;
+       long old, new;
+
+       do {
+               old = r->ref;
+               if(old <= 0)
+                       panic("decref pc=%#p", getcallerpc(&r));
+               new = old-1;
+       } while(!cmpswap(&r->ref, old, new));
+       return new;
 }
 
 /*
@@ -130,20 +91,19 @@ kstrcpy(char *s, char *t, int ns)
        int nt;
 
        nt = strlen(t);
-       if(nt+1 <= ns){
-               memmove(s, t, nt+1);
-               return;
-       }
-       /* too long */
-       if(ns < 4){
-               /* but very short! */
-               strncpy(s, t, ns);
+       if(nt < ns){
+               memmove(s, t, nt);
+               s[nt] = '\0';
                return;
        }
-       /* truncate with ... at character boundary (very rare case) */
-       memmove(s, t, ns-4);
+       /* too long, truncate */
+       nt = ns-1;
+       memmove(s, t, nt);
+       s[nt] = '\0';
+       /* append ... if there is space */
        ns -= 4;
-       s[ns] = '\0';
+       if(ns < 0)
+               return;
        /* look for first byte of UTF-8 sequence by skipping continuation bytes */
        while(ns>0 && (s[--ns]&0xC0)==0x80)
                ;
@@ -169,17 +129,18 @@ kstrdup(char **p, char *s)
        int n;
        char *t, *prev;
 
-       n = strlen(s)+1;
+       n = strlen(s);
        /* if it's a user, we can wait for memory; if not, something's very wrong */
-       if(up){
-               t = smalloc(n);
-               setmalloctag(t, getcallerpc(&p));
-       }else{
-               t = malloc(n);
+       if(up != nil)
+               t = smalloc(n+1);
+       else{
+               t = malloc(n+1);
                if(t == nil)
                        panic("kstrdup: no memory");
        }
+       setmalloctag(t, getcallerpc(&p));
        memmove(t, s, n);
+       t[n] = '\0';
        prev = *p;
        *p = t;
        free(prev);
@@ -191,10 +152,14 @@ chandevreset(void)
        int i;
 
        todinit();      /* avoid later reentry causing infinite recursion */
-       for(i=0; devtab[i] != nil; i++)
+       for(i=0; devtab[i] != nil; i++){
+               //print("%c: %s: reset\n", devtab[i]->dc, devtab[i]->name);
                devtab[i]->reset();
+       }
 }
 
+static void closeproc(void*);
+
 void
 chandevinit(void)
 {
@@ -202,6 +167,7 @@ chandevinit(void)
 
        for(i=0; devtab[i] != nil; i++)
                devtab[i]->init();
+       kproc("closeproc", closeproc, nil);
 }
 
 void
@@ -223,18 +189,19 @@ newchan(void)
 
        lock(&chanalloc);
        c = chanalloc.free;
-       if(c != 0)
+       if(c != nil){
                chanalloc.free = c->next;
-       unlock(&chanalloc);
-
-       if(c == nil){
+               c->next = nil;
+       } else {
+               unlock(&chanalloc);
                c = smalloc(sizeof(Chan));
                lock(&chanalloc);
-               c->fid = ++chanalloc.fid;
                c->link = chanalloc.list;
                chanalloc.list = c;
-               unlock(&chanalloc);
        }
+       if(c->fid == 0)
+               c->fid = ++chanalloc.fid;
+       unlock(&chanalloc);
 
        /* if you get an error before associating with a dev,
           close calls rootclose, a nop */
@@ -245,22 +212,24 @@ newchan(void)
        c->offset = 0;
        c->devoffset = 0;
        c->iounit = 0;
-       c->umh = 0;
+       c->umh = nil;
+       c->umc = nil;
        c->uri = 0;
        c->dri = 0;
-       c->aux = 0;
-       c->mchan = 0;
-       c->mcp = 0;
-       c->mux = 0;
-       memset(&c->mqid, 0, sizeof(c->mqid));
-       c->path = 0;
+       c->dirrock = nil;
+       c->nrock = 0;
+       c->mrock = 0;
        c->ismtpt = 0;
+       c->mcp = nil;
+       c->mux = nil;
+       c->aux = nil;
+       c->mchan = nil;
+       memset(&c->mqid, 0, sizeof(c->mqid));
+       c->path = nil;
        
        return c;
 }
 
-Ref npath;
-
 Path*
 newpath(char *s)
 {
@@ -274,14 +243,13 @@ newpath(char *s)
        p->s = smalloc(p->alen);
        memmove(p->s, s, i+1);
        p->ref = 1;
-       incref(&npath);
 
        /*
         * Cannot use newpath for arbitrary names because the mtpt 
         * array will not be populated correctly.  The names #/ and / are
         * allowed, but other names with / in them draw warnings.
         */
-       if(strchr(s, '/') && strcmp(s, "#/") != 0 && strcmp(s, "/") != 0)
+       if(strchr(s, '/') != nil && strcmp(s, "#/") != 0 && strcmp(s, "/") != 0)
                print("newpath: %s from %#p\n", s, getcallerpc(&s));
 
        p->mlen = 1;
@@ -298,8 +266,6 @@ copypath(Path *p)
        
        pp = smalloc(sizeof(Path));
        pp->ref = 1;
-       incref(&npath);
-       DBG("copypath %s %p => %p\n", p->s, p, pp);
        
        pp->len = p->len;
        pp->alen = p->alen;
@@ -311,7 +277,7 @@ copypath(Path *p)
        pp->mtpt = smalloc(p->malen*sizeof pp->mtpt[0]);
        for(i=0; i<pp->mlen; i++){
                pp->mtpt[i] = p->mtpt[i];
-               if(pp->mtpt[i])
+               if(pp->mtpt[i] != nil)
                        incref(pp->mtpt[i]);
        }
 
@@ -322,23 +288,14 @@ void
 pathclose(Path *p)
 {
        int i;
-       
-       if(p == nil)
-               return;
-//XXX
-       DBG("pathclose %p %s ref=%ld =>", p, p->s, p->ref);
-       for(i=0; i<p->mlen; i++)
-               DBG(" %p", p->mtpt[i]);
-       DBG("\n");
 
-       if(decref(p))
+       if(p == nil || decref(p))
                return;
-       decref(&npath);
-       free(p->s);
        for(i=0; i<p->mlen; i++)
-               if(p->mtpt[i])
+               if(p->mtpt[i] != nil)
                        cclose(p->mtpt[i]);
        free(p->mtpt);
+       free(p->s);
        free(p);
 }
 
@@ -396,8 +353,9 @@ addelem(Path *p, char *s, Chan *from)
        p = uniquepath(p);
 
        i = strlen(s);
-       if(p->len+1+i+1 > p->alen){
-               a = p->len+1+i+1 + PATHSLOP;
+       a = p->len+1+i+1;
+       if(a > p->alen){
+               a += PATHSLOP;
                t = smalloc(a);
                memmove(t, p->s, p->len+1);
                free(p->s);
@@ -411,8 +369,7 @@ addelem(Path *p, char *s, Chan *from)
        p->len += i;
        if(isdotdot(s)){
                fixdotdotname(p);
-               DBG("addelem %s .. => rm %p\n", p->s, p->mtpt[p->mlen-1]);
-               if(p->mlen>1 && (c = p->mtpt[--p->mlen])){
+               if(p->mlen > 1 && (c = p->mtpt[--p->mlen]) != nil){
                        p->mtpt[p->mlen] = nil;
                        cclose(c);
                }
@@ -424,9 +381,8 @@ addelem(Path *p, char *s, Chan *from)
                        free(p->mtpt);
                        p->mtpt = tt;
                }
-               DBG("addelem %s %s => add %p\n", p->s, s, from);
                p->mtpt[p->mlen++] = from;
-               if(from)
+               if(from != nil)
                        incref(from);
        }
        return p;
@@ -439,7 +395,7 @@ chanfree(Chan *c)
 
        if(c->dirrock != nil){
                free(c->dirrock);
-               c->dirrock = 0;
+               c->dirrock = nil;
                c->nrock = 0;
                c->mrock = 0;
        }
@@ -475,8 +431,8 @@ chanfree(Chan *c)
 struct {
        Chan *head;
        Chan *tail;
-       int nqueued;
-       int nclosed;
+       ulong nqueued;
+       ulong nclosed;  
        Lock l;
        QLock q;
        Rendez r;
@@ -489,72 +445,86 @@ clunkwork(void*)
 }
 
 static void
-closeproc(void*)
+closechanq(Chan *c)
+{
+       lock(&clunkq.l);
+       clunkq.nqueued++;
+       c->next = nil;
+       if(clunkq.head != nil)
+               clunkq.tail->next = c;
+       else
+               clunkq.head = c;
+       clunkq.tail = c;
+       unlock(&clunkq.l);
+       wakeup(&clunkq.r);
+}
+
+static Chan*
+closechandeq(void)
+{
+       Chan *c;
+
+       lock(&clunkq.l);
+       c = clunkq.head;
+       if(c != nil) {
+               clunkq.head = c->next;
+               clunkq.nclosed++;
+       }
+       unlock(&clunkq.l);
+       return c;
+}
+
+static void
+closeproc(void *)
 {
        Chan *c;
 
        for(;;){
-               if(clunkq.head == nil){
-                       if(!waserror()){
-                               tsleep(&clunkq.r, clunkwork, nil, 5000);
+               c = closechandeq();
+               if(c == nil) {
+                       qlock(&clunkq.q);
+                       if(!waserror()) {
+                               tsleep(&clunkq.r, clunkwork, nil, 500);
                                poperror();
                        }
+                       c = closechandeq();
+                       if(c == nil) {
+                               if(clunkq.q.head != nil) {
+                                       qunlock(&clunkq.q);
+                                       pexit("no work", 1);
+                               }
+                               qunlock(&clunkq.q);
+                               continue;
+                       }
+                       if(clunkq.q.head == nil) {
+                               if(!waserror()) {
+                                       kproc("closeproc", closeproc, nil);
+                                       poperror();
+                               }
+                       }
+                       qunlock(&clunkq.q);
                }
-               qunlock(&clunkq.q);
-               lock(&clunkq.l);
-               c = clunkq.head;
-               if(c == nil){
-                       unlock(&clunkq.l);
-                       pexit("no work", 1);
-               }
-               clunkq.head = c->next;
-               clunkq.nclosed++;
-               unlock(&clunkq.l);
                if(!waserror()){
                        devtab[c->type]->close(c);
                        poperror();
                }
                chanfree(c);
-               qlock(&clunkq.q);
        }
 }
 
-static void
-closechanq(Chan *c)
-{
-       lock(&clunkq.l);
-       clunkq.nqueued++;
-       c->next = nil;
-       if(clunkq.head)
-               clunkq.tail->next = c;
-       else
-               clunkq.head = c;
-       clunkq.tail = c;
-       unlock(&clunkq.l);
-
-       if(canqlock(&clunkq.q)){
-               c = up->dot;
-               up->dot = nil;
-               kproc("closeproc", closeproc, nil);
-               up->dot = c;
-       }else
-               wakeup(&clunkq.r);
-}
-
 void
 cclose(Chan *c)
 {
        if(c == nil || c->ref < 1 || c->flag&CFREE)
                panic("cclose %#p", getcallerpc(&c));
 
-       DBG("cclose %p name=%s ref=%ld\n", c, chanpath(c), c->ref);
-
        if(decref(c))
                return;
 
        if(devtab[c->type]->dc == L'M')
        if((c->flag&(CRCLOSE|CCACHE)) == CCACHE)
-       if((c->qid.type&(QTEXCL|QTMOUNT|QTAUTH)) == 0){
+       if((c->qid.type&(QTEXCL|QTMOUNT|QTAUTH)) == 0)
+       if((clunkq.nqueued - clunkq.nclosed) < 64){
                closechanq(c);
                return;
        }
@@ -572,12 +542,8 @@ ccloseq(Chan *c)
        if(c == nil || c->ref < 1 || c->flag&CFREE)
                panic("ccloseq %#p", getcallerpc(&c));
 
-       DBG("ccloseq %p name=%s ref=%ld\n", c, chanpath(c), c->ref);
-
-       if(decref(c))
-               return;
-
-       closechanq(c);
+       if(decref(c) == 0)
+               closechanq(c);
 }
 
 /*
@@ -643,6 +609,35 @@ newmhead(Chan *from)
        return mh;
 }
 
+/*
+ * This is necessary because there are many
+ * pointers to the top of a given mount list:
+ *
+ *     - the mhead in the namespace hash table
+ *     - the mhead in chans returned from findmount:
+ *       used in namec and then by unionread.
+ *     - the mhead in chans returned from createdir:
+ *       used in the open/create race protect, which is gone.
+ *
+ * The RWlock in the Mhead protects the mount list it contains.
+ * The mount list is deleted in cunmount() and closepgrp().
+ * The RWlock ensures that nothing is using the mount list at that time.
+ *
+ * It is okay to replace c->mh with whatever you want as 
+ * long as you are sure you have a unique reference to it.
+ *
+ * This comment might belong somewhere else.
+ */
+void
+putmhead(Mhead *m)
+{
+       if(m != nil && decref(m) == 0){
+               assert(m->mount == nil);
+               cclose(m->from);
+               free(m);
+       }
+}
+
 int
 cmount(Chan **newp, Chan *old, int flag, char *spec)
 {
@@ -655,12 +650,12 @@ cmount(Chan **newp, Chan *old, int flag, char *spec)
        if(QTDIR & (old->qid.type^(*newp)->qid.type))
                error(Emount);
 
-       if(old->umh)
+       if(old->umh != nil)
                print("cmount: unexpected umh, caller %#p\n", getcallerpc(&newp));
 
        order = flag&MORDER;
 
-       if((old->qid.type&QTDIR)==0 && order != MREPL)
+       if((old->qid.type&QTDIR) == 0 && order != MREPL)
                error(Emount);
 
        new = *newp;
@@ -684,15 +679,15 @@ cmount(Chan **newp, Chan *old, int flag, char *spec)
         * This is far more complicated than it should be, but I don't
         * see an easier way at the moment.
         */
-       if((flag&MCREATE) && mh && mh->mount
-       && (mh->mount->next || !(mh->mount->mflag&MCREATE)))
+       if((flag&MCREATE) != 0 && mh != nil && mh->mount != nil
+       && (mh->mount->next != nil || (mh->mount->mflag&MCREATE) == 0))
                error(Emount);
 
        pg = up->pgrp;
        wlock(&pg->ns);
 
        l = &MOUNTH(pg, old->qid);
-       for(m = *l; m; m = m->hash){
+       for(m = *l; m != nil; m = m->hash){
                if(eqchan(m->from, old, 1))
                        break;
                l = &m->hash;
@@ -711,7 +706,7 @@ cmount(Chan **newp, Chan *old, int flag, char *spec)
                 *  node to the mount chain.
                 */
                if(order != MREPL)
-                       m->mount = newmount(m, old, 0, 0);
+                       m->mount = newmount(old, 0, nil);
        }
        wlock(&m->lock);
        if(waserror()){
@@ -720,7 +715,7 @@ cmount(Chan **newp, Chan *old, int flag, char *spec)
        }
        wunlock(&pg->ns);
 
-       nm = newmount(m, new, flag, spec);
+       nm = newmount(new, flag, spec);
        if(mh != nil && mh->mount != nil){
                /*
                 *  copy a union when binding it onto a directory
@@ -730,32 +725,31 @@ cmount(Chan **newp, Chan *old, int flag, char *spec)
                        flg = MAFTER;
                h = &nm->next;
                um = mh->mount;
-               for(um = um->next; um; um = um->next){
-                       f = newmount(m, um->to, flg, um->spec);
+               for(um = um->next; um != nil; um = um->next){
+                       f = newmount(um->to, flg, um->spec);
                        *h = f;
                        h = &f->next;
                }
        }
 
-       if(m->mount && order == MREPL){
+       if(m->mount != nil && order == MREPL){
                mountfree(m->mount);
-               m->mount = 0;
+               m->mount = nil;
        }
 
        if(flag & MCREATE)
                nm->mflag |= MCREATE;
 
-       if(m->mount && order == MAFTER){
-               for(f = m->mount; f->next; f = f->next)
+       if(m->mount != nil && order == MAFTER){
+               for(f = m->mount; f->next != nil; f = f->next)
                        ;
                f->next = nm;
        }else{
-               for(f = nm; f->next; f = f->next)
+               for(f = nm; f->next != nil; f = f->next)
                        ;
                f->next = m->mount;
                m->mount = nm;
        }
-
        wunlock(&m->lock);
        poperror();
        return nm->mountid;
@@ -768,7 +762,7 @@ cunmount(Chan *mnt, Chan *mounted)
        Mhead *m, **l;
        Mount *f, **p;
 
-       if(mnt->umh)    /* should not happen */
+       if(mnt->umh != nil)     /* should not happen */
                print("cunmount newp extra umh %p has %p\n", mnt, mnt->umh);
 
        /*
@@ -784,47 +778,44 @@ cunmount(Chan *mnt, Chan *mounted)
        wlock(&pg->ns);
 
        l = &MOUNTH(pg, mnt->qid);
-       for(m = *l; m; m = m->hash){
+       for(m = *l; m != nil; m = m->hash){
                if(eqchan(m->from, mnt, 1))
                        break;
                l = &m->hash;
        }
 
-       if(m == 0){
+       if(m == nil){
                wunlock(&pg->ns);
                error(Eunmount);
        }
 
        wlock(&m->lock);
-       if(mounted == 0){
+       f = m->mount;
+       if(mounted == nil){
                *l = m->hash;
-               wunlock(&pg->ns);
-               mountfree(m->mount);
                m->mount = nil;
-               cclose(m->from);
                wunlock(&m->lock);
+               wunlock(&pg->ns);
+               mountfree(f);
                putmhead(m);
                return;
        }
-
-       p = &m->mount;
-       for(f = *p; f; f = f->next){
-               /* BUG: Needs to be 2 pass */
+       for(p = &m->mount; f != nil; f = f->next){
                if(eqchan(f->to, mounted, 1) ||
-                 (f->to->mchan && eqchan(f->to->mchan, mounted, 1))){
+                 (f->to->mchan != nil && eqchan(f->to->mchan, mounted, 1))){
                        *p = f->next;
-                       f->next = 0;
-                       mountfree(f);
+                       f->next = nil;
                        if(m->mount == nil){
                                *l = m->hash;
-                               cclose(m->from);
                                wunlock(&m->lock);
                                wunlock(&pg->ns);
+                               mountfree(f);
                                putmhead(m);
                                return;
                        }
                        wunlock(&m->lock);
                        wunlock(&pg->ns);
+                       mountfree(f);
                        return;
                }
                p = &f->next;
@@ -847,8 +838,7 @@ cclone(Chan *c)
                error("clone failed");
        nc = wq->clone;
        free(wq);
-       nc->path = c->path;
-       if(c->path)
+       if((nc->path = c->path) != nil)
                incref(c->path);
        return nc;
 }
@@ -857,36 +847,31 @@ cclone(Chan *c)
 int
 findmount(Chan **cp, Mhead **mp, int type, int dev, Qid qid)
 {
+       Chan *to;
        Pgrp *pg;
        Mhead *m;
 
        pg = up->pgrp;
        rlock(&pg->ns);
-       for(m = MOUNTH(pg, qid); m; m = m->hash){
-               rlock(&m->lock);
-               if(m->from == nil){
-                       print("m %p m->from 0\n", m);
-                       runlock(&m->lock);
-                       continue;
-               }
+       for(m = MOUNTH(pg, qid); m != nil; m = m->hash){
                if(eqchantdqid(m->from, type, dev, qid, 1)){
+                       rlock(&m->lock);
                        runlock(&pg->ns);
-                       if(mp != nil){
+                       if(mp != nil)
                                incref(m);
-                               if(*mp != nil)
-                                       putmhead(*mp);
+                       to = m->mount->to;
+                       incref(to);
+                       runlock(&m->lock);
+                       if(mp != nil){
+                               putmhead(*mp);
                                *mp = m;
                        }
                        if(*cp != nil)
                                cclose(*cp);
-                       incref(m->mount->to);
-                       *cp = m->mount->to;
-                       runlock(&m->lock);
+                       *cp = to;
                        return 1;
                }
-               runlock(&m->lock);
        }
-
        runlock(&pg->ns);
        return 0;
 }
@@ -897,24 +882,24 @@ findmount(Chan **cp, Mhead **mp, int type, int dev, Qid qid)
 static int
 domount(Chan **cp, Mhead **mp, Path **path)
 {
-       Chan **lc;
+       Chan **lc, *from;
        Path *p;
 
        if(findmount(cp, mp, (*cp)->type, (*cp)->dev, (*cp)->qid) == 0)
                return 0;
 
-       if(path){
+       if(path != nil){
                p = *path;
                p = uniquepath(p);
                if(p->mlen <= 0)
                        print("domount: path %s has mlen==%d\n", p->s, p->mlen);
                else{
+                       from = (*mp)->from;
+                       incref(from);
                        lc = &p->mtpt[p->mlen-1];
-DBG("domount %p %s => add %p (was %p)\n", p, p->s, (*mp)->from, p->mtpt[p->mlen-1]);
-                       incref((*mp)->from);
-                       if(*lc)
+                       if(*lc != nil)
                                cclose(*lc);
-                       *lc = (*mp)->from;
+                       *lc = from;
                }
                *path = p;
        }
@@ -935,8 +920,7 @@ undomount(Chan *c, Path *path)
                print("undomount: path %s ref %ld mlen %d caller %#p\n",
                        path->s, path->ref, path->mlen, getcallerpc(&c));
 
-       if(path->mlen>0 && (nc=path->mtpt[path->mlen-1]) != nil){
-DBG("undomount %p %s => remove %p\n", path, path->s, nc);
+       if(path->mlen > 0 && (nc = path->mtpt[path->mlen-1]) != nil){
                cclose(c);
                path->mtpt[path->mlen-1] = nil;
                c = nc;
@@ -995,14 +979,13 @@ walk(Chan **cp, char **names, int nnames, int nomount, int *nerror)
         */
        didmount = 0;
        for(nhave=0; nhave<nnames; nhave+=n){
-               if((c->qid.type&QTDIR)==0){
+               if((c->qid.type&QTDIR) == 0){
                        if(nerror)
                                *nerror = nhave;
                        pathclose(path);
                        cclose(c);
-                       strcpy(up->errstr, Enotdir);
-                       if(mh != nil)
-                               putmhead(mh);
+                       kstrcpy(up->errstr, Enotdir, ERRMAX);
+                       putmhead(mh);
                        return -1;
                }
                ntry = nnames - nhave;
@@ -1028,7 +1011,7 @@ walk(Chan **cp, char **names, int nnames, int nomount, int *nerror)
 
                if((wq = ewalk(c, nil, names+nhave, ntry)) == nil){
                        /* try a union mount, if any */
-                       if(mh && !nomount){
+                       if(mh != nil && !nomount){
                                /*
                                 * mh->mount->to == c, so start at mh->mount->next
                                 */
@@ -1048,8 +1031,7 @@ walk(Chan **cp, char **names, int nnames, int nomount, int *nerror)
                                pathclose(path);
                                if(nerror)
                                        *nerror = nhave+1;
-                               if(mh != nil)
-                                       putmhead(mh);
+                               putmhead(mh);
                                return -1;
                        }
                }
@@ -1078,18 +1060,17 @@ walk(Chan **cp, char **names, int nnames, int nomount, int *nerror)
                                if(wq->clone == nil){
                                        cclose(c);
                                        pathclose(path);
-                                       if(wq->nqid==0 || (wq->qid[wq->nqid-1].type&QTDIR)){
+                                       if(wq->nqid == 0 || (wq->qid[wq->nqid-1].type&QTDIR) != 0){
                                                if(nerror)
                                                        *nerror = nhave+wq->nqid+1;
-                                               strcpy(up->errstr, Edoesnotexist);
+                                               kstrcpy(up->errstr, Edoesnotexist, ERRMAX);
                                        }else{
                                                if(nerror)
                                                        *nerror = nhave+wq->nqid;
-                                               strcpy(up->errstr, Enotdir);
+                                               kstrcpy(up->errstr, Enotdir, ERRMAX);
                                        }
                                        free(wq);
-                                       if(mh != nil)
-                                               putmhead(mh);
+                                       putmhead(mh);
                                        return -1;
                                }
                                n = wq->nqid;
@@ -1104,7 +1085,7 @@ walk(Chan **cp, char **names, int nnames, int nomount, int *nerror)
                        }
                        for(i=0; i<n; i++){
                                mtpt = nil;
-                               if(i==n-1 && nmh)
+                               if(i==n-1 && nmh!=nil)
                                        mtpt = nmh->from;
                                path = addelem(path, names[nhave+i], mtpt);
                        }
@@ -1115,11 +1096,8 @@ walk(Chan **cp, char **names, int nnames, int nomount, int *nerror)
                mh = nmh;
                free(wq);
        }
-
        putmhead(mh);
-
        c = cunique(c);
-
        if(c->umh != nil){      //BUG
                print("walk umh\n");
                putmhead(c->umh);
@@ -1150,8 +1128,8 @@ createdir(Chan *c, Mhead *m)
                runlock(&m->lock);
                nexterror();
        }
-       for(f = m->mount; f; f = f->next){
-               if(f->mflag&MCREATE){
+       for(f = m->mount; f != nil; f = f->next){
+               if((f->mflag&MCREATE) != 0){
                        nc = cclone(f->to);
                        runlock(&m->lock);
                        poperror();
@@ -1175,7 +1153,7 @@ growparse(Elemlist *e)
        int *inew;
        enum { Delta = 8 };
 
-       if(e->nelems % Delta == 0){
+       if((e->nelems % Delta) == 0){
                new = smalloc((e->nelems+Delta) * sizeof(char*));
                memmove(new, e->elems, e->nelems*sizeof(char*));
                free(e->elems);
@@ -1226,15 +1204,6 @@ parsename(char *aname, Elemlist *e)
                *slash++ = '\0';
                name = slash;
        }
-       
-       if(0 && chandebug){
-               int i;
-               
-               print("parsename %s:", e->name);
-               for(i=0; i<=e->nelems; i++)
-                       print(" %d", e->off[i]);
-               print("\n");
-       }
 }
 
 void*
@@ -1335,7 +1304,6 @@ namec(char *aname, int amode, int omode, ulong perm)
                free(aname);
                nexterror();
        }
-       DBG("namec %s %d %d\n", aname, amode, omode);
        name = aname;
 
        /*
@@ -1373,9 +1341,6 @@ namec(char *aname, int amode, int omode, ulong perm)
                 *         any others left unprotected)
                 */
                n = chartorune(&r, up->genbuf+1)+1;
-               /* actually / is caught by parsing earlier */
-               if(utfrune("M", r))
-                       error(Enoattach);
                if(up->pgrp->noattach && utfrune("|decp", r)==nil)
                        error(Enoattach);
                t = devno(r, 1);
@@ -1410,8 +1375,6 @@ namec(char *aname, int amode, int omode, ulong perm)
                if(e.off[e.nerror]==0)
                        print("nerror=%d but off=%d\n",
                                e.nerror, e.off[e.nerror]);
-               if(0 && chandebug)
-                       print("showing %d+%d/%d (of %d) of %s (%d %d)\n", e.prefix, e.off[e.nerror], e.nerror, e.nelems, aname, e.off[0], e.off[1]);
                len = e.prefix+e.off[e.nerror];
                free(e.off);
                namelenerror(aname, len, tmperrbuf);
@@ -1446,10 +1409,10 @@ namec(char *aname, int amode, int omode, ulong perm)
                nexterror();
        }
 
-       if(e.mustbedir && !(c->qid.type&QTDIR))
+       if(e.mustbedir && (c->qid.type&QTDIR) == 0)
                error("not a directory");
 
-       if(amode == Aopen && (omode&3) == OEXEC && (c->qid.type&QTDIR))
+       if(amode == Aopen && (omode&3) == OEXEC && (c->qid.type&QTDIR) != 0)
                error("cannot exec directory");
 
        switch(amode){
@@ -1458,8 +1421,7 @@ namec(char *aname, int amode, int omode, ulong perm)
                m = nil;
                if(!nomount)
                        domount(&c, &m, nil);
-               if(c->umh != nil)
-                       putmhead(c->umh);
+               putmhead(c->umh);
                c->umh = m;
                break;
 
@@ -1470,6 +1432,10 @@ namec(char *aname, int amode, int omode, ulong perm)
                /* save&update the name; domount might change c */
                path = c->path;
                incref(path);
+               if(waserror()){
+                       pathclose(path);
+                       nexterror();
+               }
                m = nil;
                if(!nomount)
                        domount(&c, &m, &path);
@@ -1480,6 +1446,7 @@ namec(char *aname, int amode, int omode, ulong perm)
                /* now it's our copy anyway, we can put the name back */
                pathclose(c->path);
                c->path = path;
+               poperror();
 
                /* record whether c is on a mount point */
                c->ismtpt = m!=nil;
@@ -1492,13 +1459,13 @@ namec(char *aname, int amode, int omode, ulong perm)
 
                case Aopen:
                case Acreate:
-if(c->umh != nil){
-       print("cunique umh Open\n");
-       putmhead(c->umh);
-       c->umh = nil;
-}
+                       if(c->umh != nil){
+                               print("cunique umh Open\n");
+                               putmhead(c->umh);
+                               c->umh = nil;
+                       }
                        /* only save the mount head if it's a multiple element union */
-                       if(m && m->mount && m->mount->next)
+                       if(m != nil && m->mount != nil && m->mount->next != nil)
                                c->umh = m;
                        else
                                putmhead(m);
@@ -1521,7 +1488,7 @@ if(c->umh != nil){
                 * Directories (e.g. for cd) are left before the mount point,
                 * so one may mount on / or . and see the effect.
                 */
-               if(!(c->qid.type & QTDIR))
+               if((c->qid.type&QTDIR) == 0)
                        error(Enotdir);
                break;
 
@@ -1615,8 +1582,7 @@ if(c->umh != nil){
                                cnew->flag |= CCEXEC;
                        if(omode & ORCLOSE)
                                cnew->flag |= CRCLOSE;
-                       if(m)
-                               putmhead(m);
+                       putmhead(m);
                        cclose(c);
                        c = cnew;
                        c->path = addelem(c->path, e.elems[e.nelems-1], nil);
@@ -1625,8 +1591,7 @@ if(c->umh != nil){
 
                /* create failed */
                cclose(cnew);
-               if(m)
-                       putmhead(m);
+               putmhead(m);
                if(omode & OEXCL)
                        nexterror();
                /* save error */
@@ -1696,14 +1661,14 @@ char isfrog[256]={
  * to access unchecked addresses.) 
  */
 static char*
-validname0(char *aname, int slashok, int dup, ulong pc)
+validname0(char *aname, int slashok, int dup, uintptr pc)
 {
        char *ename, *name, *s;
        int c, n;
        Rune r;
 
        name = aname;
-       if((ulong)name < KZERO){
+       if((uintptr)name < KZERO){
                if(!dup)
                        print("warning: validname called from %#p with user pointer", pc);
                ename = vmemchr(name, 0, (1<<16));
@@ -1711,7 +1676,7 @@ validname0(char *aname, int slashok, int dup, ulong pc)
                ename = memchr(name, 0, (1<<16));
 
        if(ename==nil || ename-name>=(1<<16))
-               error("name too long");
+               error(Etoolong);
 
        s = nil;
        if(dup){
@@ -1731,10 +1696,10 @@ validname0(char *aname, int slashok, int dup, ulong pc)
                        name += chartorune(&r, name);
                else{
                        if(isfrog[c])
-                               if(!slashok || c!='/'){
-                                       snprint(up->genbuf, sizeof(up->genbuf), "%s: %q", Ebadchar, aname);
-                                       free(s);
-                                       error(up->genbuf);
+                       if(!slashok || c!='/'){
+                               snprint(up->genbuf, sizeof(up->genbuf), "%s: %q", Ebadchar, aname);
+                               free(s);
+                               error(up->genbuf);
                        }
                        name++;
                }
@@ -1761,32 +1726,3 @@ isdir(Chan *c)
                return;
        error(Enotdir);
 }
-
-/*
- * This is necessary because there are many
- * pointers to the top of a given mount list:
- *
- *     - the mhead in the namespace hash table
- *     - the mhead in chans returned from findmount:
- *       used in namec and then by unionread.
- *     - the mhead in chans returned from createdir:
- *       used in the open/create race protect, which is gone.
- *
- * The RWlock in the Mhead protects the mount list it contains.
- * The mount list is deleted when we cunmount.
- * The RWlock ensures that nothing is using the mount list at that time.
- *
- * It is okay to replace c->mh with whatever you want as 
- * long as you are sure you have a unique reference to it.
- *
- * This comment might belong somewhere else.
- */
-void
-putmhead(Mhead *m)
-{
-       if(m && decref(m) == 0){
-               m->mount = (Mount*)0xCafeBeef;
-               free(m);
-       }
-}
-