shithub: ridefs

Download patch

ref: 4401e746299f6c7c0665cefb557c455d4edb7d9f
parent: 9883fb9af749887da25d9ed95699064b7a10cc00
author: B. Wilson <x@wilsonb.com>
date: Mon Jun 23 10:40:27 EDT 2025

Fix race condition on r/w forks

--- a/ridefs.c
+++ b/ridefs.c
@@ -34,7 +34,7 @@
 		Qclone,
 		Qclient,
 			Qctl,
-			Qio,
+			Qdata,
 			Qinfo,
 	QCOUNT
 };
@@ -45,7 +45,7 @@
 		"clone",
 		nil,
 			"ctl",
-			"io",
+			"data",
 			"info",
 };
 
@@ -228,7 +228,7 @@
 rideinit(char *addr, int *fd, int *cfd, char **info){
 	int i;
 	char *b;
-	JSON *j;
+	JSON *j, *v;
 	JSONEl *d;
 
 	b = netmkaddr(addr, "tcp", defport);
@@ -258,7 +258,8 @@
 	free(b);
 	if(j == nil || j->t != JSONArray || nil == j->first)
 		return "unrecognized reply";
-	if(nil == (b = jsonstr(j->first->val)) || 0 != strcmp(b, "ReplyIdentify"))
+	v = j->first->val;
+	if(v->t != JSONString || 0 != strcmp(v->s, "ReplyIdentify"))
 		return "unexpected identification reply";
 	if(nil == (d = j->first->next) || d->val->t != JSONObject)
 		return "malformed identification reply";
@@ -343,13 +344,13 @@
 	switch(kind){
 	case Qrctl:   d->mode = 0666; break;
 	case Qctl:
-	case Qio:     d->mode = 0666; break;
+	case Qdata:     d->mode = 0666; break;
 	}
 
 	switch(kind){
 	case Qrctl: d->length = strlen(qrctl); break;
 	case Qctl: d->length = strlen(c->qctl); break;
-	case Qio: d->length = 0; break;
+	case Qdata: d->length = 0; break;
 	case Qinfo: d->length = strlen(c->qinfo); break;
 	}
 }
@@ -429,7 +430,6 @@
 
 static void
 fsopen(Req *r){
-	int pid;
 	char *err;
 	Rfid *f;
 	Client *c;
@@ -451,32 +451,33 @@
 
 		respond(r, nil);
 		break;
-	case Qio:
+	case Qdata:
 		if(nil == c->addr){
 			respond(r, "no server set");
 			return;
 		}
 
-		switch(pid = rfork(RFPROC|RFNOWAIT|RFMEM)){
+		qlock(c);
+		incref(&r->ref);
+		c->req = r;
+		switch(c->pid = rfork(RFPROC|RFNOWAIT|RFMEM)){
 		case 0:
-			qlock(c);
-			if(c->fd)
-				goto end;
-
-			err = rideinit(c->addr, &c->fd, &c->cfd, &c->qinfo);
+			if(!c->fd)
+				err = rideinit(c->addr, &c->fd, &c->cfd, &c->qinfo);
 			c->pid = 0;
 			c->req = nil;
-
-			end:
+			decref(&r->ref);
 			respond(r, err);
 			qunlock(c);
 			exits(nil);
 		case -1:
 			respond(r, "failed to init ride");
+			c->pid = 0;
+			c->req = nil;
+			decref(&r->ref);
+			qunlock(c);
 			break;
 		default:
-			c->pid = pid;
-			c->req = r;
 			return;
 		}
 		break;
@@ -490,7 +491,7 @@
 	Rfid *f;
 	Client *c;
 	char *buf, *err;
-	int pid, n, off;
+	int n, off;
 
 	buf = err = nil;
 	f = r->fid->aux;
@@ -502,11 +503,12 @@
 	case Qclient: dirread9p(r, genqclient, (void*)f->client); break;
 	case Qctl: buf = estrdup(c->qctl); break;
 	case Qinfo: buf = estrdup(c->qinfo); break;
-	case Qio:
-		switch(pid = rfork(RFPROC|RFNOWAIT|RFMEM)){
+	case Qdata:
+		qlock(c);
+		incref(&r->ref);
+		c->req = r;
+		switch(c->pid = rfork(RFPROC|RFNOWAIT|RFMEM)){
 		case 0:
-			qlock(c);
-
 			off = r->ifcall.offset - c->roff;
 			if(c->rn < 0){
 				free(c->r);
@@ -525,18 +527,20 @@
 				r->ofcall.count = n;
 			}
 
-			respond(r, err);
 			c->pid = 0;
 			c->req = nil;
-
+			decref(&r->ref);
+			respond(r, err);
 			qunlock(c);
 			exits(nil);
 		case -1:
 			err = "failed to fork read";
+			c->pid = 0;
+			c->req = nil;
+			decref(&r->ref);
+			qunlock(c);
 			break;
 		default:
-			c->pid = pid;
-			c->req = r;
 			return;
 		}
 		break;
@@ -554,7 +558,6 @@
 fswrite(Req *r){
 	Rfid *f;
 	Client *c;
-	int pid;
 	char *d, *err;
 	long n;
 
@@ -571,24 +574,29 @@
 	case Qctl:
 		r->ofcall.count = writeqctl(d, n, f->client);
 		break;
-	case Qio:
-		switch(pid = rfork(RFPROC|RFNOWAIT|RFMEM)){
+	case Qdata:
+		qlock(c);
+		incref(&r->ref);
+		c->req = r;
+		switch(c->pid = rfork(RFPROC|RFNOWAIT|RFMEM)){
 		case 0:
-			qlock(c);
 			r->ofcall.count = writemsg(c->fd, d, n);
 
-			respond(r, nil);
 			c->pid = 0;
 			c->req = nil;
+			decref(&r->ref);
+			respond(r, nil);
 
 			qunlock(c);
 			exits(nil);
 		case -1:
 			err = "failed to fork write";
+			c->pid = 0;
+			c->req = nil;
+			decref(&r->ref);
+			qunlock(c);
 			break;
 		default:
-			c->pid = pid;
-			c->req = r;
 			return;
 		}
 		break;
@@ -613,6 +621,7 @@
 		respond(c->req, "interrupted");
 		c->pid = 0;
 		c->req = nil;
+		decref(&c->req->ref);
 		qunlock(c);
 	}
 
--- a/test
+++ b/test
@@ -57,7 +57,7 @@
 	echo 'connect 192.168.11.17' >ctl ||
 		fail 'Could not connect to server'
 
-	<>io >[1=0] {
+	<>data >[1=0] {
 		~ `{wc -c info} 0 &&
 			fail 'Did not receive RIDE info'
 
@@ -78,12 +78,12 @@
 	cd `{read}
 	echo 'connect 192.168.11.17' >ctl
 
-	<>io >[1=0] {
+	<>data >[1=0] {
 		msg='["Execute",{"text":"⍳5\n","trace":0}]'
 		echo -n $msg || fail 'Could not send message'
 	} & spid=$apid
 
-	<>io >[1=0] {
+	<>data >[1=0] {
 		cat >/dev/null || fail 'Could not receive message'
 	} & rpid=$apid
 
--