#include "fns.h"
#include "../port/error.h"
-int chandebug=0; /* toggled by sysr1 */
-#define DBG if(chandebug)iprint
-
enum
{
PATHSLOP = 20,
#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)
{
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;
}
/*
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*);
lock(&chanalloc);
c = chanalloc.free;
- if(c != 0){
+ if(c != nil){
chanalloc.free = c->next;
- c->next = 0;
- }
- 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 */
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)
{
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;
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;
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]);
}
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);
}
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);
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);
}
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;
if(c->dirrock != nil){
free(c->dirrock);
- c->dirrock = 0;
+ c->dirrock = nil;
c->nrock = 0;
c->mrock = 0;
}
Chan *head;
Chan *tail;
ulong nqueued;
- ulong nclosed;
+ ulong nclosed;
Lock l;
QLock q;
Rendez r;
return clunkq.head != nil;
}
-static void
-closeproc(void*)
-{
- Chan *c;
-
- for(;;){
- if(clunkq.head == nil){
- if(!waserror()){
- tsleep(&clunkq.r, clunkwork, nil, 5000);
- poperror();
- }
- }
- qunlock(&clunkq.q);
- lock(&clunkq.l);
- c = clunkq.head;
- if(c == nil){
- unlock(&clunkq.l);
- if(canqlock(&clunkq.q))
- continue;
- 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)
+ if(clunkq.head != nil)
clunkq.tail->next = c;
else
clunkq.head = c;
clunkq.tail = c;
unlock(&clunkq.l);
+ wakeup(&clunkq.r);
+}
- if(up != 0 && palloc.Lock.p != up && canqlock(&clunkq.q)){
- c = up->dot;
- up->dot = up->slash; /* dummy */
+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(;;){
+ 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);
+ }
if(!waserror()){
- kproc("closeproc", closeproc, nil);
+ devtab[c->type]->close(c);
poperror();
}
- up->dot = c;
- }else
- wakeup(&clunkq.r);
+ chanfree(c);
+ }
}
void
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(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);
}
/*
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)
{
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;
* 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;
* 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()){
}
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
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;
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);
/*
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;
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;
}
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;
}
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;
}
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;
*/
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);
kstrcpy(up->errstr, Enotdir, ERRMAX);
- if(mh != nil)
- putmhead(mh);
+ putmhead(mh);
return -1;
}
ntry = nnames - nhave;
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
*/
pathclose(path);
if(nerror)
*nerror = nhave+1;
- if(mh != nil)
- putmhead(mh);
+ putmhead(mh);
return -1;
}
}
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;
kstrcpy(up->errstr, Edoesnotexist, ERRMAX);
kstrcpy(up->errstr, Enotdir, ERRMAX);
}
free(wq);
- if(mh != nil)
- putmhead(mh);
+ putmhead(mh);
return -1;
}
n = wq->nqid;
}
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);
}
mh = nmh;
free(wq);
}
-
putmhead(mh);
-
c = cunique(c);
-
if(c->umh != nil){ //BUG
print("walk umh\n");
putmhead(c->umh);
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();
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);
*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*
free(aname);
nexterror();
}
- DBG("namec %s %d %d\n", aname, amode, omode);
name = aname;
/*
* 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);
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);
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){
m = nil;
if(!nomount)
domount(&c, &m, nil);
- if(c->umh != nil)
- putmhead(c->umh);
+ putmhead(c->umh);
c->umh = m;
break;
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);
* 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;
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);
/* create failed */
cclose(cnew);
- if(m)
- putmhead(m);
+ putmhead(m);
if(omode & OEXCL)
nexterror();
/* save error */
* 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));
ename = memchr(name, 0, (1<<16));
if(ename==nil || ename-name>=(1<<16))
- error("name too long");
+ error(Etoolong);
s = nil;
if(dup){
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++;
}
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);
- }
-}
-