devip: remove unused c->car qlock, avoid potential deadlock in ipifcregisterproxy()

remove references to the unused Conv.car qlock.

ipifcregisterproxy() is called with the proxy
ifc wlock'd, which means we cannot acquire the
rwlock of the interfaces that will proxy for us
because it is allowed to rlock() multiple ifc's
in any order. to get arround this, we use canrlock()
and skip the interface when we cannot acquire the
lock.

the ifc should get wlock'd only when we are about
to modify the ifc or its lifc chain. that is when
adding or removing addresses. wlock is not required
when we addresses to the selfcache, which has its
own qlock.
This commit is contained in:
cinap_lenrek 2019-05-11 14:01:26 +02:00
parent a25819c43a
commit 3a0d5f41a8
3 changed files with 39 additions and 64 deletions

View file

@ -1037,7 +1037,7 @@ bindctlmsg(Proto *x, Conv *c, Cmdbuf *cb)
if(x->bind == nil) if(x->bind == nil)
p = Fsstdbind(c, cb->f, cb->nf); p = Fsstdbind(c, cb->f, cb->nf);
else else
p = x->bind(c, cb->f, cb->nf); p = (*x->bind)(c, cb->f, cb->nf);
if(p != nil) if(p != nil)
error(p); error(p);
} }
@ -1148,7 +1148,7 @@ ipwrite(Chan* ch, void *v, long n, vlong off)
error(Ebadip); error(Ebadip);
ipifcremmulti(c, c->raddr, ia); ipifcremmulti(c, c->raddr, ia);
} else if(x->ctl != nil) { } else if(x->ctl != nil) {
p = x->ctl(c, cb->f, cb->nf); p = (*x->ctl)(c, cb->f, cb->nf);
if(p != nil) if(p != nil)
error(p); error(p);
} else } else

View file

@ -210,7 +210,6 @@ struct Conv
Queue* sq; /* snooping queue */ Queue* sq; /* snooping queue */
Ref snoopers; /* number of processes with snoop open */ Ref snoopers; /* number of processes with snoop open */
QLock car;
Rendez cr; Rendez cr;
char cerr[ERRMAX]; char cerr[ERRMAX];

View file

