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
--
⑨