summaryrefslogtreecommitdiffstats
path: root/sys/netinet6
diff options
context:
space:
mode:
authorrwatson <rwatson@FreeBSD.org>2009-08-23 20:40:19 +0000
committerrwatson <rwatson@FreeBSD.org>2009-08-23 20:40:19 +0000
commitef8d755d4df716bf13f8a1833f7dd1db0b78c569 (patch)
tree83b839696bd918acacee8b38993abd3c6857a5fb /sys/netinet6
parent3d8e6186e2a82569f4f5214f8c8af700e5e36c13 (diff)
downloadFreeBSD-src-ef8d755d4df716bf13f8a1833f7dd1db0b78c569.zip
FreeBSD-src-ef8d755d4df716bf13f8a1833f7dd1db0b78c569.tar.gz
Rework global locks for interface list and index management, correcting
several critical bugs, including race conditions and lock order issues: Replace the single rwlock, ifnet_lock, with two locks, an rwlock and an sxlock. Either can be held to stablize the lists and indexes, but both are required to write. This allows the list to be held stable in both network interrupt contexts and sleepable user threads across sleeping memory allocations or device driver interactions. As before, writes to the interface list must occur from sleepable contexts. Reviewed by: bz, julian MFC after: 3 days
Diffstat (limited to 'sys/netinet6')
-rw-r--r--sys/netinet6/icmp6.c12
-rw-r--r--sys/netinet6/in6.c11
-rw-r--r--sys/netinet6/in6_ifattach.c6
-rw-r--r--sys/netinet6/nd6.c4
4 files changed, 14 insertions, 19 deletions
diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c
index 7fe63b6..6f13c69 100644
--- a/sys/netinet6/icmp6.c
+++ b/sys/netinet6/icmp6.c
@@ -1705,7 +1705,7 @@ ni6_addrs(struct icmp6_nodeinfo *ni6, struct mbuf *m, struct ifnet **ifpp,
}
}
- IFNET_RLOCK();
+ IFNET_RLOCK_NOSLEEP();
for (ifp = TAILQ_FIRST(&V_ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list)) {
addrsofif = 0;
IF_ADDR_LOCK(ifp);
@@ -1762,13 +1762,13 @@ ni6_addrs(struct icmp6_nodeinfo *ni6, struct mbuf *m, struct ifnet **ifpp,
IF_ADDR_UNLOCK(ifp);
if (iffound) {
*ifpp = ifp;
- IFNET_RUNLOCK();
+ IFNET_RUNLOCK_NOSLEEP();
return (addrsofif);
}
addrs += addrsofif;
}
- IFNET_RUNLOCK();
+ IFNET_RUNLOCK_NOSLEEP();
return (addrs);
}
@@ -1789,7 +1789,7 @@ ni6_store_addrs(struct icmp6_nodeinfo *ni6, struct icmp6_nodeinfo *nni6,
if (ifp0 == NULL && !(niflags & NI_NODEADDR_FLAG_ALL))
return (0); /* needless to copy */
- IFNET_RLOCK();
+ IFNET_RLOCK_NOSLEEP();
again:
for (; ifp; ifp = TAILQ_NEXT(ifp, if_list)) {
@@ -1854,7 +1854,7 @@ ni6_store_addrs(struct icmp6_nodeinfo *ni6, struct icmp6_nodeinfo *nni6,
* Set the truncate flag and return.
*/
nni6->ni_flags |= NI_NODEADDR_FLAG_TRUNCATE;
- IFNET_RUNLOCK();
+ IFNET_RUNLOCK_NOSLEEP();
return (copied);
}
@@ -1907,7 +1907,7 @@ ni6_store_addrs(struct icmp6_nodeinfo *ni6, struct icmp6_nodeinfo *nni6,
goto again;
}
- IFNET_RUNLOCK();
+ IFNET_RUNLOCK_NOSLEEP();
return (copied);
}
diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c
index c4333ed..7d9f7e7 100644
--- a/sys/netinet6/in6.c
+++ b/sys/netinet6/in6.c
@@ -2234,7 +2234,7 @@ in6_setmaxmtu(void)
unsigned long maxmtu = 0;
struct ifnet *ifp;
- IFNET_RLOCK();
+ IFNET_RLOCK_NOSLEEP();
for (ifp = TAILQ_FIRST(&V_ifnet); ifp;
ifp = TAILQ_NEXT(ifp, if_list)) {
/* this function can be called during ifnet initialization */
@@ -2244,7 +2244,7 @@ in6_setmaxmtu(void)
IN6_LINKMTU(ifp) > maxmtu)
maxmtu = IN6_LINKMTU(ifp);
}
- IFNET_RUNLOCK();
+ IFNET_RUNLOCK_NOSLEEP();
if (maxmtu) /* update only when maxmtu is positive */
V_in6_maxmtu = maxmtu;
}
@@ -2495,12 +2495,7 @@ in6_lltable_dump(struct lltable *llt, struct sysctl_req *wr)
} ndpc;
int i, error;
- /* XXXXX
- * current IFNET_RLOCK() is mapped to IFNET_WLOCK()
- * so it is okay to use this ASSERT, change it when
- * IFNET lock is finalized
- */
- IFNET_WLOCK_ASSERT();
+ IFNET_RLOCK_ASSERT();
error = 0;
for (i = 0; i < LLTBL_HASHTBL_SIZE; i++) {
diff --git a/sys/netinet6/in6_ifattach.c b/sys/netinet6/in6_ifattach.c
index 1fc54c6..6f9f11d 100644
--- a/sys/netinet6/in6_ifattach.c
+++ b/sys/netinet6/in6_ifattach.c
@@ -398,7 +398,7 @@ get_ifid(struct ifnet *ifp0, struct ifnet *altifp,
}
/* next, try to get it from some other hardware interface */
- IFNET_RLOCK();
+ IFNET_RLOCK_NOSLEEP();
for (ifp = V_ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next) {
if (ifp == ifp0)
continue;
@@ -413,11 +413,11 @@ get_ifid(struct ifnet *ifp0, struct ifnet *altifp,
nd6log((LOG_DEBUG,
"%s: borrow interface identifier from %s\n",
if_name(ifp0), if_name(ifp)));
- IFNET_RUNLOCK();
+ IFNET_RUNLOCK_NOSLEEP();
goto success;
}
}
- IFNET_RUNLOCK();
+ IFNET_RUNLOCK_NOSLEEP();
/* last resort: get from random number source */
if (get_rand_ifid(ifp, in6) == 0) {
diff --git a/sys/netinet6/nd6.c b/sys/netinet6/nd6.c
index 48635c5..acaa87e 100644
--- a/sys/netinet6/nd6.c
+++ b/sys/netinet6/nd6.c
@@ -1662,7 +1662,7 @@ nd6_slowtimo(void *arg)
callout_reset(&V_nd6_slowtimo_ch, ND6_SLOWTIMER_INTERVAL * hz,
nd6_slowtimo, curvnet);
- IFNET_RLOCK();
+ IFNET_RLOCK_NOSLEEP();
for (ifp = TAILQ_FIRST(&V_ifnet); ifp;
ifp = TAILQ_NEXT(ifp, if_list)) {
nd6if = ND_IFINFO(ifp);
@@ -1678,7 +1678,7 @@ nd6_slowtimo(void *arg)
nd6if->reachable = ND_COMPUTE_RTIME(nd6if->basereachable);
}
}
- IFNET_RUNLOCK();
+ IFNET_RUNLOCK_NOSLEEP();
CURVNET_RESTORE();
}
OpenPOWER on IntegriCloud