diff options
author | rwatson <rwatson@FreeBSD.org> | 2009-06-25 16:35:28 +0000 |
---|---|---|
committer | rwatson <rwatson@FreeBSD.org> | 2009-06-25 16:35:28 +0000 |
commit | bd6eb7be79d81290efa6dcaa9f492a05b1966344 (patch) | |
tree | ff4ff11920651e5f6aaeaa54e259e4f335eec1af /sys/netinet/ip_carp.c | |
parent | 07492aedb8a9805aa9b5287012a05ac498d59d7b (diff) | |
download | FreeBSD-src-bd6eb7be79d81290efa6dcaa9f492a05b1966344.zip FreeBSD-src-bd6eb7be79d81290efa6dcaa9f492a05b1966344.tar.gz |
Add address list locking for in6_ifaddrhead/ia_link: as with locking
for in_ifaddrhead, we stick with an rwlock for the time being, which
we will revisit in the future with a possible move to rmlocks.
Some pieces of code require significant further reworking to be
safe from all classes of writer-writer races.
Reviewed by: bz
MFC after: 6 weeks
Diffstat (limited to 'sys/netinet/ip_carp.c')
-rw-r--r-- | sys/netinet/ip_carp.c | 13 |
1 files changed, 11 insertions, 2 deletions
diff --git a/sys/netinet/ip_carp.c b/sys/netinet/ip_carp.c index 8c7bd0c..152f5e6 100644 --- a/sys/netinet/ip_carp.c +++ b/sys/netinet/ip_carp.c @@ -1680,6 +1680,7 @@ carp_set_addr6(struct carp_softc *sc, struct sockaddr_in6 *sin6) /* we have to do it by hands to check we won't match on us */ ia_if = NULL; own = 0; + IN6_IFADDR_RLOCK(); TAILQ_FOREACH(ia, &V_in6_ifaddrhead, ia_link) { int i; @@ -1702,14 +1703,20 @@ carp_set_addr6(struct carp_softc *sc, struct sockaddr_in6 *sin6) } } - if (!ia_if) + if (!ia_if) { + IN6_IFADDR_RUNLOCK(); return (EADDRNOTAVAIL); + } ia = ia_if; + ifa_ref(&ia->ia_ifa); + IN6_IFADDR_RUNLOCK(); ifp = ia->ia_ifp; if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0 || - (im6o->im6o_multicast_ifp && im6o->im6o_multicast_ifp != ifp)) + (im6o->im6o_multicast_ifp && im6o->im6o_multicast_ifp != ifp)) { + ifa_free(&ia->ia_ifa); return (EADDRNOTAVAIL); + } if (!sc->sc_naddrs6) { struct in6_multi *in6m; @@ -1811,12 +1818,14 @@ carp_set_addr6(struct carp_softc *sc, struct sockaddr_in6 *sin6) carp_setrun(sc, 0); CARP_UNLOCK(cif); + ifa_free(&ia->ia_ifa); /* XXXRW: should hold reference for softc. */ return (0); cleanup: if (!sc->sc_naddrs6) carp_multicast6_cleanup(sc); + ifa_free(&ia->ia_ifa); return (error); } |