diff options
author | mux <mux@FreeBSD.org> | 2007-12-27 10:00:57 +0000 |
---|---|---|
committer | mux <mux@FreeBSD.org> | 2007-12-27 10:00:57 +0000 |
commit | 58da8ec52155f6928ab5a5a368cac15c7e4fa2fa (patch) | |
tree | b678287fce1851087cab347782f8b195d44ad380 | |
parent | 811e8e3c3f6e7f56cbde519c14503f8bfa55a2cc (diff) | |
download | FreeBSD-src-58da8ec52155f6928ab5a5a368cac15c7e4fa2fa.zip FreeBSD-src-58da8ec52155f6928ab5a5a368cac15c7e4fa2fa.tar.gz |
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
-rw-r--r-- | sys/net/route.c | 11 | ||||
-rw-r--r-- | sys/net/route.h | 1 |
2 files changed, 11 insertions, 1 deletions
diff --git a/sys/net/route.c b/sys/net/route.c index 78cf49d..d407b6d 100644 --- a/sys/net/route.c +++ b/sys/net/route.c @@ -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 diff --git a/sys/net/route.h b/sys/net/route.h index 8c87f6b..01b2957 100644 --- a/sys/net/route.h +++ b/sys/net/route.h @@ -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) |