Message ID | 1452881034-19128-1-git-send-email-razor@blackwall.org |
---|---|
State | Accepted, archived |
Delegated to: | David Miller |
Headers | show |
From: Nikolay Aleksandrov <razor@blackwall.org> Date: Fri, 15 Jan 2016 19:03:54 +0100 > From: Nikolay Aleksandrov <nikolay@cumulusnetworks.com> > > After promisc mode management was introduced a bridge device could do > dev_set_promiscuity from its ndo_change_rx_flags() callback which in > turn can be called after the bridge's addr_list_lock has been taken > (e.g. by dev_uc_add). This causes a false positive lockdep splat because > the port interfaces' addr_list_lock is taken when br_manage_promisc() > runs after the bridge's addr list lock was already taken. > To remove the false positive introduce a custom bridge addr_list_lock > class and set it on bridge init. > A simple way to reproduce this is with the following: > $ brctl addbr br0 > $ ip l add l br0 br0.100 type vlan id 100 > $ ip l set br0 up > $ ip l set br0.100 up > $ echo 1 > /sys/class/net/br0/bridge/vlan_filtering > $ brctl addif br0 eth0 > Splat: ... > CC: Vlad Yasevich <vyasevic@redhat.com> > CC: Stephen Hemminger <stephen@networkplumber.org> > CC: Bridge list <bridge@lists.linux-foundation.org> > CC: Andy Gospodarek <gospo@cumulusnetworks.com> > CC: Roopa Prabhu <roopa@cumulusnetworks.com> > Fixes: 2796d0c648c9 ("bridge: Automatically manage port promiscuous mode.") > Reported-by: Andy Gospodarek <gospo@cumulusnetworks.com> > Signed-off-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com> Applied and queued up for -stable, thanks Nikolay.
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index 5e88d3e17546..2c8095a5d824 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c @@ -28,6 +28,8 @@ const struct nf_br_ops __rcu *nf_br_ops __read_mostly; EXPORT_SYMBOL_GPL(nf_br_ops); +static struct lock_class_key bridge_netdev_addr_lock_key; + /* net device transmit always called with BH disabled */ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev) { @@ -87,6 +89,11 @@ out: return NETDEV_TX_OK; } +static void br_set_lockdep_class(struct net_device *dev) +{ + lockdep_set_class(&dev->addr_list_lock, &bridge_netdev_addr_lock_key); +} + static int br_dev_init(struct net_device *dev) { struct net_bridge *br = netdev_priv(dev); @@ -99,6 +106,7 @@ static int br_dev_init(struct net_device *dev) err = br_vlan_init(br); if (err) free_percpu(br->stats); + br_set_lockdep_class(dev); return err; }