diff options
author | ae <ae@FreeBSD.org> | 2017-06-20 05:57:28 +0000 |
---|---|---|
committer | ae <ae@FreeBSD.org> | 2017-06-20 05:57:28 +0000 |
commit | 457477d4a00788883d774cda30eda7fa4afa921f (patch) | |
tree | 256ce820a420731becb4bd2268199ae1137030c0 /sys | |
parent | 5069a7986d5c3dc517d4a5b5eaa0c15207bf71c7 (diff) | |
download | FreeBSD-src-457477d4a00788883d774cda30eda7fa4afa921f.zip FreeBSD-src-457477d4a00788883d774cda30eda7fa4afa921f.tar.gz |
MFC r319895:
Resurrect RTF_RNH_LOCKED flag and restore ability to call rtalloc1_fib()
with acquired RIB lock.
This fixes a possible panic due to trying to acquire RIB rlock when it is
already exclusive locked.
PR: 215963, 215122
Sponsored by: Yandex LLC
Approved by: re (delphij)
Diffstat (limited to 'sys')
-rw-r--r-- | sys/net/route.c | 24 | ||||
-rw-r--r-- | sys/net/route.h | 2 |
2 files changed, 19 insertions, 7 deletions
diff --git a/sys/net/route.c b/sys/net/route.c index 5c6d526..3652eb4 100644 --- a/sys/net/route.c +++ b/sys/net/route.c @@ -454,18 +454,23 @@ rtalloc1_fib(struct sockaddr *dst, int report, u_long ignflags, /* * Look up the address in the table for that Address Family */ - RIB_RLOCK(rh); + if ((ignflags & RTF_RNH_LOCKED) == 0) + RIB_RLOCK(rh); +#ifdef INVARIANTS + else + RIB_LOCK_ASSERT(rh); +#endif rn = rh->rnh_matchaddr(dst, &rh->head); if (rn && ((rn->rn_flags & RNF_ROOT) == 0)) { newrt = RNTORT(rn); RT_LOCK(newrt); RT_ADDREF(newrt); - RIB_RUNLOCK(rh); + if ((ignflags & RTF_RNH_LOCKED) == 0) + RIB_RUNLOCK(rh); return (newrt); - } else + } else if ((ignflags & RTF_RNH_LOCKED) == 0) RIB_RUNLOCK(rh); - /* * Either we hit the root or could not find any match, * which basically means: "cannot get there from here". @@ -748,7 +753,9 @@ ifa_ifwithroute(int flags, const struct sockaddr *dst, struct sockaddr *gateway, if (ifa == NULL) ifa = ifa_ifwithnet(gateway, 0, fibnum); if (ifa == NULL) { - struct rtentry *rt = rtalloc1_fib(gateway, 0, 0, fibnum); + struct rtentry *rt; + + rt = rtalloc1_fib(gateway, 0, flags, fibnum); if (rt == NULL) return (NULL); /* @@ -1838,8 +1845,13 @@ rtrequest1_fib_change(struct rib_head *rnh, struct rt_addrinfo *info, info->rti_info[RTAX_IFP] != NULL || (info->rti_info[RTAX_IFA] != NULL && !sa_equal(info->rti_info[RTAX_IFA], rt->rt_ifa->ifa_addr))) { - + /* + * XXX: Temporarily set RTF_RNH_LOCKED flag in the rti_flags + * to avoid rlock in the ifa_ifwithroute(). + */ + info->rti_flags |= RTF_RNH_LOCKED; error = rt_getifa_fib(info, fibnum); + info->rti_flags &= ~RTF_RNH_LOCKED; if (info->rti_ifa != NULL) free_ifa = 1; diff --git a/sys/net/route.h b/sys/net/route.h index b6aa36d..d76ed70 100644 --- a/sys/net/route.h +++ b/sys/net/route.h @@ -189,7 +189,7 @@ struct rtentry { /* 0x8000000 and up unassigned */ #define RTF_STICKY 0x10000000 /* always route dst->src */ -#define RTF_RNH_LOCKED 0x40000000 /* unused */ +#define RTF_RNH_LOCKED 0x40000000 /* radix node head is locked */ #define RTF_GWFLAG_COMPAT 0x80000000 /* a compatibility bit for interacting with existing routing apps */ |