nusb/ptp: fix memory leaks, use libthread/ioprocs, cleanup

This commit is contained in:
cinap_lenrek 2011-08-22 03:05:01 +02:00
parent c360ea5511
commit 68576f5119
2 changed files with 229 additions and 202 deletions

View file

@ -5,7 +5,7 @@ LIB=../lib/usb.a$O
TARG=ptp TARG=ptp
HFILES= HFILES=
OFILES=usbptp.$O OFILES=ptp.$O
</sys/src/cmd/mkone </sys/src/cmd/mkone

View file

@ -35,6 +35,9 @@ enum {
}; };
typedef struct Ptprpc Ptprpc; typedef struct Ptprpc Ptprpc;
typedef struct Node Node;
typedef struct Ioflush Ioflush;
struct Ptprpc struct Ptprpc
{ {
uchar length[4]; uchar length[4];
@ -47,7 +50,6 @@ struct Ptprpc
}; };
}; };
typedef struct Node Node;
struct Node struct Node
{ {
Dir d; Dir d;
@ -64,14 +66,21 @@ struct Node
int ndata; int ndata;
}; };
int debug; struct Ioflush
{
Channel *c;
Ioproc *io;
};
enum { enum {
In, In,
Out, Out,
}; };
static Dev *usbep[2]; static Dev *usbep[2];
static int debug;
static ulong time0; static ulong time0;
static int maxpacket = 64; static int maxpacket = 64;
static int sessionId = 0; static int sessionId = 0;
@ -80,7 +89,10 @@ static int transId = 0;
static Node **nodes; static Node **nodes;
static int nnodes; static int nnodes;
static char *uname; static Channel *iochan;
char Eperm[] = "permission denied";
char Einterrupt[] = "interrupted";
#define PATH(type, n) ((uvlong)(type)|((uvlong)(n)<<4)) #define PATH(type, n) ((uvlong)(type)|((uvlong)(n)<<4))
#define TYPE(path) ((int)((path)&0xF)) #define TYPE(path) ((int)((path)&0xF))
@ -117,8 +129,8 @@ wasinterrupt(void)
char err[ERRMAX]; char err[ERRMAX];
rerrstr(err, sizeof(err)); rerrstr(err, sizeof(err));
if(strstr(err, "interrupted") || strstr(err, "request timed out")){ if(strstr(err, Einterrupt) || strstr(err, "timed out")){
werrstr("interrupted"); werrstr(Einterrupt);
return 1; return 1;
} }
return 0; return 0;
@ -200,7 +212,7 @@ ptpcheckerr(Ptprpc *rpc, int type, int transid, int length)
} }
static int static int
vptprpc(int code, int flags, va_list a) vptprpc(Ioproc *io, int code, int flags, va_list a)
{ {
Ptprpc rpc; Ptprpc rpc;
int np, n, t, i, l; int np, n, t, i, l;
@ -223,7 +235,7 @@ vptprpc(int code, int flags, va_list a)
hexdump("req>", (uchar*)&rpc, n); hexdump("req>", (uchar*)&rpc, n);
werrstr(""); werrstr("");
if(write(usbep[Out]->dfd, &rpc, n) != n){ if(iowrite(io, usbep[Out]->dfd, &rpc, n) != n){
wasinterrupt(); wasinterrupt();
return -1; return -1;
} }
@ -251,14 +263,14 @@ vptprpc(int code, int flags, va_list a)
if(debug) if(debug)
hexdump("data>", (uchar*)&rpc, n); hexdump("data>", (uchar*)&rpc, n);
if(write(usbep[Out]->dfd, &rpc, n) != n){ if(iowrite(io, usbep[Out]->dfd, &rpc, n) != n){
wasinterrupt(); wasinterrupt();
return -1; return -1;
} }
while(p < e){ while(p < e){
if((n = write(usbep[Out]->dfd, p, e-p)) < 0){ if((n = iowrite(io, usbep[Out]->dfd, p, e-p)) < 0){
wasinterrupt(); if(!wasinterrupt())
break; return -1;
} }
p += n; p += n;
} }
@ -275,11 +287,11 @@ vptprpc(int code, int flags, va_list a)
*prdatalen = 0; *prdatalen = 0;
do{ do{
if((n = read(usbep[In]->dfd, &rpc, sizeof(rpc))) < 0){ if((n = ioread(io, usbep[In]->dfd, &rpc, sizeof(rpc))) < 0){
wasinterrupt(); wasinterrupt();
return -1; return -1;
} }
if(debug > 1) if(debug)
hexdump("data<", (uchar*)&rpc, n); hexdump("data<", (uchar*)&rpc, n);
if((l = ptpcheckerr(&rpc, 2, t, n)) < 0) if((l = ptpcheckerr(&rpc, 2, t, n)) < 0)
return -1; return -1;
@ -301,7 +313,7 @@ vptprpc(int code, int flags, va_list a)
p += n; p += n;
while(p < e){ while(p < e){
if((n = read(usbep[In]->dfd, p, e-p)) < 0){ if((n = ioread(io, usbep[In]->dfd, p, e-p)) < 0){
wasinterrupt(); wasinterrupt();
free(b); free(b);
return -1; return -1;
@ -313,11 +325,11 @@ vptprpc(int code, int flags, va_list a)
} }
do { do {
if((n = read(usbep[In]->dfd, &rpc, sizeof(rpc))) < 0){ if((n = ioread(io, usbep[In]->dfd, &rpc, sizeof(rpc))) < 0){
wasinterrupt(); wasinterrupt();
return -1; return -1;
} }
if(debug > 1) if(debug)
hexdump("resp<", (uchar*)&rpc, n); hexdump("resp<", (uchar*)&rpc, n);
if((l = ptpcheckerr(&rpc, 3, t, n)) < 0) if((l = ptpcheckerr(&rpc, 3, t, n)) < 0)
return -1; return -1;
@ -335,30 +347,60 @@ vptprpc(int code, int flags, va_list a)
return 0; return 0;
} }
static void
ioflusher(void *aux)
{
Ioflush f = *((Ioflush*)aux);
while(recvp(f.c))
iointerrupt(f.io);
chanfree(f.c);
}
static int static int
ptprpc(Req *r, int code, int flags, ...) ptprpc(Req *r, int code, int flags, ...)
{ {
static long ptpsem = 1; va_list va;
va_list a; Ioflush f;
Alt a[3];
char *m;
int i; int i;
if(r != nil){ i = -1;
r->aux = (void*)getpid(); f.c = nil;
f.io = nil;
m = Einterrupt;
a[0].op = CHANRCV;
a[0].c = iochan;
a[0].v = &f.io;
if(r){
f.c = chancreate(sizeof(char*), 0);
a[1].op = CHANRCV;
a[1].c = f.c;
a[1].v = &m;
a[2].op = CHANEND;
r->aux = f.c;
srvrelease(r->srv); srvrelease(r->srv);
} } else
i = semacquire(&ptpsem, 1); a[1].op = CHANEND;
if(i == 1){ if(alt(a) == 0){
va_start(a, flags); ioflush(f.io);
i = vptprpc(code, flags, a); if(f.c)
va_end(a); threadcreate(ioflusher, &f, 4*1024);
semrelease(&ptpsem, 1); va_start(va, flags);
} i = vptprpc(f.io, code, flags, va);
if(i < 0 && debug) va_end(va);
fprint(2, "ptprpc: req=%p %r\n", r); } else
if(r != nil){ werrstr("%s", m);
if(r){
srvacquire(r->srv); srvacquire(r->srv);
r->aux = (void*)-1; r->aux = nil;
} }
if(f.io){
if(f.c)
sendp(f.c, nil);
sendp(iochan, f.io);
} else if(f.c)
chanfree(f.c);
return i; return i;
} }
@ -433,31 +475,42 @@ copydir(Dir *d, Dir *s)
} }
static Node* static Node*
getnode(uvlong path, Req *r) cachednode(uvlong path, Node ***pf)
{ {
int i, j;
Node *x; Node *x;
uchar *p; int i;
int np;
char *s;
j = -1; if(pf)
*pf = nil;
for(i=0; i<nnodes; i++){ for(i=0; i<nnodes; i++){
if((x = nodes[i]) == nil){ if((x = nodes[i]) == nil){
j = i; if(pf)
*pf = &nodes[i];
continue; continue;
} }
if(x->d.qid.path == path) if(x->d.qid.path == path)
return x; return x;
} }
return nil;
}
static Node*
getnode(Req *r, uvlong path)
{
Node *x, *y, **f;
uchar *p;
int np;
char *s;
if(x = cachednode(path, &f))
return x;
y = nil;
x = emalloc9p(sizeof(*x)); x = emalloc9p(sizeof(*x));
memset(x, 0, sizeof(*x)); memset(x, 0, sizeof(*x));
x->d.qid.path = path; x->d.qid.path = path;
x->d.uid = estrdup9p(uname); x->d.uid = estrdup9p("ptp");
x->d.gid = estrdup9p(uname); x->d.gid = estrdup9p("usb");
x->d.atime = x->d.mtime = time0; x->d.atime = x->d.mtime = time0;
p = nil; p = nil;
@ -467,7 +520,7 @@ getnode(uvlong path, Req *r)
x->d.qid.type = QTDIR; x->d.qid.type = QTDIR;
x->d.mode = DMDIR|0777; x->d.mode = DMDIR|0777;
x->d.name = estrdup9p("/"); x->d.name = estrdup9p("/");
break; goto Addnode;
case Qstore: case Qstore:
x->store = NUM(path); x->store = NUM(path);
@ -476,36 +529,29 @@ getnode(uvlong path, Req *r)
x->d.mode = DMDIR|0777; x->d.mode = DMDIR|0777;
x->d.name = emalloc9p(10); x->d.name = emalloc9p(10);
sprint(x->d.name, "%x", x->store); sprint(x->d.name, "%x", x->store);
break; goto Addnode;
case Qobj: case Qobj:
case Qthumb: case Qthumb:
if(ptprpc(r, GetObjectInfo, 1|DataRecv, NUM(path), &p, &np) < 0) if(ptprpc(r, GetObjectInfo, 1|DataRecv, NUM(path), &p, &np) < 0)
goto err; break;
if(debug > 1) if(debug)
hexdump("objectinfo", p, np); hexdump("objectinfo", p, np);
if(np < 52){ if(np < 52){
werrstr("bad objectinfo"); werrstr("bad objectinfo");
goto err; break;
} }
j = -1; /*
for(i=0; i<nnodes; i++){ * another proc migh'v come in and done it for us,
if(nodes[i] == nil){ * so check the cache again.
j = i; */
continue; if(y = cachednode(path, &f))
} break;
if(nodes[i]->d.qid.path == path){
/* never mind */
cleardir(&x->d);
free(x);
return nodes[i];
}
}
if((x->d.name = ptpstring2(p+52, p+np)) == nil){ if((x->d.name = ptpstring2(p+52, p+np)) == nil){
werrstr("bad objectinfo"); werrstr("bad objectinfo");
goto err; break;
} }
x->handle = NUM(path); x->handle = NUM(path);
x->store = GET4(p); x->store = GET4(p);
@ -554,22 +600,19 @@ getnode(uvlong path, Req *r)
free(s); free(s);
} }
free(p); free(p);
break; Addnode:
} if(f == nil){
if(j < 0){
if(nnodes % 64 == 0) if(nnodes % 64 == 0)
nodes = erealloc9p(nodes, sizeof(nodes[0]) * (nnodes + 64)); nodes = erealloc9p(nodes, sizeof(nodes[0]) * (nnodes + 64));
j = nnodes++; f = &nodes[nnodes++];
}
return *f = x;
} }
return nodes[j] = x;
err:
cleardir(&x->d); cleardir(&x->d);
free(x); free(x);
free(p); free(p);
return y;
return nil;
} }
static void static void
@ -590,14 +633,15 @@ freenode(Node *nod)
} }
static int static int
readchilds(Node *nod, Req *r) readchilds(Req *r, Node *nod)
{ {
int i; int e, i;
int *a; int *a;
uchar *p; uchar *p;
int np; int np;
Node *x, **xx; Node *x, **xx;
e = 0;
switch(TYPE(nod->d.qid.path)){ switch(TYPE(nod->d.qid.path)){
case Qroot: case Qroot:
if(ptprpc(r, GetStorageIds, 0|DataRecv, &p, &np) < 0) if(ptprpc(r, GetStorageIds, 0|DataRecv, &p, &np) < 0)
@ -605,14 +649,17 @@ readchilds(Node *nod, Req *r)
a = ptparray4(p, p+np); a = ptparray4(p, p+np);
free(p); free(p);
xx = &nod->child; xx = &nod->child;
*xx = nil;
for(i=0; a && i<a[0]; i++){ for(i=0; a && i<a[0]; i++){
if(x = getnode(PATH(Qstore, a[i+1]), r)){ if((x = getnode(r, PATH(Qstore, a[i+1]))) == nil){
e = -1;
break;
}
x->parent = nod; x->parent = nod;
*xx = x; *xx = x;
xx = &x->next; xx = &x->next;
}
}
*xx = nil; *xx = nil;
}
free(a); free(a);
break; break;
@ -623,28 +670,34 @@ readchilds(Node *nod, Req *r)
a = ptparray4(p, p+np); a = ptparray4(p, p+np);
free(p); free(p);
xx = &nod->child; xx = &nod->child;
*xx = nil;
for(i=0; a && i<a[0]; i++){ for(i=0; a && i<a[0]; i++){
if(x = getnode(PATH(Qobj, a[i+1]), r)){ if((x = getnode(r, PATH(Qobj, a[i+1]))) == nil){
e = -1;
break;
}
x->parent = nod; x->parent = nod;
*xx = x; *xx = x;
xx = &x->next; xx = &x->next;
*xx = nil;
/* skip thumb when not image format */ /* skip thumb when not image format */
if((x->format & 0xFF00) != 0x3800) if((x->format & 0xFF00) != 0x3800)
continue; continue;
if((x = getnode(r, PATH(Qthumb, a[i+1]))) == nil){
e = -1;
break;
} }
if(x = getnode(PATH(Qthumb, a[i+1]), r)){
x->parent = nod; x->parent = nod;
*xx = x; *xx = x;
xx = &x->next; xx = &x->next;
}
}
*xx = nil; *xx = nil;
}
free(a); free(a);
break; break;
} }
return 0; return e;
} }
static void static void
@ -654,8 +707,6 @@ fsattach(Req *r)
respond(r, "invalid attach specifier"); respond(r, "invalid attach specifier");
return; return;
} }
if(uname == nil)
uname = estrdup9p(r->ifcall.uname);
r->fid->qid.path = PATH(Qroot, 0); r->fid->qid.path = PATH(Qroot, 0);
r->fid->qid.type = QTDIR; r->fid->qid.type = QTDIR;
r->fid->qid.vers = 0; r->fid->qid.vers = 0;
@ -668,7 +719,7 @@ fsstat(Req *r)
{ {
Node *nod; Node *nod;
if((nod = getnode(r->fid->qid.path, r)) == nil){ if((nod = getnode(r, r->fid->qid.path)) == nil){
responderror(r); responderror(r);
return; return;
} }
@ -702,17 +753,13 @@ fswalk1(Req *r, char *name, Qid *qid)
path = fid->qid.path; path = fid->qid.path;
if(!(fid->qid.type&QTDIR)) if(!(fid->qid.type&QTDIR))
return "walk in non-directory"; return "walk in non-directory";
if(nod = getnode(r, path)){
if((nod = getnode(path, r)) == nil)
goto err;
if(strcmp(name, "..") == 0){ if(strcmp(name, "..") == 0){
if(nod = nod->parent) if(nod = nod->parent)
*qid = nod->d.qid; *qid = nod->d.qid;
return nil; return nil;
} }
if(readchilds(nod, r) < 0) if(readchilds(r, nod) == 0){
goto err;
for(nod=nod->child; nod; nod=nod->next){ for(nod=nod->child; nod; nod=nod->next){
if(strcmp(nod->d.name, name) == 0){ if(strcmp(nod->d.name, name) == 0){
*qid = nod->d.qid; *qid = nod->d.qid;
@ -720,8 +767,8 @@ fswalk1(Req *r, char *name, Qid *qid)
} }
} }
return "directory entry not found"; return "directory entry not found";
}
err: }
rerrstr(buf, sizeof(buf)); rerrstr(buf, sizeof(buf));
return buf; return buf;
} }
@ -764,32 +811,24 @@ fsread(Req *r)
np = 0; np = 0;
p = nil; p = nil;
path = r->fid->qid.path; path = r->fid->qid.path;
if((nod = getnode(path, r)) == nil) if(nod = getnode(r, path)){
goto err; switch(TYPE(path)){
case Qroot:
case Qstore:
case Qobj:
if(nod->d.qid.type & QTDIR){ if(nod->d.qid.type & QTDIR){
if(readchilds(nod, r) < 0) if(readchilds(r, nod) < 0)
goto err; break;
dirread9p(r, nodegen, nod); dirread9p(r, nodegen, nod);
respond(r, nil); respond(r, nil);
return; return;
} }
/* no break */
switch(TYPE(path)){
default:
werrstr("bug in fsread path=%llux", path);
break;
case Qobj:
case Qthumb: case Qthumb:
if(nod->data == nil){ if(nod->data == nil){
if(TYPE(path)==Qthumb){ if(ptprpc(r, TYPE(path)==Qthumb ? GetThumb : GetObject,
if(ptprpc(r, GetThumb, 1|DataRecv, nod->handle, &p, &np) < 0) 1|DataRecv, nod->handle, &p, &np) < 0)
goto err; break;
} else {
if(ptprpc(r, GetObject, 1|DataRecv, nod->handle, &p, &np) < 0)
goto err;
}
nod->data = p; nod->data = p;
nod->ndata = np; nod->ndata = np;
} }
@ -797,7 +836,7 @@ fsread(Req *r)
respond(r, nil); respond(r, nil);
return; return;
} }
err: }
free(p); free(p);
responderror(r); responderror(r);
} }
@ -809,22 +848,22 @@ fsremove(Req *r)
uvlong path; uvlong path;
path = r->fid->qid.path; path = r->fid->qid.path;
if((nod = getnode(path, r)) == nil) if(nod = getnode(r, path)){
goto err;
switch(TYPE(path)){ switch(TYPE(path)){
default: default:
werrstr("bug in fsremove path=%llux", path); werrstr(Eperm);
break; break;
case Qobj: case Qobj:
if(ptprpc(r, DeleteObject, 2, nod->handle, 0) < 0) if(ptprpc(r, DeleteObject, 2, nod->handle, 0) < 0)
goto err; break;
/* no break */
case Qthumb: case Qthumb:
if(nod = cachednode(path, nil))
freenode(nod); freenode(nod);
respond(r, nil); respond(r, nil);
return; return;
} }
err: }
responderror(r); responderror(r);
} }
@ -832,7 +871,7 @@ static void
fsopen(Req *r) fsopen(Req *r)
{ {
if(r->ifcall.mode != OREAD){ if(r->ifcall.mode != OREAD){
respond(r, "permission denied"); respond(r, Eperm);
return; return;
} }
respond(r, nil); respond(r, nil);
@ -841,17 +880,10 @@ fsopen(Req *r)
static void static void
fsflush(Req *r) fsflush(Req *r)
{ {
Req *o; Channel *c;
if(o = r->oldreq){ if(c = r->oldreq->aux)
if(debug) sendp(c, Einterrupt);
fprint(2, "fsflush: req=%p\n", o);
int pid = (int)o->aux;
if(pid != -1 && pid != 0){
o->aux = (void*)-1;
postnote(PNPROC, pid, "interrupt");
}
}
respond(r, nil); respond(r, nil);
} }
@ -865,7 +897,7 @@ fsdestroyfid(Fid *fid)
switch(TYPE(path)){ switch(TYPE(path)){
case Qobj: case Qobj:
case Qthumb: case Qthumb:
if(nod = getnode(path, nil)){ if(nod = cachednode(path, nil)){
free(nod->data); free(nod->data);
nod->data = nil; nod->data = nil;
nod->ndata = 0; nod->ndata = 0;
@ -878,6 +910,7 @@ static void
fsend(Srv *) fsend(Srv *)
{ {
ptprpc(nil, CloseSession, 0); ptprpc(nil, CloseSession, 0);
closeioproc(recvp(iochan));
} }
static int static int
@ -906,39 +939,31 @@ findendpoints(Dev *d, int *epin, int *epout)
return -1; return -1;
} }
static int
inote(void *, char *msg)
{
if(strstr(msg, "interrupt"))
return 1;
return 0;
}
Srv fs = Srv fs =
{ {
.attach= fsattach, .attach = fsattach,
.destroyfid= fsdestroyfid, .destroyfid = fsdestroyfid,
.walk= fswalk, .walk = fswalk,
.open= fsopen, .open = fsopen,
.read= fsread, .read = fsread,
.remove= fsremove, .remove = fsremove,
.stat= fsstat, .stat = fsstat,
.flush= fsflush, .flush = fsflush,
.end= fsend, .end = fsend,
}; };
static void static void
usage(void) usage(void)
{ {
fprint(2, "usage: %s [-dD] devid\n", argv0); fprint(2, "usage: %s [-dD] devid\n", argv0);
exits("usage"); threadexits("usage");
} }
void void
main(int argc, char **argv) threadmain(int argc, char **argv)
{ {
int epin, epout;
char name[64], desc[64]; char name[64], desc[64];
int epin, epout;
Dev *d; Dev *d;
ARGBEGIN { ARGBEGIN {
@ -972,16 +997,18 @@ main(int argc, char **argv)
if(usbep[In]->dfd < 0 || usbep[Out]->dfd < 0) if(usbep[In]->dfd < 0 || usbep[Out]->dfd < 0)
sysfatal("open endpoints: %r"); sysfatal("open endpoints: %r");
iochan = chancreate(sizeof(Ioproc*), 1);
sendp(iochan, ioproc());
sessionId = getpid(); sessionId = getpid();
if(ptprpc(nil, OpenSession, 1, sessionId) < 0) if(ptprpc(nil, OpenSession, 1, sessionId) < 0)
return; sysfatal("open session: %r");
atnotify(inote, 1);
time0 = time(0); time0 = time(0);
snprint(name, sizeof name, "sdU%d.0", d->id); snprint(name, sizeof name, "sdU%d.0", d->id);
snprint(desc, sizeof desc, "%d.ptp", d->id); snprint(desc, sizeof desc, "%d.ptp", d->id);
postsharesrv(&fs, nil, name, desc); threadpostsharesrv(&fs, nil, name, desc);
exits(0); threadexits(0);
} }