shithub: gefs

Download patch

ref: c060aac1dc864907d750acb529553e0151f286e5
parent: 903c4891fb14330c01182ed0b565861f2c4220d5
author: Michael Forney <mforney@mforney.org>
date: Sat Feb 12 15:13:52 EST 2022

fs: add some missed putfid and fix an incorrect clunkfid condition
Omitting putfid causes leaked Fid structures and Mnt/Dent references.
Most of these are only in failure paths, so don't occur frequently.
However, fsremove never calls putfid even in the success path so
it only removes the clunk reference, not it's local reference.

In fswalk, if m->fid != m->newfid, but we didn't walk the full path,
then we haven't duped into newfid. If getdent fails, then we end
up clunking the original fid. This would cause an Efid the next
time the client tries to use it.

--- a/fs.c
+++ b/fs.c
@@ -796,6 +796,7 @@
 	}
 	if(o->mode != -1){
 		rerror(m, Einuse);
+		putfid(o);
 		return;
 	}
 	e = nil;
@@ -856,7 +857,7 @@
 	if(i > 0){
 		dent = getdent(up, &d);
 		if(dent == nil){
-			if(m->fid != m->newfid)
+			if(f != o)
 				clunkfid(f);
 			rerror(m, Enomem);
 			putfid(f);
@@ -1094,13 +1095,15 @@
 	}
 	if(m->perm & (DMMOUNT|DMAUTH)){
 		rerror(m, "unknown permission");
+		putfid(f);
 		return;
 	}
 	de = f->dent;
 	rlock(de);
 	if(fsaccess(f, de->mode, de->uid, de->gid, DMWRITE) == -1){
-		rerror(m, Eperm);
 		runlock(de);
+		rerror(m, Eperm);
+		putfid(f);
 		return;
 	}
 	runlock(de);
@@ -1233,6 +1236,7 @@
 		rerror(m, Efid);
 		return;
 	}
+	clunkfid(f);
 
 	rlock(f->dent);
 	if((e = candelete(f)) != nil)
@@ -1253,17 +1257,16 @@
 			goto Error;
 	}
 
-	clunkfid(f);
 	runlock(f->dent);
 	r.type = Rremove;
 	respond(m, &r);
+	putfid(f);
 	return;
 
 Error:
-	clunkfid(f);
 	runlock(f->dent);
 	rerror(m, e);
-	return;
+	putfid(f);
 }
 
 static void
@@ -1337,6 +1340,7 @@
 		if((e = btupsert(f->mnt->root, &mb, 1)) != nil){
 			wunlock(f->dent);
 			rerror(m, e);
+			putfid(f);
 			return;
 		}
 		wunlock(f->dent);