diff options
author | rwatson <rwatson@FreeBSD.org> | 2009-06-25 11:52:33 +0000 |
---|---|---|
committer | rwatson <rwatson@FreeBSD.org> | 2009-06-25 11:52:33 +0000 |
commit | ea70a3542dc7bf7a2e16d5d9c4639fd211a395b6 (patch) | |
tree | f7bd2b06a93cabd18d4d4396239234b49517bc87 /sys/netinet/in_pcb.c | |
parent | 078b9535f0627f5c60944246a4c3df0402604c44 (diff) | |
download | FreeBSD-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/in_pcb.c')
-rw-r--r-- | sys/netinet/in_pcb.c | 21 |
1 files changed, 15 insertions, 6 deletions
diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c index 574ce63..958e6b6 100644 --- a/sys/netinet/in_pcb.c +++ b/sys/netinet/in_pcb.c @@ -813,16 +813,21 @@ in_pcbconnect_setup(struct inpcb *inp, struct sockaddr *nam, * choose the broadcast address for that interface. */ if (faddr.s_addr == INADDR_ANY) { + IN_IFADDR_RLOCK(); faddr = IA_SIN(TAILQ_FIRST(&V_in_ifaddrhead))->sin_addr; + IN_IFADDR_RUNLOCK(); if (cred != NULL && (error = prison_get_ip4(cred, &faddr)) != 0) return (error); - } else if (faddr.s_addr == (u_long)INADDR_BROADCAST && - (TAILQ_FIRST(&V_in_ifaddrhead)->ia_ifp->if_flags & - IFF_BROADCAST)) - faddr = satosin(&TAILQ_FIRST( - &V_in_ifaddrhead)->ia_broadaddr)->sin_addr; + } else if (faddr.s_addr == (u_long)INADDR_BROADCAST) { + IN_IFADDR_RLOCK(); + if (TAILQ_FIRST(&V_in_ifaddrhead)->ia_ifp->if_flags & + IFF_BROADCAST) + faddr = satosin(&TAILQ_FIRST( + &V_in_ifaddrhead)->ia_broadaddr)->sin_addr; + IN_IFADDR_RUNLOCK(); + } } if (laddr.s_addr == INADDR_ANY) { error = in_pcbladdr(inp, &faddr, &laddr, cred); @@ -842,12 +847,16 @@ in_pcbconnect_setup(struct inpcb *inp, struct sockaddr *nam, imo = inp->inp_moptions; if (imo->imo_multicast_ifp != NULL) { ifp = imo->imo_multicast_ifp; + IN_IFADDR_RLOCK(); TAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) if (ia->ia_ifp == ifp) break; - if (ia == NULL) + if (ia == NULL) { + IN_IFADDR_RUNLOCK(); return (EADDRNOTAVAIL); + } laddr = ia->ia_addr.sin_addr; + IN_IFADDR_RUNLOCK(); } } } |