aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNikolay Aleksandrov <nikolay@redhat.com>2014-02-26 08:20:30 -0500
committerDavid S. Miller <davem@davemloft.net>2014-02-26 17:09:09 -0500
commitee6154e11eeccd4ae32c4881415dbd902a869592 (patch)
treeee61b4fe5ed2665a595d9119afe433608c19e21e
parente5fe0cd442e50f156bb54f5385b19eda50a13ccd (diff)
bonding: fix a div error caused by the slave release path
There's a bug in the slave release function which leads the transmit functions which use the bond->slave_cnt to a div by 0 because we might just have released our last slave and made slave_cnt == 0 but at the same time we may have a transmitter after the check for an empty list which will fetch it and use it in the slave id calculation. Fix it by moving the slave_cnt after synchronize_rcu so if this was our last slave any new transmitters will see an empty slave list which is checked after rcu lock but before calling the mode transmit functions which rely on bond->slave_cnt. Fixes: 278b208375 ("bonding: initial RCU conversion") CC: Veaceslav Falico <vfalico@redhat.com> CC: Andy Gospodarek <andy@greyhouse.net> CC: Jay Vosburgh <fubar@us.ibm.com> CC: David S. Miller <davem@davemloft.net> Signed-off-by: Nikolay Aleksandrov <nikolay@redhat.com> Acked-by: Veaceslav Falico <vfalico@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/bonding/bond_main.c4
1 files changed, 1 insertions, 3 deletions
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 82b70ff1fd28..b47fa0421e01 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -1659,9 +1659,6 @@ static int __bond_release_one(struct net_device *bond_dev,
1659 return -EINVAL; 1659 return -EINVAL;
1660 } 1660 }
1661 1661
1662 /* release the slave from its bond */
1663 bond->slave_cnt--;
1664
1665 bond_sysfs_slave_del(slave); 1662 bond_sysfs_slave_del(slave);
1666 1663
1667 bond_upper_dev_unlink(bond_dev, slave_dev); 1664 bond_upper_dev_unlink(bond_dev, slave_dev);
@@ -1743,6 +1740,7 @@ static int __bond_release_one(struct net_device *bond_dev,
1743 1740
1744 unblock_netpoll_tx(); 1741 unblock_netpoll_tx();
1745 synchronize_rcu(); 1742 synchronize_rcu();
1743 bond->slave_cnt--;
1746 1744
1747 if (!bond_has_slaves(bond)) { 1745 if (!bond_has_slaves(bond)) {
1748 call_netdevice_notifiers(NETDEV_CHANGEADDR, bond->dev); 1746 call_netdevice_notifiers(NETDEV_CHANGEADDR, bond->dev);