diff options
author | rwatson <rwatson@FreeBSD.org> | 2009-04-20 16:05:16 +0000 |
---|---|---|
committer | rwatson <rwatson@FreeBSD.org> | 2009-04-20 16:05:16 +0000 |
commit | eb422ada74096ff9364e6e87dfe2b2a7390a437e (patch) | |
tree | af06d4202424155724a064297e38890d8cc435b9 /sys/netinet6/in6.c | |
parent | c07d8be27a1524f2a97721591588d69603218eab (diff) | |
download | FreeBSD-src-eb422ada74096ff9364e6e87dfe2b2a7390a437e.zip FreeBSD-src-eb422ada74096ff9364e6e87dfe2b2a7390a437e.tar.gz |
Close some but not all writer-writer races when maintaining IPv6
interface address lists by locking the interface address list lock.
MFC after: 2 weeks
Diffstat (limited to 'sys/netinet6/in6.c')
-rw-r--r-- | sys/netinet6/in6.c | 19 |
1 files changed, 18 insertions, 1 deletions
diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c index d8a11d0..d997057 100644 --- a/sys/netinet6/in6.c +++ b/sys/netinet6/in6.c @@ -815,7 +815,9 @@ in6_update_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra, V_in6_ifaddr = ia; ia->ia_ifa.ifa_refcnt = 1; + IF_ADDR_LOCK(ifp); TAILQ_INSERT_TAIL(&ifp->if_addrlist, &ia->ia_ifa, ifa_list); + IF_ADDR_UNLOCK(ifp); } /* update timestamp */ @@ -1175,7 +1177,9 @@ in6_unlink_ifa(struct in6_ifaddr *ia, struct ifnet *ifp) struct in6_ifaddr *oia; int s = splnet(); + IF_ADDR_LOCK(ifp); TAILQ_REMOVE(&ifp->if_addrlist, &ia->ia_ifa, ifa_list); + IF_ADDR_UNLOCK(ifp); oia = ia; if (oia == (ia = V_in6_ifaddr)) @@ -1410,6 +1414,7 @@ in6_lifaddr_ioctl(struct socket *so, u_long cmd, caddr_t data, } } + IF_ADDR_LOCK(ifp); TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; @@ -1430,6 +1435,7 @@ in6_lifaddr_ioctl(struct socket *so, u_long cmd, caddr_t data, if (IN6_ARE_ADDR_EQUAL(&candidate, &match)) break; } + IF_ADDR_UNLOCK(ifp); if (!ifa) return EADDRNOTAVAIL; ia = ifa2ia6(ifa); @@ -1507,11 +1513,13 @@ in6_ifinit(struct ifnet *ifp, struct in6_ifaddr *ia, * if this is its first address, * and to validate the address if necessary. */ + IF_ADDR_LOCK(ifp); TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; ifacount++; } + IF_ADDR_UNLOCK(ifp); ia->ia_addr = *sin6; @@ -1621,6 +1629,7 @@ in6ifa_ifpforlinklocal(struct ifnet *ifp, int ignoreflags) { struct ifaddr *ifa; + IF_ADDR_LOCK(ifp); TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; @@ -1631,6 +1640,7 @@ in6ifa_ifpforlinklocal(struct ifnet *ifp, int ignoreflags) break; } } + IF_ADDR_UNLOCK(ifp); return ((struct in6_ifaddr *)ifa); } @@ -1848,6 +1858,7 @@ in6_ifawithifp(struct ifnet *ifp, struct in6_addr *dst) * If two or more, return one which matches the dst longest. * If none, return one of global addresses assigned other ifs. */ + IF_ADDR_LOCK(ifp); TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; @@ -1879,8 +1890,10 @@ in6_ifawithifp(struct ifnet *ifp, struct in6_addr *dst) besta = (struct in6_ifaddr *)ifa; } } - if (besta) + if (besta) { + IF_ADDR_UNLOCK(ifp); return (besta); + } TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { if (ifa->ifa_addr->sa_family != AF_INET6) @@ -1897,8 +1910,10 @@ in6_ifawithifp(struct ifnet *ifp, struct in6_addr *dst) continue; } + IF_ADDR_UNLOCK(ifp); return (struct in6_ifaddr *)ifa; } + IF_ADDR_UNLOCK(ifp); /* use the last-resort values, that are, deprecated addresses */ if (dep[0]) @@ -1918,6 +1933,7 @@ in6_if_up(struct ifnet *ifp) struct ifaddr *ifa; struct in6_ifaddr *ia; + IF_ADDR_LOCK(ifp); TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; @@ -1933,6 +1949,7 @@ in6_if_up(struct ifnet *ifp) arc4random() % (MAX_RTR_SOLICITATION_DELAY * hz)); } } + IF_ADDR_UNLOCK(ifp); /* * special cases, like 6to4, are handled in in6_ifattach |