aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorXin Long <lucien.xin@gmail.com>2018-03-25 13:16:46 -0400
committerDavid S. Miller <davem@davemloft.net>2018-03-26 12:51:05 -0400
commitae42cc62a9f07f1f6979054ed92606b9c30f4a2e (patch)
tree01a68bd811a25483f2fef432180cd26a94084678
parent5c78f6bfae2b10ff70e21d343e64584ea6280c26 (diff)
bonding: move dev_mc_sync after master_upper_dev_link in bond_enslave
Beniamino found a crash when adding vlan as slave of bond which is also the parent link: ip link add bond1 type bond ip link set bond1 up ip link add link bond1 vlan1 type vlan id 80 ip link set vlan1 master bond1 The call trace is as below: [<ffffffffa850842a>] queued_spin_lock_slowpath+0xb/0xf [<ffffffffa8515680>] _raw_spin_lock+0x20/0x30 [<ffffffffa83f6f07>] dev_mc_sync+0x37/0x80 [<ffffffffc08687dc>] vlan_dev_set_rx_mode+0x1c/0x30 [8021q] [<ffffffffa83efd2a>] __dev_set_rx_mode+0x5a/0xa0 [<ffffffffa83f7138>] dev_mc_sync_multiple+0x78/0x80 [<ffffffffc084127c>] bond_enslave+0x67c/0x1190 [bonding] [<ffffffffa8401909>] do_setlink+0x9c9/0xe50 [<ffffffffa8403bf2>] rtnl_newlink+0x522/0x880 [<ffffffffa8403ff7>] rtnetlink_rcv_msg+0xa7/0x260 [<ffffffffa8424ecb>] netlink_rcv_skb+0xab/0xc0 [<ffffffffa83fe498>] rtnetlink_rcv+0x28/0x30 [<ffffffffa8424850>] netlink_unicast+0x170/0x210 [<ffffffffa8424bf8>] netlink_sendmsg+0x308/0x420 [<ffffffffa83cc396>] sock_sendmsg+0xb6/0xf0 This is actually a dead lock caused by sync slave hwaddr from master when the master is the slave's 'slave'. This dead loop check is actually done by netdev_master_upper_dev_link. However, Commit 1f718f0f4f97 ("bonding: populate neighbour's private on enslave") moved it after dev_mc_sync. This patch is to fix it by moving dev_mc_sync after master_upper_dev_link, so that this loop check would be earlier than dev_mc_sync. It also moves if (mode == BOND_MODE_8023AD) into if (!bond_uses_primary) clause as an improvement. Note team driver also has this issue, I will fix it in another patch. Fixes: 1f718f0f4f97 ("bonding: populate neighbour's private on enslave") Reported-by: Beniamino Galvani <bgalvani@redhat.com> Signed-off-by: Xin Long <lucien.xin@gmail.com> Acked-by: Andy Gospodarek <andy@greyhouse.net> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/bonding/bond_main.c73
1 files changed, 35 insertions, 38 deletions
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 0c299de4f2ef..55e198554ec0 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -1528,44 +1528,11 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev,
1528 goto err_close; 1528 goto err_close;
1529 } 1529 }
1530 1530
1531 /* If the mode uses primary, then the following is handled by
1532 * bond_change_active_slave().
1533 */
1534 if (!bond_uses_primary(bond)) {
1535 /* set promiscuity level to new slave */
1536 if (bond_dev->flags & IFF_PROMISC) {
1537 res = dev_set_promiscuity(slave_dev, 1);
1538 if (res)
1539 goto err_close;
1540 }
1541
1542 /* set allmulti level to new slave */
1543 if (bond_dev->flags & IFF_ALLMULTI) {
1544 res = dev_set_allmulti(slave_dev, 1);
1545 if (res)
1546 goto err_close;
1547 }
1548
1549 netif_addr_lock_bh(bond_dev);
1550
1551 dev_mc_sync_multiple(slave_dev, bond_dev);
1552 dev_uc_sync_multiple(slave_dev, bond_dev);
1553
1554 netif_addr_unlock_bh(bond_dev);
1555 }
1556
1557 if (BOND_MODE(bond) == BOND_MODE_8023AD) {
1558 /* add lacpdu mc addr to mc list */
1559 u8 lacpdu_multicast[ETH_ALEN] = MULTICAST_LACPDU_ADDR;
1560
1561 dev_mc_add(slave_dev, lacpdu_multicast);
1562 }
1563
1564 res = vlan_vids_add_by_dev(slave_dev, bond_dev); 1531 res = vlan_vids_add_by_dev(slave_dev, bond_dev);
1565 if (res) { 1532 if (res) {
1566 netdev_err(bond_dev, "Couldn't add bond vlan ids to %s\n", 1533 netdev_err(bond_dev, "Couldn't add bond vlan ids to %s\n",
1567 slave_dev->name); 1534 slave_dev->name);
1568 goto err_hwaddr_unsync; 1535 goto err_close;
1569 } 1536 }
1570 1537
1571 prev_slave = bond_last_slave(bond); 1538 prev_slave = bond_last_slave(bond);
@@ -1725,6 +1692,37 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev,
1725 goto err_upper_unlink; 1692 goto err_upper_unlink;
1726 } 1693 }
1727 1694
1695 /* If the mode uses primary, then the following is handled by
1696 * bond_change_active_slave().
1697 */
1698 if (!bond_uses_primary(bond)) {
1699 /* set promiscuity level to new slave */
1700 if (bond_dev->flags & IFF_PROMISC) {
1701 res = dev_set_promiscuity(slave_dev, 1);
1702 if (res)
1703 goto err_sysfs_del;
1704 }
1705
1706 /* set allmulti level to new slave */
1707 if (bond_dev->flags & IFF_ALLMULTI) {
1708 res = dev_set_allmulti(slave_dev, 1);
1709 if (res)
1710 goto err_sysfs_del;
1711 }
1712
1713 netif_addr_lock_bh(bond_dev);
1714 dev_mc_sync_multiple(slave_dev, bond_dev);
1715 dev_uc_sync_multiple(slave_dev, bond_dev);
1716 netif_addr_unlock_bh(bond_dev);
1717
1718 if (BOND_MODE(bond) == BOND_MODE_8023AD) {
1719 /* add lacpdu mc addr to mc list */
1720 u8 lacpdu_multicast[ETH_ALEN] = MULTICAST_LACPDU_ADDR;
1721
1722 dev_mc_add(slave_dev, lacpdu_multicast);
1723 }
1724 }
1725
1728 bond->slave_cnt++; 1726 bond->slave_cnt++;
1729 bond_compute_features(bond); 1727 bond_compute_features(bond);
1730 bond_set_carrier(bond); 1728 bond_set_carrier(bond);
@@ -1748,6 +1746,9 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev,
1748 return 0; 1746 return 0;
1749 1747
1750/* Undo stages on error */ 1748/* Undo stages on error */
1749err_sysfs_del:
1750 bond_sysfs_slave_del(new_slave);
1751
1751err_upper_unlink: 1752err_upper_unlink:
1752 bond_upper_dev_unlink(bond, new_slave); 1753 bond_upper_dev_unlink(bond, new_slave);
1753 1754
@@ -1768,10 +1769,6 @@ err_detach:
1768 synchronize_rcu(); 1769 synchronize_rcu();
1769 slave_disable_netpoll(new_slave); 1770 slave_disable_netpoll(new_slave);
1770 1771
1771err_hwaddr_unsync:
1772 if (!bond_uses_primary(bond))
1773 bond_hw_addr_flush(bond_dev, slave_dev);
1774
1775err_close: 1772err_close:
1776 slave_dev->priv_flags &= ~IFF_BONDING; 1773 slave_dev->priv_flags &= ~IFF_BONDING;
1777 dev_close(slave_dev); 1774 dev_close(slave_dev);