Add a workaround for a deadlock between the rt_setgate() and rt_check()

functions.  It is easily triggered by running routed, and, I expect, by
running any other daemon that uses routing sockets.

Reviewed by:	net@
MFC after:	1 week
This commit is contained in:
Maxime Henrion 2007-12-27 10:00:57 +00:00
parent c07f36f742
commit f321ff1561
2 changed files with 11 additions and 1 deletions

View File

@ -1025,6 +1025,7 @@ rt_setgate(struct rtentry *rt, struct sockaddr *dst, struct sockaddr *gate)
struct radix_node_head *rnh = rt_tables[dst->sa_family];
int dlen = SA_SIZE(dst), glen = SA_SIZE(gate);
again:
RT_LOCK_ASSERT(rt);
/*
@ -1057,7 +1058,15 @@ rt_setgate(struct rtentry *rt, struct sockaddr *dst, struct sockaddr *gate)
RT_REMREF(rt);
return (EADDRINUSE); /* failure */
}
RT_LOCK(rt);
/*
* Try to reacquire the lock on rt, and if it fails,
* clean state and restart from scratch.
*/
if (!RT_TRYLOCK(rt)) {
RTFREE_LOCKED(gwrt);
RT_LOCK(rt);
goto again;
}
/*
* If there is already a gwroute, then drop it. If we
* are asked to replace route with itself, then do

View File

@ -289,6 +289,7 @@ struct rt_addrinfo {
#define RT_LOCK_INIT(_rt) \
mtx_init(&(_rt)->rt_mtx, "rtentry", NULL, MTX_DEF | MTX_DUPOK)
#define RT_LOCK(_rt) mtx_lock(&(_rt)->rt_mtx)
#define RT_TRYLOCK(_rt) mtx_trylock(&(_rt)->rt_mtx)
#define RT_UNLOCK(_rt) mtx_unlock(&(_rt)->rt_mtx)
#define RT_LOCK_DESTROY(_rt) mtx_destroy(&(_rt)->rt_mtx)
#define RT_LOCK_ASSERT(_rt) mtx_assert(&(_rt)->rt_mtx, MA_OWNED)