shithub: riscv

Download patch

ref: c3d2d3f2ab7e0ad244661511ed328510bc1aeab1
parent: 01ed94c60df156518ce434401dfd471dd620ae4e
author: Ori Bernstein <ori@eigenstate.org>
date: Sat Feb 22 15:52:48 EST 2025

gefs: cleanly reject too many connections

before this commit, gefs would allow many attempts to
attach, but would blow up when we ran out of epoch ids;
now, we should log an error and reject the connection.

--- a/sys/src/cmd/gefs/blk.c
+++ b/sys/src/cmd/gefs/blk.c
@@ -849,6 +849,7 @@
 {
 	ulong ge;
 
+	assert(tid >= 0);
 	ge = agetl(&fs->epoch);
 	asetl(&fs->lepoch[tid], ge | Eactive);
 }
@@ -858,6 +859,7 @@
 {
 	ulong le;
 
+	assert(tid >= 0);
 	le = agetl(&fs->lepoch[tid]);
 	asetl(&fs->lepoch[tid], le &~ Eactive);
 }
--- a/sys/src/cmd/gefs/dat.h
+++ b/sys/src/cmd/gefs/dat.h
@@ -84,6 +84,7 @@
 	Leafspc 	= Blksz - Leafhdsz,
 	Msgmax  	= 1 + (Kvmax > Kpmax ? Kvmax : Kpmax),
 	Estacksz	= 64,
+	Maxprocs	= 128,
 };
 
 enum {
@@ -516,6 +517,7 @@
 	long	syncing;
 	long	nsyncers;
 	long	nreaders;
+	long	nprocs;
 
 	QLock	synclk;
 	Rendez	syncrz;
--- a/sys/src/cmd/gefs/fns.h
+++ b/sys/src/cmd/gefs/fns.h
@@ -64,7 +64,6 @@
 void	freeblk(Tree*, Blk*);
 void	freebp(Tree*, Bptr);
 int	logbarrier(Arena *, vlong);
-void	dlappend(Dlist *dl, Bptr);
 void	killblk(Tree*, Bptr);
 ushort	blkfill(Blk*);
 uvlong	blkhash(Blk*);
--- a/sys/src/cmd/gefs/main.c
+++ b/sys/src/cmd/gefs/main.c
@@ -189,26 +189,39 @@
 	}
 }
 
-static void
-launch(void (*f)(int, void *), void *arg, char *text)
+static int
+launch(void (*f)(int, void *), void *arg, long id, char *text)
 {
-	long pid, id;
+	long pid;
 
-	assert(fs->nworker < nelem(fs->lepoch));
+	assert(id == -1 || id < nelem(fs->lepoch));
+	if(aincl(&fs->nprocs, 1) >= Maxprocs){
+		werrstr("too many worker procs\n");
+		return -1;
+	}
 	pid = rfork(RFPROC|RFMEM|RFNOWAIT);
 	if (pid < 0)
-		sysfatal("can't fork: %r");
+		werrstr("fork: %r");
 	if (pid == 0) {
-		id = aincl(&fs->nworker, 1);
 		if((*errctx = mallocz(sizeof(Errctx), 1)) == nil)
 			sysfatal("malloc: %r");
 		(*errctx)->tid = id;
 		procsetname("%s.%ld", text, id);
 		(*f)(id, arg);
+		aincl(&fs->nprocs, -1);
 		exits("child returned");
 	}
+	return pid;
 }
 
+/* launches a proc that must start, kills the file system if it fails */
+static void
+xlaunch(void (*f)(int, void*), void *arg, long id, char *text)
+{
+	if(launch(f, arg, id, text) == -1)
+		sysfatal("setting up initial proc set failed: %r");
+}
+
 static int
 postfd(char *name, char *suff, int mode)
 {
@@ -255,7 +268,10 @@
 			close(fd);
 			continue;
 		}
-		launch(runfs, c, "netio");
+		if(launch(runfs, c, -1, "netio") == -1){
+			fprint(2, "listener failed: %r");
+			putconn(c);
+		}
 	}
 	close(actl);
 }
@@ -411,25 +427,25 @@
 		fs->arenas[i].sync = &fs->syncq[i%fs->nsyncers];
 	srvfd = postfd(srvname, "", 0666);
 	ctlfd = postfd(srvname, ".cmd", 0600);
-	launch(runcons, (void*)ctlfd, "ctl");
-	launch(runmutate, nil, "mutate");
-	launch(runsweep, nil, "sweep");
-	launch(runtasks, nil, "tasks");
+	xlaunch(runcons, (void*)ctlfd, aincl(&fs->nworker, 1), "ctl");
+	xlaunch(runmutate, nil, aincl(&fs->nworker, 1), "mutate");
+	xlaunch(runsweep, nil, aincl(&fs->nworker, 1), "sweep");
+	xlaunch(runtasks, nil, aincl(&fs->nworker, 1), "tasks");
 	for(i = 0; i < fs->nreaders; i++)
-		launch(runread, fs->rdchan[i], "readio");
+		xlaunch(runread, fs->rdchan[i], aincl(&fs->nworker, 1), "readio");
 	for(i = 0; i < fs->nsyncers; i++)
-		launch(runsync, &fs->syncq[i], "syncio");
+		xlaunch(runsync, &fs->syncq[i], aincl(&fs->nworker, 1), "syncio");
 	for(i = 0; i < nann; i++)
-		launch(runannounce, ann[i], "announce");
+		xlaunch(runannounce, ann[i], -1, "announce");
 	if(srvfd != -1){
 		if((c = newconn(srvfd, srvfd, -1)) == nil)
 			sysfatal("%r");
-		launch(runfs, c, "srvio");
+		xlaunch(runfs, c, -1, "srvio");
 	}
 	if(stdio){
 		if((c = newconn(0, 1, -1)) == nil)
 			sysfatal("%r");
-		launch(runfs, c, "stdio");
+		xlaunch(runfs, c, -1, "stdio");
 	}
 	exits(nil);
 }
--