@ -61,7 +61,7 @@ static char tifc[] = "ifc ";
static void addselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a, int type); static void addselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a, int type);
static void remselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a); static void remselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a);
static void ipifcregisteraddr(Fs*, Ipifc*, uchar *, uchar *); static void ipifcregisteraddr(Fs*, Ipifc*, Iplifc*, uchar*);
static void ipifcregisterproxy(Fs*, Ipifc*, uchar*, int); static void ipifcregisterproxy(Fs*, Ipifc*, uchar*, int);
static char* ipifcremlifc(Ipifc*, Iplifc**); static char* ipifcremlifc(Ipifc*, Iplifc**);
@ -194,29 +194,28 @@ ipifcbind(Conv *c, char **argv, int argc)
/* /*
* detach a device from an interface, close the interface * detach a device from an interface, close the interface
* called with ifc->conv closed
*/ */
static char* static char*
ipifcunbind(Ipifc *ifc) ipifcunbind(Ipifc *ifc)
{ {
char *err;
wlock(ifc); wlock(ifc);
if(waserror()){ if(ifc->m == nil){
wunlock(ifc); wunlock(ifc);
nexterror(); return "interface not bound";
} }
/* disassociate logical interfaces (before zeroing ifc->arg) */ /* disassociate logical interfaces (before zeroing ifc->arg) */
while(ifc->lifc != nil){ while(ifc->lifc != nil)
err = ipifcremlifc(ifc, &ifc->lifc); ipifcremlifc(ifc, &ifc->lifc);
if(err != nil)
error(err);
}
/* disassociate device */ /* disassociate device */
if(ifc->m != nil && ifc->m->unbind != nil) if(ifc->m->unbind != nil){
(*ifc->m->unbind)(ifc); if(!waserror()){
(*ifc->m->unbind)(ifc);
poperror();
}
}
memset(ifc->dev, 0, sizeof(ifc->dev)); memset(ifc->dev, 0, sizeof(ifc->dev));
ifc->arg = nil; ifc->arg = nil;
@ -230,12 +229,11 @@ ipifcunbind(Ipifc *ifc)
/* dissociate routes */ /* dissociate routes */
ifc->ifcid++; ifc->ifcid++;
if(ifc->m != nil && ifc->m->unbindonclose == 0) if(ifc->m->unbindonclose == 0)
ifc->conv->inuse--; ifc->conv->inuse--;
ifc->m = nil; ifc->m = nil;
wunlock(ifc); wunlock(ifc);
poperror();
return nil; return nil;
} }
@ -400,15 +398,16 @@ ipifccreate(Conv *c)
/* /*
* called after last close of ipifc data or ctl * called after last close of ipifc data or ctl
* called with c locked, we must unlock
*/ */
static void static void
ipifcclose(Conv *c) ipifcclose(Conv *c)
{ {
Ipifc *ifc; Ipifc *ifc;
Medium *m;
ifc = (Ipifc*)c->ptcl; ifc = (Ipifc*)c->ptcl;
if(ifc->m != nil && ifc->m->unbindonclose) m = ifc->m;
if(m != nil && m->unbindonclose)
ipifcunbind(ifc); ipifcunbind(ifc);
} }
@ -489,7 +488,7 @@ ipifcadd(Ipifc *ifc, char **argv, int argc, int tentative, Iplifc *lifcp)
wlock(ifc); wlock(ifc);
if(ifc->m == nil){ if(ifc->m == nil){
wunlock(ifc); wunlock(ifc);
return "ipifc not yet bound to device"; return "interface not yet bound to device";
} }
f = ifc->conv->p->f; f = ifc->conv->p->f;
if(waserror()){ if(waserror()){
@ -615,17 +614,16 @@ ipifcadd(Ipifc *ifc, char **argv, int argc, int tentative, Iplifc *lifcp)
} }
done: done:
ipifcregisteraddr(f, ifc, lifc, ip);
wunlock(ifc); wunlock(ifc);
poperror(); poperror();
ipifcregisteraddr(f, ifc, ip, ip);
return nil; return nil;
} }
/* /*
* remove a logical interface from an ifc * remove a logical interface from an ifc
* always called with ifc wlock'd * called with ifc wlock'd
*/ */
static char* static char*
ipifcremlifc(Ipifc *ifc, Iplifc **l) ipifcremlifc(Ipifc *ifc, Iplifc **l)
@ -678,7 +676,6 @@ done:
/* /*
* remove an address from an interface. * remove an address from an interface.
* called with c->car locked
*/ */
char* char*
ipifcrem(Ipifc *ifc, char **argv, int argc) ipifcrem(Ipifc *ifc, char **argv, int argc)
@ -727,18 +724,9 @@ ipifcconnect(Conv* c, char **argv, int argc)
Ipifc *ifc; Ipifc *ifc;
ifc = (Ipifc*)c->ptcl; ifc = (Ipifc*)c->ptcl;
if(ifc->m == nil)
return "ipifc not yet bound to device";
wlock(ifc); wlock(ifc);
while(ifc->lifc != nil){ while(ifc->lifc != nil)
err = ipifcremlifc(ifc, &ifc->lifc); ipifcremlifc(ifc, &ifc->lifc);
if(err != nil){
wunlock(ifc);
return err;
}
}
wunlock(ifc); wunlock(ifc);
err = ipifcadd(ifc, argv, argc, 0, nil); err = ipifcadd(ifc, argv, argc, 0, nil);
@ -808,7 +796,6 @@ ipifcra6(Ipifc *ifc, char **argv, int argc)
/* /*
* non-standard control messages. * non-standard control messages.
* called with c->car locked.
*/ */
static char* static char*
ipifcctl(Conv* c, char **argv, int argc) ipifcctl(Conv* c, char **argv, int argc)
@ -892,7 +879,6 @@ ipifcinit(Fs *f)
/* /*
* add to self routing cache * add to self routing cache
* called with c->car locked
*/ */
static void static void
addselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a, int type) addselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a, int type)
@ -1011,7 +997,6 @@ ipselffree(Ipself *p)
/* /*
* Decrement reference for this address on this link. * Decrement reference for this address on this link.
* Unlink from selftab if this is the last ref. * Unlink from selftab if this is the last ref.
* called with c->car locked
*/ */
static void static void
remselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a) remselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a)
@ -1468,7 +1453,7 @@ ipismulticast(uchar *ip)
} }
/* /*
* add a multicast address to an interface, called with c->car locked * add a multicast address to an interface.
*/ */
void void
ipifcaddmulti(Conv *c, uchar *ma, uchar *ia) ipifcaddmulti(Conv *c, uchar *ma, uchar *ia)
@ -1487,14 +1472,14 @@ ipifcaddmulti(Conv *c, uchar *ma, uchar *ia)
f = c->p->f; f = c->p->f;
if((ifc = findipifc(f, ia, ma, Rmulti)) != nil){ if((ifc = findipifc(f, ia, ma, Rmulti)) != nil){
wlock(ifc); rlock(ifc);
if(waserror()){ if(waserror()){
wunlock(ifc); runlock(ifc);
nexterror(); nexterror();
} }
if((lifc = iplocalonifc(ifc, ia)) != nil) if((lifc = iplocalonifc(ifc, ia)) != nil)
addselfcache(f, ifc, lifc, ma, Rmulti); addselfcache(f, ifc, lifc, ma, Rmulti);
wunlock(ifc); runlock(ifc);
poperror(); poperror();
} }
@ -1507,7 +1492,7 @@ ipifcaddmulti(Conv *c, uchar *ma, uchar *ia)
/* /*
* remove a multicast address from an interface, called with c->car locked * remove a multicast address from an interface.
*/ */
void void
ipifcremmulti(Conv *c, uchar *ma, uchar *ia) ipifcremmulti(Conv *c, uchar *ma, uchar *ia)
@ -1530,33 +1515,27 @@ ipifcremmulti(Conv *c, uchar *ma, uchar *ia)
f = c->p->f; f = c->p->f;
if((ifc = findipifc(f, ia, ma, Rmulti)) != nil){ if((ifc = findipifc(f, ia, ma, Rmulti)) != nil){
wlock(ifc); rlock(ifc);
if(!waserror()){ if(!waserror()){
if((lifc = iplocalonifc(ifc, ia)) != nil) if((lifc = iplocalonifc(ifc, ia)) != nil)
remselfcache(f, ifc, lifc, ma); remselfcache(f, ifc, lifc, ma);
poperror(); poperror();
} }
wunlock(ifc); runlock(ifc);
} }
free(multi); free(multi);
} }
/* register the address on this network for address resolution */ /* register the address on this network for address resolution */
static void static void
ipifcregisteraddr(Fs *f, Ipifc *ifc, uchar *ia, uchar *ip) ipifcregisteraddr(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *ip)
{ {
Iplifc *lifc;
rlock(ifc);
if(waserror()){ if(waserror()){
runlock(ifc); print("ipifcregisteraddr %s %I %I: %s\n", ifc->dev, lifc->local, ip, up->errstr);
print("ipifcregisteraddr %s %I %I: %s\n", ifc->dev, ia, ip, up->errstr);
return; return;
} }
lifc = iplocalonifc(ifc, ia); if(ifc->m != nil && ifc->m->areg != nil)
if(lifc != nil && ifc->m != nil && ifc->m->areg != nil)
(*ifc->m->areg)(f, ifc, lifc, ip); (*ifc->m->areg)(f, ifc, lifc, ip);
runlock(ifc);
poperror(); poperror();
} }
@ -1571,15 +1550,14 @@ ipifcregisterproxy(Fs *f, Ipifc *ifc, uchar *ip, int add)
/* register the address on any interface that will proxy for the ip */ /* register the address on any interface that will proxy for the ip */
for(cp = f->ipifc->conv; *cp != nil; cp++){ for(cp = f->ipifc->conv; *cp != nil; cp++){
nifc = (Ipifc*)(*cp)->ptcl; nifc = (Ipifc*)(*cp)->ptcl;
if(nifc == ifc) if(nifc == ifc || !canrlock(nifc))
continue; continue;
wlock(nifc);
if(nifc->m == nil if(nifc->m == nil
|| (lifc = ipremoteonifc(nifc, ip)) == nil || (lifc = ipremoteonifc(nifc, ip)) == nil
|| (lifc->type & Rptpt) != 0 || (lifc->type & Rptpt) != 0
|| waserror()){ || waserror()){
wunlock(nifc); runlock(nifc);
continue; continue;
} }
if((lifc->type & Rv4) == 0){ if((lifc->type & Rv4) == 0){
@ -1590,12 +1568,10 @@ ipifcregisterproxy(Fs *f, Ipifc *ifc, uchar *ip, int add)
else else
remselfcache(f, nifc, lifc, a); remselfcache(f, nifc, lifc, a);
} }
ipmove(a, lifc->local);
wunlock(nifc);
poperror();
if(add) if(add)
ipifcregisteraddr(f, nifc, a, ip); ipifcregisteraddr(f, nifc, lifc, ip);
runlock(nifc);
poperror();
} }
} }