shithub: gefs

Download patch

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);
 			}