ref: d8cf26110d5c98a0568260caf772ed8c10b2a395
parent: b061a21bfae3da3fbca2eb85542d6ebca1719c67
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Wed Aug 28 14:34:14 EDT 2024
gefs: properly close and free connections Before, we would just leak all the "Conn" structures. fshangup() could cause problems as it just forcefully closes the file descriptors, not considering someone else going to write them afterwards. Instead, we add a "hangup" flag to Conn, which readers and writers check before attempting i/o. And we only close the file-descriptors when the last reader/writer drops the connection. (Make it ref-counted). For faster teardown, also preserve the "ctl" file descriptor from listen() amd use it to kill the connection quickly when fshangup() is called.
--- a/sys/src/cmd/gefs/dat.h
+++ b/sys/src/cmd/gefs/dat.h
@@ -654,12 +654,18 @@
struct Conn {
Conn *next;
+
QLock wrlk;
+
int rfd;
int wfd;
+ int cfd;
int iounit;
int versioned;
int authok;
+ int hangup;
+
+ long ref;
/* fid hash table */
Lock fidtablk[Nfidtab];
--- a/sys/src/cmd/gefs/fns.h
+++ b/sys/src/cmd/gefs/fns.h
@@ -94,7 +94,8 @@
void dlsync(void);
void setval(Blk*, Kvp*);
-Conn* newconn(int, int);
+Conn* newconn(int, int, int);
+void putconn(Conn*);
int walk1(Tree*, vlong, char*, Qid*, vlong*);
void loadusers(int, Tree*);
--- a/sys/src/cmd/gefs/fs.c
+++ b/sys/src/cmd/gefs/fs.c
@@ -344,38 +344,23 @@
{
char buf[ERRMAX];
va_list ap;
- Amsg *a;
- Fid *f;
- int i;
+ c->hangup = 1;
+
va_start(ap, fmt);
vsnprint(buf, sizeof(buf), fmt, ap);
va_end(ap);
+
fprint(2, "hangup: %s\n", buf);
- close(c->rfd);
- close(c->wfd);
- for(i = 0; i < Nfidtab; i++){
- lock(&c->fidtablk[i]);
- for(f = c->fidtab[i]; f != nil; f = f->next){
- lock(f);
- if(waserror()){
- unlock(f);
- continue;
- }
- a = nil;
- clunkfid(c, f, &a);
- unlock(f);
- if(a != nil)
- chsend(fs->admchan, a);
- nexterror();
- }
- unlock(&c->fidtablk[i]);
- }
+
+ if(c->cfd >= 0)
+ hangup(c->cfd);
}
static void
respond(Fmsg *m, Fcall *r)
{
+ Conn *c;
RWLock *lk;
uchar buf[Max9p+IOHDRSZ];
int w, n;
@@ -385,11 +370,12 @@
assert(m->type+1 == r->type || r->type == Rerror);
if((n = convS2M(r, buf, sizeof(buf))) == 0)
abort();
- qlock(&m->conn->wrlk);
- w = write(m->conn->wfd, buf, n);
- qunlock(&m->conn->wrlk);
+ c = m->conn;
+ qlock(&c->wrlk);
+ w = c->hangup? n: write(c->wfd, buf, n);
+ qunlock(&c->wrlk);
if(w != n)
- fshangup(m->conn, Eio);
+ fshangup(c, Eio);
if(m->type == Tflush){
lk = &fs->flushq[ihash(m->oldtag) % Nflushtab];
wunlock(lk);
@@ -398,6 +384,7 @@
runlock(lk);
}
free(m);
+ putconn(c);
}
static void
@@ -850,6 +837,7 @@
free(m);
return -1;
}
+ aincl(&c->ref, 1);
m->conn = c;
m->sz = sz;
PBIT32(m->buf, sz);
@@ -2256,23 +2244,76 @@
}
Conn *
-newconn(int rfd, int wfd)
+newconn(int rfd, int wfd, int cfd)
{
Conn *c;
if((c = mallocz(sizeof(*c), 1)) == nil)
return nil;
+
c->rfd = rfd;
c->wfd = wfd;
+ c->cfd = cfd;
+
c->iounit = Max9p;
- c->next = fs->conns;
+
+ c->ref = 1;
+
lock(&fs->connlk);
+ c->next = fs->conns;
fs->conns = c;
unlock(&fs->connlk);
+
return c;
}
void
+putconn(Conn *c)
+{
+ Conn **pp;
+ Amsg *a;
+ Fid *f;
+ int i;
+
+ if(aincl(&c->ref, -1))
+ return;
+
+ lock(&fs->connlk);
+ for(pp = &fs->conns; *pp != nil; pp = &((*pp)->next)){
+ if(*pp == c){
+ *pp = c->next;
+ break;
+ }
+ }
+ unlock(&fs->connlk);
+
+ close(c->rfd);
+ if(c->rfd != c->wfd)
+ close(c->wfd);
+ if(c->cfd >= 0)
+ close(c->cfd);
+
+ for(i = 0; i < Nfidtab; i++){
+ lock(&c->fidtablk[i]);
+ for(f = c->fidtab[i]; f != nil; f = f->next){
+ lock(f);
+ if(waserror()){
+ unlock(f);
+ continue;
+ }
+ a = nil;
+ clunkfid(c, f, &a);
+ unlock(f);
+ if(a != nil)
+ chsend(fs->admchan, a);
+ nexterror();
+ }
+ unlock(&c->fidtablk[i]);
+ }
+ free(c);
+}
+
+void
runfs(int, void *pc)
{
char err[128];
@@ -2284,20 +2325,20 @@
u32int h;
c = pc;
- while(1){
+ while(!c->hangup){
if(readmsg(c, &m) < 0){
fshangup(c, "read message: %r");
- return;
+ break;
}
if(m == nil)
break;
if(convM2S(m->buf, m->sz, m) == 0){
fshangup(c, "invalid message: %r");
- return;
+ break;
}
if(m->type != Tversion && !c->versioned){
fshangup(c, "version required");
- return;
+ break;
}
dprint("← %F\n", &m->Fcall);
@@ -2350,6 +2391,7 @@
if(a != nil)
chsend(fs->admchan, a);
}
+ putconn(c);
}
void
--- a/sys/src/cmd/gefs/main.c
+++ b/sys/src/cmd/gefs/main.c
@@ -257,21 +257,22 @@
sysfatal("announce %s: %r", ann);
while(1){
if((lctl = listen(adir, ldir)) < 0){
- fprint(2, "listen %s: %r", adir);
+ fprint(2, "listen %s: %r\n", adir);
break;
}
fd = accept(lctl, ldir);
- close(lctl);
if(fd < 0){
- fprint(2, "accept %s: %r", ldir);
+ fprint(2, "accept %s: %r\n", ldir);
+ close(lctl);
continue;
}
- if(!(c = newconn(fd, fd))){
+ c = newconn(fd, fd, lctl);
+ if(c == nil){
+ fprint(2, "newconn: %r\n");
+ close(lctl);
close(fd);
- fprint(2, "%r");
continue;
}
-
launch(runfs, c, "netio");
}
close(actl);
@@ -440,12 +441,12 @@
for(i = 0; i < nann; i++)
launch(runannounce, ann[i], "announce");
if(srvfd != -1){
- if((c = newconn(srvfd, srvfd)) == nil)
+ if((c = newconn(srvfd, srvfd, -1)) == nil)
sysfatal("%r");
launch(runfs, c, "srvio");
}
if(stdio){
- if((c = newconn(0, 1)) == nil)
+ if((c = newconn(0, 1, -1)) == nil)
sysfatal("%r");
launch(runfs, c, "stdio");
}
--
⑨