devip: avoid media bind/unbind kproc reader startup race, simplify etherbind
mark reader process pointers with (void*)-1 to mean not started yet. this avoids the race condition when media unbind happens before the kproc has set its Proc* pointer. then we would not post the note and the reader would continue running after unbind. etherbind can be simplified by reading the #lX/addr file to get the mac address, avoiding the temporary buffer.
This commit is contained in:
parent
ed3a576e8b
commit
a25819c43a
3 changed files with 65 additions and 64 deletions
|
@ -122,32 +122,49 @@ static char *nbmsg = "nonblocking";
|
|||
static void
|
||||
etherbind(Ipifc *ifc, int argc, char **argv)
|
||||
{
|
||||
Chan *mchan4, *cchan4, *achan, *mchan6, *cchan6, *schan;
|
||||
char addr[Maxpath]; //char addr[2*KNAMELEN];
|
||||
char dir[Maxpath]; //char dir[2*KNAMELEN];
|
||||
char *buf;
|
||||
int n;
|
||||
char *ptr;
|
||||
char addr[Maxpath], dir[Maxpath];
|
||||
Etherrock *er;
|
||||
Chan *c;
|
||||
int n;
|
||||
|
||||
if(argc < 2)
|
||||
error(Ebadarg);
|
||||
|
||||
mchan4 = cchan4 = achan = mchan6 = cchan6 = nil;
|
||||
buf = nil;
|
||||
/*
|
||||
* get mac address
|
||||
*/
|
||||
snprint(addr, sizeof(addr), "%s/addr", argv[2]);
|
||||
c = namec(addr, Aopen, OREAD, 0);
|
||||
if(waserror()){
|
||||
if(mchan4 != nil)
|
||||
cclose(mchan4);
|
||||
if(cchan4 != nil)
|
||||
cclose(cchan4);
|
||||
if(achan != nil)
|
||||
cclose(achan);
|
||||
if(mchan6 != nil)
|
||||
cclose(mchan6);
|
||||
if(cchan6 != nil)
|
||||
cclose(cchan6);
|
||||
if(buf != nil)
|
||||
free(buf);
|
||||
cclose(c);
|
||||
nexterror();
|
||||
}
|
||||
n = devtab[c->type]->read(c, addr, sizeof(addr)-1, 0);
|
||||
if(n < 0)
|
||||
error(Eio);
|
||||
addr[n] = 0;
|
||||
if(parsemac(ifc->mac, addr, sizeof(ifc->mac)) != 6)
|
||||
error("could not find mac address");
|
||||
cclose(c);
|
||||
poperror();
|
||||
|
||||
er = smalloc(sizeof(*er));
|
||||
er->read4p = er->read6p = er->arpp = (void*)-1;
|
||||
er->mchan4 = er->cchan4 = er->mchan6 = er->cchan6 = er->achan = nil;
|
||||
er->f = ifc->conv->p->f;
|
||||
|
||||
if(waserror()){
|
||||
if(er->mchan4 != nil)
|
||||
cclose(er->mchan4);
|
||||
if(er->cchan4 != nil)
|
||||
cclose(er->cchan4);
|
||||
if(er->mchan6 != nil)
|
||||
cclose(er->mchan6);
|
||||
if(er->cchan6 != nil)
|
||||
cclose(er->cchan6);
|
||||
if(er->achan != nil)
|
||||
cclose(er->achan);
|
||||
free(er);
|
||||
nexterror();
|
||||
}
|
||||
|
||||
|
@ -158,39 +175,12 @@ etherbind(Ipifc *ifc, int argc, char **argv)
|
|||
* this device.
|
||||
*/
|
||||
snprint(addr, sizeof(addr), "%s!0x800", argv[2]); /* ETIP4 */
|
||||
mchan4 = chandial(addr, nil, dir, &cchan4);
|
||||
er->mchan4 = chandial(addr, nil, dir, &er->cchan4);
|
||||
|
||||
/*
|
||||
* make it non-blocking
|
||||
*/
|
||||
devtab[cchan4->type]->write(cchan4, nbmsg, strlen(nbmsg), 0);
|
||||
|
||||
/*
|
||||
* get mac address and speed
|
||||
*/
|
||||
snprint(addr, sizeof(addr), "%s/stats", argv[2]);
|
||||
buf = smalloc(512);
|
||||
schan = namec(addr, Aopen, OREAD, 0);
|
||||
if(waserror()){
|
||||
cclose(schan);
|
||||
nexterror();
|
||||
}
|
||||
n = devtab[schan->type]->read(schan, buf, 511, 0);
|
||||
cclose(schan);
|
||||
poperror();
|
||||
buf[n] = 0;
|
||||
|
||||
ptr = strstr(buf, "addr: ");
|
||||
if(!ptr)
|
||||
error(Eio);
|
||||
ptr += 6;
|
||||
parsemac(ifc->mac, ptr, 6);
|
||||
|
||||
/*
|
||||
* open arp conversation
|
||||
*/
|
||||
snprint(addr, sizeof(addr), "%s!0x806", argv[2]); /* ETARP */
|
||||
achan = chandial(addr, nil, nil, nil);
|
||||
devtab[er->cchan4->type]->write(er->cchan4, nbmsg, strlen(nbmsg), 0);
|
||||
|
||||
/*
|
||||
* open ipv6 conversation
|
||||
|
@ -199,25 +189,22 @@ etherbind(Ipifc *ifc, int argc, char **argv)
|
|||
* this device.
|
||||
*/
|
||||
snprint(addr, sizeof(addr), "%s!0x86DD", argv[2]); /* ETIP6 */
|
||||
mchan6 = chandial(addr, nil, dir, &cchan6);
|
||||
er->mchan6 = chandial(addr, nil, dir, &er->cchan6);
|
||||
|
||||
/*
|
||||
* make it non-blocking
|
||||
*/
|
||||
devtab[cchan6->type]->write(cchan6, nbmsg, strlen(nbmsg), 0);
|
||||
devtab[er->cchan6->type]->write(er->cchan6, nbmsg, strlen(nbmsg), 0);
|
||||
|
||||
er = smalloc(sizeof(*er));
|
||||
er->mchan4 = mchan4;
|
||||
er->cchan4 = cchan4;
|
||||
er->achan = achan;
|
||||
er->mchan6 = mchan6;
|
||||
er->cchan6 = cchan6;
|
||||
er->f = ifc->conv->p->f;
|
||||
ifc->arg = er;
|
||||
|
||||
free(buf);
|
||||
/*
|
||||
* open arp conversation
|
||||
*/
|
||||
snprint(addr, sizeof(addr), "%s!0x806", argv[2]); /* ETARP */
|
||||
er->achan = chandial(addr, nil, nil, nil);
|
||||
poperror();
|
||||
|
||||
ifc->arg = er;
|
||||
|
||||
kproc("etherread4", etherread4, ifc);
|
||||
kproc("etherread6", etherread6, ifc);
|
||||
kproc("recvarpproc", recvarpproc, ifc);
|
||||
|
@ -231,6 +218,10 @@ etherunbind(Ipifc *ifc)
|
|||
{
|
||||
Etherrock *er = ifc->arg;
|
||||
|
||||
/* wait for readers to start */
|
||||
while(er->arpp == (void*)-1 || er->read4p == (void*)-1 || er->read6p == (void*)-1)
|
||||
tsleep(&up->sleep, return0, 0, 300);
|
||||
|
||||
if(er->read4p != nil)
|
||||
postnote(er->read4p, 1, "unbind", 0);
|
||||
if(er->read6p != nil)
|
||||
|
|
|
@ -28,6 +28,7 @@ loopbackbind(Ipifc *ifc, int, char**)
|
|||
LB *lb;
|
||||
|
||||
lb = smalloc(sizeof(*lb));
|
||||
lb->readp = (void*)-1;
|
||||
lb->f = ifc->conv->p->f;
|
||||
lb->q = qopen(1024*1024, Qmsg, nil, nil);
|
||||
ifc->arg = lb;
|
||||
|
@ -41,11 +42,15 @@ loopbackunbind(Ipifc *ifc)
|
|||
{
|
||||
LB *lb = ifc->arg;
|
||||
|
||||
if(lb->readp)
|
||||
/* wat for reader to start */
|
||||
while(lb->readp == (void*)-1)
|
||||
tsleep(&up->sleep, return0, 0, 300);
|
||||
|
||||
if(lb->readp != nil)
|
||||
postnote(lb->readp, 1, "unbind", 0);
|
||||
|
||||
/* wait for reader to die */
|
||||
while(lb->readp != 0)
|
||||
while(lb->readp != nil)
|
||||
tsleep(&up->sleep, return0, 0, 300);
|
||||
|
||||
/* clean up */
|
||||
|
|
|
@ -49,6 +49,7 @@ netdevbind(Ipifc *ifc, int argc, char **argv)
|
|||
mchan = namec(argv[2], Aopen, ORDWR, 0);
|
||||
|
||||
er = smalloc(sizeof(*er));
|
||||
er->readp = (void*)-1;
|
||||
er->mchan = mchan;
|
||||
er->f = ifc->conv->p->f;
|
||||
|
||||
|
@ -65,10 +66,14 @@ netdevunbind(Ipifc *ifc)
|
|||
{
|
||||
Netdevrock *er = ifc->arg;
|
||||
|
||||
/* wait for reader to start */
|
||||
while(er->readp == (void*)-1)
|
||||
tsleep(&up->sleep, return0, 0, 300);
|
||||
|
||||
if(er->readp != nil)
|
||||
postnote(er->readp, 1, "unbind", 0);
|
||||
|
||||
/* wait for readers to die */
|
||||
/* wait for reader to die */
|
||||
while(er->readp != nil)
|
||||
tsleep(&up->sleep, return0, 0, 300);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue