summaryrefslogtreecommitdiffstats
path: root/sys/net/route.c
diff options
context:
space:
mode:
authormux <mux@FreeBSD.org>2007-12-27 10:00:57 +0000
committermux <mux@FreeBSD.org>2007-12-27 10:00:57 +0000
commit58da8ec52155f6928ab5a5a368cac15c7e4fa2fa (patch)
treeb678287fce1851087cab347782f8b195d44ad380 /sys/net/route.c
parent811e8e3c3f6e7f56cbde519c14503f8bfa55a2cc (diff)
downloadFreeBSD-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
Diffstat (limited to 'sys/net/route.c')
-rw-r--r--sys/net/route.c11
1 files changed, 10 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
OpenPOWER on IntegriCloud