aboutsummaryrefslogtreecommitdiff
path: root/sys/net/if_bridge.c
diff options
context:
space:
mode:
authorKristof Provost <kp@FreeBSD.org>2017-01-25 21:25:26 +0000
committerKristof Provost <kp@FreeBSD.org>2017-01-25 21:25:26 +0000
commitab5cda71df1d9b12d243f30d6f8183f65ae8355c (patch)
tree6b60f87af52cea013e657bd4f0975a94c9096b09 /sys/net/if_bridge.c
parent26594bd1ee12bdcdbc54f6c53b029f913fb55d6f (diff)
downloadsrc-ab5cda71df1d9b12d243f30d6f8183f65ae8355c.tar.gz
src-ab5cda71df1d9b12d243f30d6f8183f65ae8355c.zip
bridge: Release the bridge lock when calling bridge_set_ifcap()
This calls ioctl() handlers for the different interfaces in the bridge. These handlers expect to get called in an ioctl context where it's safe for them to sleep. We may not sleep with the bridge lock held. However, we still need to protect the interface list, to ensure it doesn't get changed while we iterate over it. Use BRIDGE_XLOCK(), which prevents bridge members from being removed. Adding bridge members is safe, because it uses LIST_INSERT_HEAD(). This caused panics when adding xen interfaces to a bridge. PR: 216304 Reviewed by: ae MFC after: 1 week Sponsored by: RootBSD Differential Revision: https://reviews.freebsd.org/D9290
Notes
Notes: svn path=/head/; revision=312782
Diffstat (limited to 'sys/net/if_bridge.c')
-rw-r--r--sys/net/if_bridge.c6
1 files changed, 6 insertions, 0 deletions
diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c
index d98e691e58e3..d04b60299830 100644
--- a/sys/net/if_bridge.c
+++ b/sys/net/if_bridge.c
@@ -909,14 +909,18 @@ bridge_mutecaps(struct bridge_softc *sc)
mask &= bif->bif_savedcaps;
}
+ BRIDGE_XLOCK(sc);
LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
enabled = bif->bif_ifp->if_capenable;
enabled &= ~BRIDGE_IFCAPS_STRIP;
/* strip off mask bits and enable them again if allowed */
enabled &= ~BRIDGE_IFCAPS_MASK;
enabled |= mask;
+ BRIDGE_UNLOCK(sc);
bridge_set_ifcap(sc, bif, enabled);
+ BRIDGE_LOCK(sc);
}
+ BRIDGE_XDROP(sc);
}
@@ -927,6 +931,8 @@ bridge_set_ifcap(struct bridge_softc *sc, struct bridge_iflist *bif, int set)
struct ifreq ifr;
int error;
+ BRIDGE_UNLOCK_ASSERT(sc);
+
bzero(&ifr, sizeof(ifr));
ifr.ifr_reqcap = set;