ref: e3c68a8e1bb6c6a40622ec5efc88dcfcc0714d0c
parent: c5c5553b4518e787443a462cba1f657499ba257e
author: Ori Bernstein <ori@eigenstate.org>
date: Sun Jan 7 21:30:48 EST 2024
fs: fix locking and length around file truncation
--- a/dat.h
+++ b/dat.h
@@ -620,9 +620,11 @@
Xdir;
Dent *next;
QLock trunclk;
+ Rendez truncrz;
vlong up;
long ref;
char gone;
+ char trunc;
char buf[Maxent];
};
--- a/fs.c
+++ b/fs.c
@@ -396,13 +396,14 @@
static void
truncwait(Dent *de, int id)
{
- if(canqlock(&de->trunclk))
- return;
- epochend(id);
qunlock(&fs->mutlk);
qlock(&de->trunclk);
- qlock(&fs->mutlk);
+ epochend(id);
+ while(de->trunc)
+ rsleep(&de->truncrz);
epochstart(id);
+ qunlock(&de->trunclk);
+ qlock(&fs->mutlk);
}
static int
@@ -509,6 +510,7 @@
de->up = pqid;
de->qid = d->qid;
de->length = d->length;
+ de->truncrz.l = &de->trunclk;
if((e = packdkey(de->buf, sizeof(de->buf), pqid, d->name)) == nil){
free(de);
@@ -1301,7 +1303,7 @@
{
char rnbuf[Kvmax], opbuf[Kvmax], upbuf[Upksz];
char *p, strs[65535];
- int op, nm, rename, truncate;
+ int op, nm, rename;
vlong oldlen;
Qid old;
Fcall r;
@@ -1316,7 +1318,6 @@
*ao = nil;
rename = 0;
- truncate = 0;
if((f = getfid(m->conn, m->fid)) == nil){
rerror(m, Enofid);
return;
@@ -1367,6 +1368,9 @@
if(d.length < de->length){
if((*ao = malloc(sizeof(Amsg))) == nil)
error(Enomem);
+ qlock(&de->trunclk);
+ de->trunc = 1;
+ qunlock(&de->trunclk);
aincl(&de->ref, 1);
aincl(&f->mnt->ref, 1);
(*ao)->op = AOclear;
@@ -1375,7 +1379,6 @@
(*ao)->off = d.length;
(*ao)->length = f->dent->length;
(*ao)->dent = de;
- truncate = 1;
}
de->length = d.length;
n.length = d.length;
@@ -1501,9 +1504,7 @@
respond(m, &r);
poperror();
-Err: if(!truncate)
- qunlock(&de->trunclk);
- wunlock(de);
+Err: wunlock(de);
putfid(f);
}
@@ -1719,7 +1720,7 @@
r.type = Rremove;
respond(m, &r);
poperror();
-Err: qunlock(&f->dent->trunclk);
+Err:
wunlock(f->dent);
putfid(f);
return;
@@ -1747,6 +1748,8 @@
putfid(f);
return;
}
+ if(m->mode & OTRUNC)
+ truncwait(f->dent, id);
t = agetp(&f->mnt->root);
if((f->qpath & Qdump) != 0){
filldumpdir(&d);
@@ -1781,8 +1784,27 @@
}
f->mode = mode2bits(m->mode);
if(m->mode & OTRUNC){
- truncwait(f->dent, id);
wlock(f->dent);
+
+ if(waserror()){
+ wunlock(f->dent);
+ free(*ao);
+ *ao = nil;
+ nexterror();
+ }
+ *ao = emalloc(sizeof(Amsg), 1);
+ qlock(&f->dent->trunclk);
+ f->dent->trunc = 1;
+ qunlock(&f->dent->trunclk);
+ aincl(&f->dent->ref, 1);
+ aincl(&f->mnt->ref, 1);
+ (*ao)->op = AOclear;
+ (*ao)->mnt = f->mnt;
+ (*ao)->qpath = f->qpath;
+ (*ao)->off = 0;
+ (*ao)->length = f->dent->length;
+ (*ao)->dent = f->dent;
+
f->dent->muid = f->uid;
f->dent->qid.vers++;
f->dent->length = 0;
@@ -1796,21 +1818,8 @@
mb.nk = f->dent->nk;
mb.v = buf;
mb.nv = p - buf;
- if(waserror()){
- qunlock(&f->dent->trunclk);
- wunlock(f->dent);
- nexterror();
- }
- *ao = emalloc(sizeof(Amsg), 1);
- aincl(&f->mnt->ref, 1);
- (*ao)->op = AOclear;
- (*ao)->mnt = f->mnt;
- (*ao)->qpath = f->qpath;
- (*ao)->off = 0;
- (*ao)->length = f->dent->length;
- (*ao)->dent = nil;
+
upsert(f->mnt, &mb, 1);
- qunlock(&f->dent->trunclk);
wunlock(f->dent);
poperror();
}
@@ -2024,7 +2033,6 @@
wlock(f->dent);
if(waserror()){
rerror(m, errmsg());
- qunlock(&f->dent->trunclk);
wunlock(f->dent);
putfid(f);
return;
@@ -2091,7 +2099,6 @@
Out:
poperror();
respond(m, &r);
- qunlock(&f->dent->trunclk);
wunlock(f->dent);
putfid(f);
}
@@ -2435,6 +2442,8 @@
ainc(&fs->rdonly);
break;
}
+ if(am->dent != nil)
+ qlock(&am->dent->trunclk);
for(off = am->off; off < am->length; off += Blksz){
qlock(&fs->mutlk);
if(waserror()){
@@ -2457,6 +2466,8 @@
poperror();
}
if(am->dent != nil){
+ am->dent->trunc = 0;
+ rwakeup(&am->dent->truncrz);
qunlock(&am->dent->trunclk);
clunkdent(am->dent);
}