ref: 46e7aaa19a6cdf258ff2f60292c5f074ac9d73d9
parent: 2fce59a13a759fd099d46f735f2a10face403130
author: Ori Bernstein <ori@eigenstate.org>
date: Fri May 30 09:50:53 EDT 2025
gefs: use rwlock instead of atomics for mount list Using an rwlock here simplifies reasoning about the code. The individial elements of the mount list still participate in EBR, becuase accessing them via the FID needs to be safe, but we don't need the performance of EBR when walking the list.
--- a/sys/src/cmd/gefs/cons.c
+++ b/sys/src/cmd/gefs/cons.c
@@ -173,7 +173,9 @@
for(i = 0; i < fs->nusers; i++){
u = &fs->users[i];
fprint(fd, "%d:%s:", u->id, u->name);
- if((v = uid2user(u->lead)) == nil)
+ if(u->lead == noneid)
+ fprint(fd, ":");
+ else if((v = uid2user(u->lead)) == nil)
fprint(fd, "???:");
else
fprint(fd, "%s:", v->name);
--- a/sys/src/cmd/gefs/dat.h
+++ b/sys/src/cmd/gefs/dat.h
@@ -533,7 +533,7 @@
QLock synclk;
Rendez syncrz;
- QLock mountlk;
+ RWLock mountlk;
Mount *mounts;
Mount *snapmnt;
Lock connlk;
--- a/sys/src/cmd/gefs/fs.c
+++ b/sys/src/cmd/gefs/fs.c
@@ -114,8 +114,16 @@
nexterror();
}
tracem("packb");
- for(mnt = agetp(&fs->mounts); mnt != nil; mnt = mnt->next)
+
+ rlock(&fs->mountlk);
+ if(waserror()){
+ runlock(&fs->mountlk);
+ nexterror();
+ }
+ for(mnt = fs->mounts; mnt != nil; mnt = mnt->next)
updatesnap(&mnt->root, mnt->root, mnt->name, mnt->flag);
+ runlock(&fs->mountlk);
+ poperror();
/*
* Now that we've updated the snaps, we can sync the
* dlist; the snap tree will not change from here.
@@ -204,16 +212,18 @@
static void
snapfs(Amsg *a, Tree **tp)
{
- Tree *t, *s;
+ Tree *t, *s, *r;
Mount *mnt;
+ t = nil;
+ r = nil;
+ *tp = nil;
+ rlock(&fs->mountlk);
if(waserror()){
- *tp = nil;
+ runlock(&fs->mountlk);
nexterror();
}
- t = nil;
- *tp = nil;
- for(mnt = agetp(&fs->mounts); mnt != nil; mnt = mnt->next){
+ for(mnt = fs->mounts; mnt != nil; mnt = mnt->next){
if(strcmp(a->old, mnt->name) == 0){
updatesnap(&mnt->root, mnt->root, mnt->name, mnt->flag);
t = agetp(&mnt->root);
@@ -224,6 +234,7 @@
if(t == nil && (t = opensnap(a->old, nil)) == nil){
if(a->fd != -1)
fprint(a->fd, "snap: open '%s': does not exist\n", a->old);
+ runlock(&fs->mountlk);
poperror();
return;
}
@@ -231,12 +242,13 @@
if(mnt != nil) {
if(a->fd != -1)
fprint(a->fd, "snap: snap is mounted: '%s'\n", a->old);
+ runlock(&fs->mountlk);
poperror();
return;
}
if(t->nlbl == 1 && t->nref <= 1 && t->succ == -1){
ainc(&t->memref);
- *tp = t;
+ r = t;
}
delsnap(t, t->succ, a->old);
}else{
@@ -244,6 +256,7 @@
if(a->fd != -1)
fprint(a->fd, "snap: already exists '%s'\n", a->new);
closesnap(s);
+ runlock(&fs->mountlk);
poperror();
return;
}
@@ -250,7 +263,9 @@
tagsnap(t, a->new, a->flag);
}
closesnap(t);
+ runlock(&fs->mountlk);
poperror();
+ *tp = r;
if(a->fd != -1){
if(a->delete)
fprint(a->fd, "deleted: %s\n", a->old);
@@ -415,8 +430,16 @@
{
if(!(mnt->flag & Lmut))
error(Erdonly);
- if(mnt->root->nlbl != 1 || mnt->root->nref != 0)
+ if(mnt->root->nlbl != 1 || mnt->root->nref != 0){
+ rlock(&fs->mountlk);
+ if(waserror()){
+ runlock(&fs->mountlk);
+ nexterror();
+ }
updatesnap(&mnt->root, mnt->root, mnt->name, mnt->flag);
+ poperror();
+ runlock(&fs->mountlk);
+ }
btupsert(mnt->root, m, nm);
}
@@ -679,22 +702,19 @@
return fs->snapmnt;
}
- qlock(&fs->mountlk);
- for(mnt = agetp(&fs->mounts); mnt != nil; mnt = mnt->next){
+ wlock(&fs->mountlk);
+ for(mnt = fs->mounts; mnt != nil; mnt = mnt->next){
if(strcmp(name, mnt->name) == 0){
ainc(&mnt->ref);
goto Out;
}
}
- if((mnt = mallocz(sizeof(*mnt), 1)) == nil){
- qunlock(&fs->mountlk);
- error(Enomem);
- }
if(waserror()){
- qunlock(&fs->mountlk);
+ wunlock(&fs->mountlk);
free(mnt);
nexterror();
}
+ mnt = emalloc(sizeof(*mnt), 1);
mnt->ref = 1;
snprint(mnt->name, sizeof(mnt->name), "%s", name);
if((t = opensnap(name, &flg)) == nil)
@@ -703,11 +723,11 @@
mnt->root = t;
mnt->next = fs->mounts;
loadautos(mnt);
- asetp(&fs->mounts, mnt);
+ fs->mounts = mnt;
poperror();
Out:
- qunlock(&fs->mountlk);
+ wunlock(&fs->mountlk);
return mnt;
}
@@ -718,8 +738,8 @@
if(mnt == nil)
return;
+ wlock(&fs->mountlk);
if(adec(&mnt->ref) == 0){
- qlock(&fs->mountlk);
for(p = &fs->mounts; (me = *p) != nil; p = &me->next){
if(me == mnt)
break;
@@ -727,8 +747,8 @@
assert(me != nil);
*p = me->next;
limbo(DFmnt, me);
- qunlock(&fs->mountlk);
}
+ wunlock(&fs->mountlk);
}
static void
@@ -3032,12 +3052,14 @@
tmnow(&tm, nil);
now = tmnorm(&tm);
- for(mnt = agetp(&fs->mounts); mnt != nil; mnt = mnt->next){
+ rlock(&fs->mountlk);
+ for(mnt = fs->mounts; mnt != nil; mnt = mnt->next){
if(!(mnt->flag & Lmut))
continue;
for(i = 0; i < nelem(mnt->cron); i++)
cronsync(mnt->name, &mnt->cron[i], &tm, now);
}
+ runlock(&fs->mountlk);
poperror();
}
}
--- a/sys/src/cmd/gefs/snap.c
+++ b/sys/src/cmd/gefs/snap.c
@@ -310,6 +310,8 @@
*
* If it has one successor and no label, then
* it will be merged with that successor.
+ *
+ * Must be called with mntlock held for r
*/
void
delsnap(Tree *t, vlong succ, char *name)
@@ -360,7 +362,8 @@
btupsert(&fs->snap, m, nm);
if(deltree){
reclaimblocks(t->gen, succ, t->pred);
- for(mnt = agetp(&fs->mounts); mnt != nil; mnt = mnt->next){
+ assert(!canwlock(&fs->mountlk));
+ for(mnt = fs->mounts; mnt != nil; mnt = mnt->next){
if(mnt->root->gen == t->succ)
mnt->root->pred = t->pred;
if(mnt->root->gen == t->pred)
--- a/sys/src/cmd/gefs/user.c
+++ b/sys/src/cmd/gefs/user.c
@@ -133,6 +133,7 @@
goto Error;
}
snprint(u->name, sizeof(u->name), "%s", f);
+ u->lead = noneid;
u->memb = nil;
u->nmemb = 0;
i++;
@@ -162,6 +163,11 @@
if(u == nil){
fprint(fd, "/adm/users:%d: leader %s does not exist\n", lnum, f);
err = Enouser;
+ goto Error;
+ }
+ if(u->id == noneid){
+ fprint(fd, "/adm/users:%d: group leader may not be none\n", lnum);
+ err = Esyntax;
goto Error;
}
users[i].lead = u->id;
--
⑨