ref: 36e5075ded47aaace9185b96567a4086bd49bb58
parent: 084c9d6eba486cba2c3d693b5bc5d04b44651031
author: Ori Bernstein <ori@eigenstate.org>
date: Sat Sep 7 15:00:06 EDT 2024
gefs: protect fids with rwlock
--- a/sys/src/cmd/gefs/dat.h
+++ b/sys/src/cmd/gefs/dat.h
@@ -676,7 +676,7 @@
};
struct Fid {
- Lock;
+ RWLock;
Fid *next;
/*
* if opened with OEXEC, we want to use a snapshot,
--- a/sys/src/cmd/gefs/fs.c
+++ b/sys/src/cmd/gefs/fs.c
@@ -741,6 +741,7 @@
return nil;
*n = *f;
+ memset(&n->RWLock, 0, sizeof(RWLock));
n->fid = new;
n->ref = 2; /* one for dup, one for clunk */
n->mode = -1;
@@ -780,7 +781,7 @@
Fid *f, **pf;
u32int h;
- assert(!canlock(fid));
+ assert(!canwlock(fid));
h = ihash(fid->fid) % Nfidtab;
lock(&c->fidtablk[h]);
@@ -823,6 +824,21 @@
}
}
+static void
+freeamsg(Amsg *a)
+{
+ if(a == nil)
+ return;
+ switch(a->op){
+ case AOrclose:
+ case AOclear:
+ clunkdent(a->mnt, a->dent);
+ clunkmount(a->mnt);
+ break;
+ }
+ free(a);
+}
+
static int
readmsg(Conn *c, Fmsg **pm)
{
@@ -1253,7 +1269,7 @@
fswalk(Fmsg *m)
{
char *name, kbuf[Maxent], kvbuf[Kvmax];
- int duid, dgid, dmode;
+ int duid, dgid, dmode, duped;
vlong up, upup, prev;
Dent *dent, *dir;
Fid *o, *f;
@@ -1270,8 +1286,10 @@
rerror(m, Enofid);
return;
}
+ rlock(o);
if(waserror()){
rerror(m, errmsg());
+ runlock(o);
putfid(o);
return;
}
@@ -1325,25 +1343,22 @@
if(i == 0 && m->nwname != 0)
error(Esrch);
f = o;
+ duped = 0;
if(m->fid != m->newfid && i == m->nwname){
if((f = dupfid(m->conn, m->newfid, o)) == nil)
error(Efid);
- putfid(o);
- poperror();
- if(waserror()){
- rerror(m, errmsg());
- putfid(f);
- return;
- }
+ duped = 1;
}
+ runlock(o);
+
if(i > 0 && i == m->nwname){
- lock(f);
+ wlock(f);
ao = nil;
if(waserror()){
- if(f != o)
+ if(duped)
clunkfid(m->conn, f, &ao);
assert(ao == nil);
- unlock(f);
+ wunlock(f);
nexterror();
}
if(up == -1ULL){
@@ -1374,10 +1389,12 @@
f->dgid = dgid;
f->dmode = dmode;
poperror();
- unlock(f);
+ wunlock(f);
}
- respond(m, &r);
+ if(duped)
+ putfid(o);
putfid(f);
+ respond(m, &r);
poperror();
}
@@ -1439,7 +1456,7 @@
wlock(de);
if(waserror()){
rerror(m, errmsg());
- free(*ao);
+ freeamsg(*ao);
*ao = nil;
goto Err;
}
@@ -1638,9 +1655,9 @@
rerror(m, Enofid);
return;
}
- lock(f);
+ wlock(f);
clunkfid(m->conn, f, ao);
- unlock(f);
+ wunlock(f);
r.type = Rclunk;
respond(m, &r);
putfid(f);
@@ -1671,7 +1688,7 @@
rerror(m, Enofid);
return;
}
- lock(f);
+ wlock(f);
if(waserror()){
rerror(m, errmsg());
@@ -1761,7 +1778,7 @@
r.iounit = f->iounit;
respond(m, &r);
Out: poperror();
-Err: unlock(f);
+Err: wunlock(f);
putfid(f);
return;
}
@@ -1805,15 +1822,13 @@
}
t = f->mnt->root;
nm = 0;
- lock(f);
+ wlock(f);
clunkfid(m->conn, f, ao);
- unlock(f);
-
truncwait(f->dent, id);
wlock(f->dent);
if(waserror()){
rerror(m, errmsg());
- free(*ao);
+ freeamsg(*ao);
*ao = nil;
goto Err;
}
@@ -1834,7 +1849,10 @@
error(e);
if(fsaccess(f, f->dmode, f->duid, f->dgid, DMWRITE) == -1)
error(Eperm);
- lock(f);
+
+ freeamsg(*ao);
+ *ao = nil;
+
mb[nm].op = Odelete;
mb[nm].k = f->dent->k;
mb[nm].nk = f->dent->nk;
@@ -1841,8 +1859,6 @@
mb[nm].v = "\0";
mb[nm].nv = 1;
nm++;
- unlock(f);
-
if(f->dent->qid.type & QTDIR){
packsuper(buf, sizeof(buf), f->qpath);
mb[nm].op = Oclobber;
@@ -1851,8 +1867,7 @@
mb[nm].nv = 0;
nm++;
}else{
- if(*ao == nil)
- *ao = emalloc(sizeof(Amsg), 1);
+ *ao = emalloc(sizeof(Amsg), 1);
ainc(&f->mnt->ref);
(*ao)->op = AOclear;
(*ao)->mnt = f->mnt;
@@ -1870,6 +1885,7 @@
poperror();
Err:
wunlock(f->dent);
+ wunlock(f);
putfid(f);
return;
}
@@ -1928,9 +1944,9 @@
r.qid = d.qid;
r.iounit = f->iounit;
- lock(f);
+ wlock(f);
if(f->mode != -1){
- unlock(f);
+ wunlock(f);
error(Einuse);
}
if((m->mode & OTRUNC) && !(f->dent->mode & DMAPPEND)){
@@ -1938,7 +1954,7 @@
if(waserror()){
wunlock(f->dent);
- free(*ao);
+ freeamsg(*ao);
*ao = nil;
nexterror();
}
@@ -1976,7 +1992,7 @@
f->mode = mode2bits(m->mode);
if(m->mode & ORCLOSE)
f->rclose = emalloc(sizeof(Amsg), 1);
- unlock(f);
+ wunlock(f);
poperror();
respond(m, &r);
putfid(f);
@@ -1990,6 +2006,12 @@
Scan *s;
Xdir d;
+ /* mutates scan */
+ wlock(f);
+ if(waserror()){
+ wunlock(f);
+ nexterror();
+ }
s = f->scan;
if(s != nil && s->offset != 0 && s->offset != m->offset)
error(Edscan);
@@ -1997,12 +2019,10 @@
s = emalloc(sizeof(Scan), 1);
pfx[0] = Klabel;
btnewscan(s, pfx, 1);
- lock(f);
if(f->scan != nil){
free(f->scan);
}
f->scan = s;
- unlock(f);
}
if(s->donescan){
r->count = 0;
@@ -2038,6 +2058,8 @@
n -= ns;
}
btexit(s);
+ poperror();
+ wunlock(f);
r->count = p - r->data;
return;
}
@@ -2050,6 +2072,12 @@
Tree *t;
Scan *s;
+ /* mutates scan */
+ wlock(f);
+ if(waserror()){
+ wunlock(f);
+ nexterror();
+ }
s = f->scan;
t = agetp(&f->mnt->root);
if(s != nil && s->offset != 0 && s->offset != m->offset)
@@ -2058,22 +2086,21 @@
s = emalloc(sizeof(Scan), 1);
packdkey(pfx, sizeof(pfx), f->qpath, nil);
btnewscan(s, pfx, sizeof(pfx));
- lock(f);
if(f->scan != nil)
free(f->scan);
f->scan = s;
- unlock(f);
}
if(s->donescan){
r->count = 0;
- return;
+ goto Out;
}
p = r->data;
n = m->count;
if(s->overflow){
+ /* someone picked an iounit too small for a dir */
if((ns = kv2statbuf(&s->kv, p, n)) == -1){
r->count = 0;
- return;
+ error(Ebotch);
}
s->overflow = 0;
p += ns;
@@ -2090,8 +2117,11 @@
p += ns;
n -= ns;
}
- btexit(s);
r->count = p - r->data;
+ btexit(s);
+Out:
+ poperror();
+ wunlock(f);
}
static void
@@ -2102,10 +2132,12 @@
Dent *e;
Tree *t;
+ rlock(f);
e = f->dent;
rlock(e);
if(m->offset > e->length){
runlock(e);
+ runlock(f);
return;
}
p = r->data;
@@ -2124,6 +2156,7 @@
c -= n;
}
runlock(e);
+ runlock(f);
}
static void
@@ -2177,19 +2210,18 @@
rerror(m, Enofid);
return;
}
- if(!(f->mode & DMWRITE)){
- rerror(m, Einuse);
- putfid(f);
- return;
- }
+ wlock(f);
truncwait(f->dent, id);
wlock(f->dent);
if(waserror()){
rerror(m, errmsg());
wunlock(f->dent);
+ wunlock(f);
putfid(f);
return;
}
+ if(!(f->mode & DMWRITE))
+ error(Einuse);
if(f->dent->gone)
error(Ephase);
if(f->dent->qid.type & QTAUTH){
@@ -2255,6 +2287,7 @@
poperror();
respond(m, &r);
wunlock(f->dent);
+ wunlock(f);
putfid(f);
}
@@ -2328,9 +2361,9 @@
ainc(&f->ref);
unlock(&c->fidtablk[i]);
- lock(f);
+ wlock(f);
clunkfid(c, f, &a);
- unlock(f);
+ wunlock(f);
putfid(f);
if(a != nil)
@@ -2441,15 +2474,11 @@
rerror(m, Enofid);
continue;
}
- lock(f);
+ wlock(f);
clunkfid(m->conn, f, &a);
- unlock(f);
+ wunlock(f);
putfid(f);
- if(a != nil){
- clunkdent(a->mnt, a->dent);
- clunkmount(a->mnt);
- free(a);
- }
+ freeamsg(a);
}
rerror(m, Erdonly);
continue;
@@ -2736,15 +2765,13 @@
am->dent->trunc = 0;
rwakeup(&am->dent->truncrz);
qunlock(&am->dent->trunclk);
- clunkdent(am->mnt, am->dent);
}
- clunkmount(am->mnt);
poperror();
break;
}
Next:
assert(estacksz() == 0);
- free(am);
+ freeamsg(am);
}
}
--
⑨