shithub: front

Download patch

ref: d31382ca17d92fe7c0b3c45f418f605d1759ed55
parent: 0ab0a036edd97a461b1b0b1ff5c5c8274f2a6f7b
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Fri Aug 30 15:16:13 EDT 2024

gefs: fix fidtab locking order in clunkfid()

Do not abuse fidtab lock for serializing
clunking.

The clunk should serialize on Fid.Lock
instead, so add a canlock check here.

The lock order is strictly:

Fid.Lock > Conn.fidtab[x].Lock

--- a/sys/src/cmd/gefs/fs.c
+++ b/sys/src/cmd/gefs/fs.c
@@ -769,6 +769,11 @@
 	return n;
 }
 
+/*
+ * clunkfid() removes a fid from the
+ * connection fid tab and drops reference.
+ * Fid must be locked.
+ */
 static void
 clunkfid(Conn *c, Fid *fid, Amsg **ao)
 {
@@ -775,6 +780,8 @@
 	Fid *f, **pf;
 	u32int h;
 
+	assert(!canlock(fid));
+
 	h = ihash(fid->fid) % Nfidtab;
 	lock(&c->fidtablk[h]);
 	pf = &c->fidtab[h];
@@ -786,6 +793,8 @@
 		}
 		pf = &f->next;
 	}
+	unlock(&c->fidtablk[h]);
+
 	assert(f != nil);
 	if(f->scan != nil){
 		free(f->scan);
@@ -811,7 +820,6 @@
 		(*ao)->end = f->dent->length;
 		(*ao)->dent = f->dent;
 	}
-	unlock(&c->fidtablk[h]);
 }
 
 static int
@@ -1796,8 +1804,8 @@
 	}
 	t = f->mnt->root;
 	nm = 0;
-	*ao = nil;
 	lock(f);
+	*ao = nil;
 	clunkfid(m->conn, f, ao);
 	/* rclose files are getting removed here anyways */
 	if(*ao != nil)
@@ -2291,7 +2299,7 @@
 {
 	Conn **pp;
 	Amsg *a;
-	Fid *f, *nf;
+	Fid *f;
 	int i;
 
 	if(adec(&c->ref) != 0)
@@ -2313,19 +2321,25 @@
 		close(c->cfd);
 
 	for(i = 0; i < Nfidtab; i++){
-		lock(&c->fidtablk[i]);
-		for(f = c->fidtab[i]; f != nil; f = nf){
-			nf = f->next;
+		for(;;){
+			lock(&c->fidtablk[i]);
+			f = c->fidtab[i];
+			if(f == nil){
+				unlock(&c->fidtablk[i]);
+				break;
+			}
 			ainc(&f->ref);
+			unlock(&c->fidtablk[i]);
+			
 			lock(f);
 			a = nil;
 			clunkfid(c, f, &a);
 			unlock(f);
 			putfid(f);
+
 			if(a != nil)
 				chsend(fs->admchan, a);
 		}
-		unlock(&c->fidtablk[i]);
 	}
 	free(c);
 }
--