changelog shortlog tags branches files raw gz bz2 help

Mercurial > hg > plan9front / changeset: devip: avoid media bind/unbind kproc reader startup race, simplify etherbind

changeset 7228: 74d3b4699b3a
parent 7227: 9cf755535d58
child 7229: a0387db0dcba
author: cinap_lenrek@felloff.net
date: Sat, 11 May 2019 07:22:34 +0200
files: sys/src/9/ip/ethermedium.c sys/src/9/ip/loopbackmedium.c sys/src/9/ip/netdevmedium.c
description: 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.
     1.1--- a/sys/src/9/ip/ethermedium.c
     1.2+++ b/sys/src/9/ip/ethermedium.c
     1.3@@ -122,32 +122,49 @@ static char *nbmsg = "nonblocking";
     1.4 static void
     1.5 etherbind(Ipifc *ifc, int argc, char **argv)
     1.6 {
     1.7-	Chan *mchan4, *cchan4, *achan, *mchan6, *cchan6, *schan;
     1.8-	char addr[Maxpath];	//char addr[2*KNAMELEN];
     1.9-	char dir[Maxpath];	//char dir[2*KNAMELEN];
    1.10-	char *buf;
    1.11+	char addr[Maxpath], dir[Maxpath];
    1.12+	Etherrock *er;
    1.13+	Chan *c;
    1.14 	int n;
    1.15-	char *ptr;
    1.16-	Etherrock *er;
    1.17 
    1.18 	if(argc < 2)
    1.19 		error(Ebadarg);
    1.20 
    1.21-	mchan4 = cchan4 = achan = mchan6 = cchan6 = nil;
    1.22-	buf = nil;
    1.23+	/*
    1.24+	 *  get mac address
    1.25+	 */
    1.26+	snprint(addr, sizeof(addr), "%s/addr", argv[2]);
    1.27+	c = namec(addr, Aopen, OREAD, 0);
    1.28 	if(waserror()){
    1.29-		if(mchan4 != nil)
    1.30-			cclose(mchan4);
    1.31-		if(cchan4 != nil)
    1.32-			cclose(cchan4);
    1.33-		if(achan != nil)
    1.34-			cclose(achan);
    1.35-		if(mchan6 != nil)
    1.36-			cclose(mchan6);
    1.37-		if(cchan6 != nil)
    1.38-			cclose(cchan6);
    1.39-		if(buf != nil)
    1.40-			free(buf);
    1.41+		cclose(c);
    1.42+		nexterror();
    1.43+	}
    1.44+	n = devtab[c->type]->read(c, addr, sizeof(addr)-1, 0);
    1.45+	if(n < 0)
    1.46+		error(Eio);
    1.47+	addr[n] = 0;
    1.48+	if(parsemac(ifc->mac, addr, sizeof(ifc->mac)) != 6)
    1.49+		error("could not find mac address");
    1.50+	cclose(c);
    1.51+	poperror();
    1.52+
    1.53+	er = smalloc(sizeof(*er));
    1.54+	er->read4p = er->read6p = er->arpp = (void*)-1;
    1.55+	er->mchan4 = er->cchan4 = er->mchan6 = er->cchan6 = er->achan = nil;
    1.56+	er->f = ifc->conv->p->f;
    1.57+
    1.58+	if(waserror()){
    1.59+		if(er->mchan4 != nil)
    1.60+			cclose(er->mchan4);
    1.61+		if(er->cchan4 != nil)
    1.62+			cclose(er->cchan4);
    1.63+		if(er->mchan6 != nil)
    1.64+			cclose(er->mchan6);
    1.65+		if(er->cchan6 != nil)
    1.66+			cclose(er->cchan6);
    1.67+		if(er->achan != nil)
    1.68+			cclose(er->achan);
    1.69+		free(er);
    1.70 		nexterror();
    1.71 	}
    1.72 
    1.73@@ -158,39 +175,12 @@ etherbind(Ipifc *ifc, int argc, char **a
    1.74 	 *  this device.
    1.75 	 */
    1.76 	snprint(addr, sizeof(addr), "%s!0x800", argv[2]);	/* ETIP4 */
    1.77-	mchan4 = chandial(addr, nil, dir, &cchan4);
    1.78+	er->mchan4 = chandial(addr, nil, dir, &er->cchan4);
    1.79 
    1.80 	/*
    1.81 	 *  make it non-blocking
    1.82 	 */
    1.83-	devtab[cchan4->type]->write(cchan4, nbmsg, strlen(nbmsg), 0);
    1.84-
    1.85-	/*
    1.86-	 *  get mac address and speed
    1.87-	 */
    1.88-	snprint(addr, sizeof(addr), "%s/stats", argv[2]);
    1.89-	buf = smalloc(512);
    1.90-	schan = namec(addr, Aopen, OREAD, 0);
    1.91-	if(waserror()){
    1.92-		cclose(schan);
    1.93-		nexterror();
    1.94-	}
    1.95-	n = devtab[schan->type]->read(schan, buf, 511, 0);
    1.96-	cclose(schan);
    1.97-	poperror();
    1.98-	buf[n] = 0;
    1.99-
   1.100-	ptr = strstr(buf, "addr: ");
   1.101-	if(!ptr)
   1.102-		error(Eio);
   1.103-	ptr += 6;
   1.104-	parsemac(ifc->mac, ptr, 6);
   1.105-
   1.106-	/*
   1.107- 	 *  open arp conversation
   1.108-	 */
   1.109-	snprint(addr, sizeof(addr), "%s!0x806", argv[2]);	/* ETARP */
   1.110-	achan = chandial(addr, nil, nil, nil);
   1.111+	devtab[er->cchan4->type]->write(er->cchan4, nbmsg, strlen(nbmsg), 0);
   1.112 
   1.113 	/*
   1.114 	 *  open ipv6 conversation
   1.115@@ -199,25 +189,22 @@ etherbind(Ipifc *ifc, int argc, char **a
   1.116 	 *  this device.
   1.117 	 */
   1.118 	snprint(addr, sizeof(addr), "%s!0x86DD", argv[2]);	/* ETIP6 */
   1.119-	mchan6 = chandial(addr, nil, dir, &cchan6);
   1.120+	er->mchan6 = chandial(addr, nil, dir, &er->cchan6);
   1.121 
   1.122 	/*
   1.123 	 *  make it non-blocking
   1.124 	 */
   1.125-	devtab[cchan6->type]->write(cchan6, nbmsg, strlen(nbmsg), 0);
   1.126+	devtab[er->cchan6->type]->write(er->cchan6, nbmsg, strlen(nbmsg), 0);
   1.127 
   1.128-	er = smalloc(sizeof(*er));
   1.129-	er->mchan4 = mchan4;
   1.130-	er->cchan4 = cchan4;
   1.131-	er->achan = achan;
   1.132-	er->mchan6 = mchan6;
   1.133-	er->cchan6 = cchan6;
   1.134-	er->f = ifc->conv->p->f;
   1.135+	/*
   1.136+ 	 *  open arp conversation
   1.137+	 */
   1.138+	snprint(addr, sizeof(addr), "%s!0x806", argv[2]);	/* ETARP */
   1.139+	er->achan = chandial(addr, nil, nil, nil);
   1.140+	poperror();
   1.141+
   1.142 	ifc->arg = er;
   1.143 
   1.144-	free(buf);
   1.145-	poperror();
   1.146-
   1.147 	kproc("etherread4", etherread4, ifc);
   1.148 	kproc("etherread6", etherread6, ifc);
   1.149 	kproc("recvarpproc", recvarpproc, ifc);
   1.150@@ -231,6 +218,10 @@ etherunbind(Ipifc *ifc)
   1.151 {
   1.152 	Etherrock *er = ifc->arg;
   1.153 
   1.154+	/* wait for readers to start */
   1.155+	while(er->arpp == (void*)-1 || er->read4p == (void*)-1 || er->read6p == (void*)-1)
   1.156+		tsleep(&up->sleep, return0, 0, 300);
   1.157+
   1.158 	if(er->read4p != nil)
   1.159 		postnote(er->read4p, 1, "unbind", 0);
   1.160 	if(er->read6p != nil)
     2.1--- a/sys/src/9/ip/loopbackmedium.c
     2.2+++ b/sys/src/9/ip/loopbackmedium.c
     2.3@@ -28,6 +28,7 @@ loopbackbind(Ipifc *ifc, int, char**)
     2.4 	LB *lb;
     2.5 
     2.6 	lb = smalloc(sizeof(*lb));
     2.7+	lb->readp = (void*)-1;
     2.8 	lb->f = ifc->conv->p->f;
     2.9 	lb->q = qopen(1024*1024, Qmsg, nil, nil);
    2.10 	ifc->arg = lb;
    2.11@@ -41,11 +42,15 @@ loopbackunbind(Ipifc *ifc)
    2.12 {
    2.13 	LB *lb = ifc->arg;
    2.14 
    2.15-	if(lb->readp)
    2.16+	/* wat for reader to start */
    2.17+	while(lb->readp == (void*)-1)
    2.18+		tsleep(&up->sleep, return0, 0, 300);
    2.19+		
    2.20+	if(lb->readp != nil)
    2.21 		postnote(lb->readp, 1, "unbind", 0);
    2.22 
    2.23 	/* wait for reader to die */
    2.24-	while(lb->readp != 0)
    2.25+	while(lb->readp != nil)
    2.26 		tsleep(&up->sleep, return0, 0, 300);
    2.27 
    2.28 	/* clean up */
     3.1--- a/sys/src/9/ip/netdevmedium.c
     3.2+++ b/sys/src/9/ip/netdevmedium.c
     3.3@@ -49,6 +49,7 @@ netdevbind(Ipifc *ifc, int argc, char **
     3.4 	mchan = namec(argv[2], Aopen, ORDWR, 0);
     3.5 
     3.6 	er = smalloc(sizeof(*er));
     3.7+	er->readp = (void*)-1;
     3.8 	er->mchan = mchan;
     3.9 	er->f = ifc->conv->p->f;
    3.10 
    3.11@@ -65,10 +66,14 @@ netdevunbind(Ipifc *ifc)
    3.12 {
    3.13 	Netdevrock *er = ifc->arg;
    3.14 
    3.15+	/* wait for reader to start */
    3.16+	while(er->readp == (void*)-1)
    3.17+		tsleep(&up->sleep, return0, 0, 300);
    3.18+
    3.19 	if(er->readp != nil)
    3.20 		postnote(er->readp, 1, "unbind", 0);
    3.21 
    3.22-	/* wait for readers to die */
    3.23+	/* wait for reader to die */
    3.24 	while(er->readp != nil)
    3.25 		tsleep(&up->sleep, return0, 0, 300);
    3.26