summaryrefslogtreecommitdiffstats
path: root/sys/netinet/if_ether.c
diff options
context:
space:
mode:
authorrwatson <rwatson@FreeBSD.org>2009-06-25 11:52:33 +0000
committerrwatson <rwatson@FreeBSD.org>2009-06-25 11:52:33 +0000
commitea70a3542dc7bf7a2e16d5d9c4639fd211a395b6 (patch)
treef7bd2b06a93cabd18d4d4396239234b49517bc87 /sys/netinet/if_ether.c
parent078b9535f0627f5c60944246a4c3df0402604c44 (diff)
downloadFreeBSD-src-ea70a3542dc7bf7a2e16d5d9c4639fd211a395b6.zip
FreeBSD-src-ea70a3542dc7bf7a2e16d5d9c4639fd211a395b6.tar.gz
Add a new global rwlock, in_ifaddr_lock, which will synchronize use of the
in_ifaddrhead and INADDR_HASH address lists. Previously, these lists were used unsynchronized as they were effectively never changed in steady state, but we've seen increasing reports of writer-writer races on very busy VPN servers as core count has gone up (and similar configurations where address lists change frequently and concurrently). For the time being, use rwlocks rather than rmlocks in order to take advantage of their better lock debugging support. As a result, we don't enable ip_input()'s read-locking of INADDR_HASH until an rmlock conversion is complete and a performance analysis has been done. This means that one class of reader-writer races still exists. MFC after: 6 weeks Reviewed by: bz
Diffstat (limited to 'sys/netinet/if_ether.c')
-rw-r--r--sys/netinet/if_ether.c12
1 files changed, 11 insertions, 1 deletions
diff --git a/sys/netinet/if_ether.c b/sys/netinet/if_ether.c
index 9c80ea0..97ea108 100644
--- a/sys/netinet/if_ether.c
+++ b/sys/netinet/if_ether.c
@@ -509,11 +509,13 @@ in_arpinput(struct mbuf *m)
* request for the virtual host ip.
* XXX: This is really ugly!
*/
+ IN_IFADDR_RLOCK();
LIST_FOREACH(ia, INADDR_HASH(itaddr.s_addr), ia_hash) {
if (((bridged && ia->ia_ifp->if_bridge != NULL) ||
ia->ia_ifp == ifp) &&
itaddr.s_addr == ia->ia_addr.sin_addr.s_addr) {
ifa_ref(&ia->ia_ifa);
+ IN_IFADDR_RUNLOCK();
goto match;
}
#ifdef DEV_CARP
@@ -522,6 +524,7 @@ in_arpinput(struct mbuf *m)
itaddr.s_addr == ia->ia_addr.sin_addr.s_addr) {
carp_match = 1;
ifa_ref(&ia->ia_ifa);
+ IN_IFADDR_RUNLOCK();
goto match;
}
#endif
@@ -531,6 +534,7 @@ in_arpinput(struct mbuf *m)
ia->ia_ifp == ifp) &&
isaddr.s_addr == ia->ia_addr.sin_addr.s_addr) {
ifa_ref(&ia->ia_ifa);
+ IN_IFADDR_RUNLOCK();
goto match;
}
@@ -549,11 +553,13 @@ in_arpinput(struct mbuf *m)
if (BDG_MEMBER_MATCHES_ARP(itaddr.s_addr, ifp, ia)) {
ifa_ref(&ia->ia_ifa);
ifp = ia->ia_ifp;
+ IN_IFADDR_RUNLOCK();
goto match;
}
}
}
#undef BDG_MEMBER_MATCHES_ARP
+ IN_IFADDR_RUNLOCK();
/*
* No match, use the first inet address on the receive interface
@@ -572,9 +578,13 @@ in_arpinput(struct mbuf *m)
/*
* If bridging, fall back to using any inet address.
*/
- if (!bridged || (ia = TAILQ_FIRST(&V_in_ifaddrhead)) == NULL)
+ IN_IFADDR_RLOCK();
+ if (!bridged || (ia = TAILQ_FIRST(&V_in_ifaddrhead)) == NULL) {
+ IN_IFADDR_RUNLOCK();
goto drop;
+ }
ifa_ref(&ia->ia_ifa);
+ IN_IFADDR_RUNLOCK();
match:
if (!enaddr)
enaddr = (u_int8_t *)IF_LLADDR(ifp);
OpenPOWER on IntegriCloud