shithub: gefs

Download patch

ref: 1edcad42b69b0deddf8befff489682cf94c2376d
parent: 39d119309f93dedbcd10f9004633c7a69c1f891d
author: Ori Bernstein <ori@eigenstate.org>
date: Sun Oct 22 00:28:30 EDT 2023

fs: stop leaking blocks when truncating files

--- a/dat.h
+++ b/dat.h
@@ -378,7 +378,9 @@
 		};
 		struct {	/* AOclear */
 			Mount	*mnt;
+			Dent	*dent;
 			vlong	qpath;
+			vlong	off;
 			vlong	length;
 		};
 	};
--- a/fs.c
+++ b/fs.c
@@ -1203,11 +1203,11 @@
 }
 
 static void
-fswstat(Fmsg *m)
+fswstat(Fmsg *m, Amsg **ao)
 {
 	char rnbuf[Kvmax], opbuf[Kvmax], upbuf[Upksz];
 	char *p, *e, strs[65535];
-	int op, nm, rename;
+	int op, nm, rename, truncate;
 	vlong oldlen;
 	Qid old;
 	Fcall r;
@@ -1220,6 +1220,7 @@
 	User *u;
 
 	rename = 0;
+	truncate = 0;
 	if((f = getfid(m->conn, m->fid)) == nil){
 		rerror(m, Enofid);
 		return;
@@ -1275,6 +1276,20 @@
 			goto Out;
 		}
 		if(d.length != de->length){
+			if(d.length < de->length){
+				if((*ao = malloc(sizeof(Amsg))) == nil){
+					rerror(m, Enomem);
+					goto Out;
+				}
+				aincl(&f->mnt->ref, 1);
+				(*ao)->op = AOclear;
+				(*ao)->mnt = f->mnt;
+				(*ao)->qpath = f->qpath;
+				(*ao)->off = d.length;
+				(*ao)->length = f->dent->length;
+				(*ao)->dent = de;
+				truncate = 1;
+			}
 			n.length = d.length;
 			op |= Owsize;
 			PACK64(p, n.length);
@@ -1425,7 +1440,8 @@
 	respond(m, &r);
 
 Out:
-	wunlock(de);
+	if(!truncate)
+		wunlock(de);
 	putfid(f);
 }
 
@@ -1637,7 +1653,9 @@
 		(*ao)->op = AOclear;
 		(*ao)->mnt = f->mnt;
 		(*ao)->qpath = f->qpath;
+		(*ao)->off = 0;
 		(*ao)->length = f->dent->length;
+		(*ao)->dent = nil;
 	}
 	f->dent->gone = 1;
 	wunlock(f->dent);
@@ -1742,7 +1760,9 @@
 		(*ao)->op = AOclear;
 		(*ao)->mnt = f->mnt;
 		(*ao)->qpath = f->qpath;
+		(*ao)->off = 0;
 		(*ao)->length = f->dent->length;
+		(*ao)->dent = nil;
 		if((e = upsert(f->mnt, &mb, 1)) != nil){
 Error:
 			wunlock(f->dent);
@@ -2182,7 +2202,7 @@
 		switch(m->type){
 		case Tcreate:	fscreate(m);	break;
 		case Twrite:	fswrite(m);	break;
-		case Twstat:	fswstat(m);	break;
+		case Twstat:	fswstat(m, &a);	break;
 		case Tremove:	fsremove(m,&a);	break;
 		case Topen:	fsopen(m, &a);	break;
 		default:	abort();	break;
@@ -2246,7 +2266,7 @@
 			qunlock(&fs->mutlk);
 			break;
 		case AOclear:
-			for(off = 0; off < a->length; off += Blksz){
+			for(off = a->off; off < a->length; off += Blksz){
 				qlock(&fs->mutlk);
 				epochstart(id);
 				m.k = buf;
@@ -2264,6 +2284,10 @@
 				epochend(id);
 				qunlock(&fs->mutlk);
 				epochclean();
+			}
+			if(a->dent != nil){
+				wunlock(a->dent);
+				clunkdent(a->dent);
 			}
 			clunkmount(a->mnt);
 			break;