Add a bandaid for a long-standing race condition during route entry

un-expiring.

The previous version of code have no locking when testing rt_refcnt.
The result of the lack of locking may result in a condition where
a routing entry have a reference count but at the same time have
RTPRF_OURS bit set and an expiration timer.  These would eventually
lead to a panic:

	panic: rtqkill route really not free

When the system have ICMP redirects accepted from local gateway
in a moderate frequency, for instance.

Commit this workaround for now until we have some better solution.

PR:		kern/149804
Reviewed by:	bz
Tested by:	Zhao Xin, Pete French
MFC after:	2 weeks
This commit is contained in:
Xin LI 2010-09-27 19:26:56 +00:00
parent 0d2d8fab68
commit 64e0f48e7c
2 changed files with 6 additions and 3 deletions

View File

@ -121,12 +121,13 @@ in_matroute(void *v_arg, struct radix_node_head *head)
struct radix_node *rn = rn_match(v_arg, head);
struct rtentry *rt = (struct rtentry *)rn;
/*XXX locking? */
if (rt && rt->rt_refcnt == 0) { /* this is first reference */
if (rt) {
RT_LOCK(rt);
if (rt->rt_flags & RTPRF_OURS) {
rt->rt_flags &= ~RTPRF_OURS;
rt->rt_rmx.rmx_expire = 0;
}
RT_UNLOCK(rt);
}
return rn;
}

View File

@ -193,11 +193,13 @@ in6_matroute(void *v_arg, struct radix_node_head *head)
struct radix_node *rn = rn_match(v_arg, head);
struct rtentry *rt = (struct rtentry *)rn;
if (rt && rt->rt_refcnt == 0) { /* this is first reference */
if (rt) {
RT_LOCK(rt);
if (rt->rt_flags & RTPRF_OURS) {
rt->rt_flags &= ~RTPRF_OURS;
rt->rt_rmx.rmx_expire = 0;
}
RT_UNLOCK(rt);
}
return rn;
}