diff options
Diffstat (limited to 'drivers/net/bonding/bond_alb.c')
-rw-r--r-- | drivers/net/bonding/bond_alb.c | 110 |
1 files changed, 85 insertions, 25 deletions
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index aea2217c56eb..25b8dbf6cfd7 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c | |||
@@ -128,12 +128,12 @@ static inline u8 _simple_hash(const u8 *hash_start, int hash_size) | |||
128 | 128 | ||
129 | static inline void _lock_tx_hashtbl(struct bonding *bond) | 129 | static inline void _lock_tx_hashtbl(struct bonding *bond) |
130 | { | 130 | { |
131 | spin_lock(&(BOND_ALB_INFO(bond).tx_hashtbl_lock)); | 131 | spin_lock_bh(&(BOND_ALB_INFO(bond).tx_hashtbl_lock)); |
132 | } | 132 | } |
133 | 133 | ||
134 | static inline void _unlock_tx_hashtbl(struct bonding *bond) | 134 | static inline void _unlock_tx_hashtbl(struct bonding *bond) |
135 | { | 135 | { |
136 | spin_unlock(&(BOND_ALB_INFO(bond).tx_hashtbl_lock)); | 136 | spin_unlock_bh(&(BOND_ALB_INFO(bond).tx_hashtbl_lock)); |
137 | } | 137 | } |
138 | 138 | ||
139 | /* Caller must hold tx_hashtbl lock */ | 139 | /* Caller must hold tx_hashtbl lock */ |
@@ -305,12 +305,12 @@ static struct slave *tlb_choose_channel(struct bonding *bond, u32 hash_index, u3 | |||
305 | /*********************** rlb specific functions ***************************/ | 305 | /*********************** rlb specific functions ***************************/ |
306 | static inline void _lock_rx_hashtbl(struct bonding *bond) | 306 | static inline void _lock_rx_hashtbl(struct bonding *bond) |
307 | { | 307 | { |
308 | spin_lock(&(BOND_ALB_INFO(bond).rx_hashtbl_lock)); | 308 | spin_lock_bh(&(BOND_ALB_INFO(bond).rx_hashtbl_lock)); |
309 | } | 309 | } |
310 | 310 | ||
311 | static inline void _unlock_rx_hashtbl(struct bonding *bond) | 311 | static inline void _unlock_rx_hashtbl(struct bonding *bond) |
312 | { | 312 | { |
313 | spin_unlock(&(BOND_ALB_INFO(bond).rx_hashtbl_lock)); | 313 | spin_unlock_bh(&(BOND_ALB_INFO(bond).rx_hashtbl_lock)); |
314 | } | 314 | } |
315 | 315 | ||
316 | /* when an ARP REPLY is received from a client update its info | 316 | /* when an ARP REPLY is received from a client update its info |
@@ -472,13 +472,13 @@ static void rlb_clear_slave(struct bonding *bond, struct slave *slave) | |||
472 | 472 | ||
473 | _unlock_rx_hashtbl(bond); | 473 | _unlock_rx_hashtbl(bond); |
474 | 474 | ||
475 | write_lock(&bond->curr_slave_lock); | 475 | write_lock_bh(&bond->curr_slave_lock); |
476 | 476 | ||
477 | if (slave != bond->curr_active_slave) { | 477 | if (slave != bond->curr_active_slave) { |
478 | rlb_teach_disabled_mac_on_primary(bond, slave->dev->dev_addr); | 478 | rlb_teach_disabled_mac_on_primary(bond, slave->dev->dev_addr); |
479 | } | 479 | } |
480 | 480 | ||
481 | write_unlock(&bond->curr_slave_lock); | 481 | write_unlock_bh(&bond->curr_slave_lock); |
482 | } | 482 | } |
483 | 483 | ||
484 | static void rlb_update_client(struct rlb_client_info *client_info) | 484 | static void rlb_update_client(struct rlb_client_info *client_info) |
@@ -959,19 +959,34 @@ static int alb_set_slave_mac_addr(struct slave *slave, u8 addr[], int hw) | |||
959 | return 0; | 959 | return 0; |
960 | } | 960 | } |
961 | 961 | ||
962 | /* Caller must hold bond lock for write or curr_slave_lock for write*/ | 962 | /* |
963 | * Swap MAC addresses between two slaves. | ||
964 | * | ||
965 | * Called with RTNL held, and no other locks. | ||
966 | * | ||
967 | */ | ||
968 | |||
963 | static void alb_swap_mac_addr(struct bonding *bond, struct slave *slave1, struct slave *slave2) | 969 | static void alb_swap_mac_addr(struct bonding *bond, struct slave *slave1, struct slave *slave2) |
964 | { | 970 | { |
965 | struct slave *disabled_slave = NULL; | ||
966 | u8 tmp_mac_addr[ETH_ALEN]; | 971 | u8 tmp_mac_addr[ETH_ALEN]; |
967 | int slaves_state_differ; | ||
968 | |||
969 | slaves_state_differ = (SLAVE_IS_OK(slave1) != SLAVE_IS_OK(slave2)); | ||
970 | 972 | ||
971 | memcpy(tmp_mac_addr, slave1->dev->dev_addr, ETH_ALEN); | 973 | memcpy(tmp_mac_addr, slave1->dev->dev_addr, ETH_ALEN); |
972 | alb_set_slave_mac_addr(slave1, slave2->dev->dev_addr, bond->alb_info.rlb_enabled); | 974 | alb_set_slave_mac_addr(slave1, slave2->dev->dev_addr, bond->alb_info.rlb_enabled); |
973 | alb_set_slave_mac_addr(slave2, tmp_mac_addr, bond->alb_info.rlb_enabled); | 975 | alb_set_slave_mac_addr(slave2, tmp_mac_addr, bond->alb_info.rlb_enabled); |
974 | 976 | ||
977 | } | ||
978 | |||
979 | /* | ||
980 | * Send learning packets after MAC address swap. | ||
981 | * | ||
982 | * Called with RTNL and bond->lock held for read. | ||
983 | */ | ||
984 | static void alb_fasten_mac_swap(struct bonding *bond, struct slave *slave1, | ||
985 | struct slave *slave2) | ||
986 | { | ||
987 | int slaves_state_differ = (SLAVE_IS_OK(slave1) != SLAVE_IS_OK(slave2)); | ||
988 | struct slave *disabled_slave = NULL; | ||
989 | |||
975 | /* fasten the change in the switch */ | 990 | /* fasten the change in the switch */ |
976 | if (SLAVE_IS_OK(slave1)) { | 991 | if (SLAVE_IS_OK(slave1)) { |
977 | alb_send_learning_packets(slave1, slave1->dev->dev_addr); | 992 | alb_send_learning_packets(slave1, slave1->dev->dev_addr); |
@@ -1044,7 +1059,9 @@ static void alb_change_hw_addr_on_detach(struct bonding *bond, struct slave *sla | |||
1044 | } | 1059 | } |
1045 | 1060 | ||
1046 | if (found) { | 1061 | if (found) { |
1062 | /* locking: needs RTNL and nothing else */ | ||
1047 | alb_swap_mac_addr(bond, slave, tmp_slave); | 1063 | alb_swap_mac_addr(bond, slave, tmp_slave); |
1064 | alb_fasten_mac_swap(bond, slave, tmp_slave); | ||
1048 | } | 1065 | } |
1049 | } | 1066 | } |
1050 | } | 1067 | } |
@@ -1375,8 +1392,10 @@ out: | |||
1375 | return 0; | 1392 | return 0; |
1376 | } | 1393 | } |
1377 | 1394 | ||
1378 | void bond_alb_monitor(struct bonding *bond) | 1395 | void bond_alb_monitor(struct work_struct *work) |
1379 | { | 1396 | { |
1397 | struct bonding *bond = container_of(work, struct bonding, | ||
1398 | alb_work.work); | ||
1380 | struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); | 1399 | struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); |
1381 | struct slave *slave; | 1400 | struct slave *slave; |
1382 | int i; | 1401 | int i; |
@@ -1436,16 +1455,16 @@ void bond_alb_monitor(struct bonding *bond) | |||
1436 | 1455 | ||
1437 | /* handle rlb stuff */ | 1456 | /* handle rlb stuff */ |
1438 | if (bond_info->rlb_enabled) { | 1457 | if (bond_info->rlb_enabled) { |
1439 | /* the following code changes the promiscuity of the | ||
1440 | * the curr_active_slave. It needs to be locked with a | ||
1441 | * write lock to protect from other code that also | ||
1442 | * sets the promiscuity. | ||
1443 | */ | ||
1444 | write_lock_bh(&bond->curr_slave_lock); | ||
1445 | |||
1446 | if (bond_info->primary_is_promisc && | 1458 | if (bond_info->primary_is_promisc && |
1447 | (++bond_info->rlb_promisc_timeout_counter >= RLB_PROMISC_TIMEOUT)) { | 1459 | (++bond_info->rlb_promisc_timeout_counter >= RLB_PROMISC_TIMEOUT)) { |
1448 | 1460 | ||
1461 | /* | ||
1462 | * dev_set_promiscuity requires rtnl and | ||
1463 | * nothing else. | ||
1464 | */ | ||
1465 | read_unlock(&bond->lock); | ||
1466 | rtnl_lock(); | ||
1467 | |||
1449 | bond_info->rlb_promisc_timeout_counter = 0; | 1468 | bond_info->rlb_promisc_timeout_counter = 0; |
1450 | 1469 | ||
1451 | /* If the primary was set to promiscuous mode | 1470 | /* If the primary was set to promiscuous mode |
@@ -1454,9 +1473,10 @@ void bond_alb_monitor(struct bonding *bond) | |||
1454 | */ | 1473 | */ |
1455 | dev_set_promiscuity(bond->curr_active_slave->dev, -1); | 1474 | dev_set_promiscuity(bond->curr_active_slave->dev, -1); |
1456 | bond_info->primary_is_promisc = 0; | 1475 | bond_info->primary_is_promisc = 0; |
1457 | } | ||
1458 | 1476 | ||
1459 | write_unlock_bh(&bond->curr_slave_lock); | 1477 | rtnl_unlock(); |
1478 | read_lock(&bond->lock); | ||
1479 | } | ||
1460 | 1480 | ||
1461 | if (bond_info->rlb_rebalance) { | 1481 | if (bond_info->rlb_rebalance) { |
1462 | bond_info->rlb_rebalance = 0; | 1482 | bond_info->rlb_rebalance = 0; |
@@ -1479,7 +1499,7 @@ void bond_alb_monitor(struct bonding *bond) | |||
1479 | } | 1499 | } |
1480 | 1500 | ||
1481 | re_arm: | 1501 | re_arm: |
1482 | mod_timer(&(bond_info->alb_timer), jiffies + alb_delta_in_ticks); | 1502 | queue_delayed_work(bond->wq, &bond->alb_work, alb_delta_in_ticks); |
1483 | out: | 1503 | out: |
1484 | read_unlock(&bond->lock); | 1504 | read_unlock(&bond->lock); |
1485 | } | 1505 | } |
@@ -1500,11 +1520,11 @@ int bond_alb_init_slave(struct bonding *bond, struct slave *slave) | |||
1500 | /* caller must hold the bond lock for write since the mac addresses | 1520 | /* caller must hold the bond lock for write since the mac addresses |
1501 | * are compared and may be swapped. | 1521 | * are compared and may be swapped. |
1502 | */ | 1522 | */ |
1503 | write_lock_bh(&bond->lock); | 1523 | read_lock(&bond->lock); |
1504 | 1524 | ||
1505 | res = alb_handle_addr_collision_on_attach(bond, slave); | 1525 | res = alb_handle_addr_collision_on_attach(bond, slave); |
1506 | 1526 | ||
1507 | write_unlock_bh(&bond->lock); | 1527 | read_unlock(&bond->lock); |
1508 | 1528 | ||
1509 | if (res) { | 1529 | if (res) { |
1510 | return res; | 1530 | return res; |
@@ -1569,13 +1589,21 @@ void bond_alb_handle_link_change(struct bonding *bond, struct slave *slave, char | |||
1569 | * Set the bond->curr_active_slave to @new_slave and handle | 1589 | * Set the bond->curr_active_slave to @new_slave and handle |
1570 | * mac address swapping and promiscuity changes as needed. | 1590 | * mac address swapping and promiscuity changes as needed. |
1571 | * | 1591 | * |
1572 | * Caller must hold bond curr_slave_lock for write (or bond lock for write) | 1592 | * If new_slave is NULL, caller must hold curr_slave_lock or |
1593 | * bond->lock for write. | ||
1594 | * | ||
1595 | * If new_slave is not NULL, caller must hold RTNL, bond->lock for | ||
1596 | * read and curr_slave_lock for write. Processing here may sleep, so | ||
1597 | * no other locks may be held. | ||
1573 | */ | 1598 | */ |
1574 | void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave) | 1599 | void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave) |
1575 | { | 1600 | { |
1576 | struct slave *swap_slave; | 1601 | struct slave *swap_slave; |
1577 | int i; | 1602 | int i; |
1578 | 1603 | ||
1604 | if (new_slave) | ||
1605 | ASSERT_RTNL(); | ||
1606 | |||
1579 | if (bond->curr_active_slave == new_slave) { | 1607 | if (bond->curr_active_slave == new_slave) { |
1580 | return; | 1608 | return; |
1581 | } | 1609 | } |
@@ -1608,6 +1636,19 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave | |||
1608 | } | 1636 | } |
1609 | } | 1637 | } |
1610 | 1638 | ||
1639 | /* | ||
1640 | * Arrange for swap_slave and new_slave to temporarily be | ||
1641 | * ignored so we can mess with their MAC addresses without | ||
1642 | * fear of interference from transmit activity. | ||
1643 | */ | ||
1644 | if (swap_slave) { | ||
1645 | tlb_clear_slave(bond, swap_slave, 1); | ||
1646 | } | ||
1647 | tlb_clear_slave(bond, new_slave, 1); | ||
1648 | |||
1649 | write_unlock_bh(&bond->curr_slave_lock); | ||
1650 | read_unlock(&bond->lock); | ||
1651 | |||
1611 | /* curr_active_slave must be set before calling alb_swap_mac_addr */ | 1652 | /* curr_active_slave must be set before calling alb_swap_mac_addr */ |
1612 | if (swap_slave) { | 1653 | if (swap_slave) { |
1613 | /* swap mac address */ | 1654 | /* swap mac address */ |
@@ -1616,11 +1657,23 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave | |||
1616 | /* set the new_slave to the bond mac address */ | 1657 | /* set the new_slave to the bond mac address */ |
1617 | alb_set_slave_mac_addr(new_slave, bond->dev->dev_addr, | 1658 | alb_set_slave_mac_addr(new_slave, bond->dev->dev_addr, |
1618 | bond->alb_info.rlb_enabled); | 1659 | bond->alb_info.rlb_enabled); |
1660 | } | ||
1661 | |||
1662 | read_lock(&bond->lock); | ||
1663 | |||
1664 | if (swap_slave) { | ||
1665 | alb_fasten_mac_swap(bond, swap_slave, new_slave); | ||
1666 | } else { | ||
1619 | /* fasten bond mac on new current slave */ | 1667 | /* fasten bond mac on new current slave */ |
1620 | alb_send_learning_packets(new_slave, bond->dev->dev_addr); | 1668 | alb_send_learning_packets(new_slave, bond->dev->dev_addr); |
1621 | } | 1669 | } |
1670 | |||
1671 | write_lock_bh(&bond->curr_slave_lock); | ||
1622 | } | 1672 | } |
1623 | 1673 | ||
1674 | /* | ||
1675 | * Called with RTNL | ||
1676 | */ | ||
1624 | int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr) | 1677 | int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr) |
1625 | { | 1678 | { |
1626 | struct bonding *bond = bond_dev->priv; | 1679 | struct bonding *bond = bond_dev->priv; |
@@ -1657,8 +1710,12 @@ int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr) | |||
1657 | } | 1710 | } |
1658 | } | 1711 | } |
1659 | 1712 | ||
1713 | write_unlock_bh(&bond->curr_slave_lock); | ||
1714 | read_unlock(&bond->lock); | ||
1715 | |||
1660 | if (swap_slave) { | 1716 | if (swap_slave) { |
1661 | alb_swap_mac_addr(bond, swap_slave, bond->curr_active_slave); | 1717 | alb_swap_mac_addr(bond, swap_slave, bond->curr_active_slave); |
1718 | alb_fasten_mac_swap(bond, swap_slave, bond->curr_active_slave); | ||
1662 | } else { | 1719 | } else { |
1663 | alb_set_slave_mac_addr(bond->curr_active_slave, bond_dev->dev_addr, | 1720 | alb_set_slave_mac_addr(bond->curr_active_slave, bond_dev->dev_addr, |
1664 | bond->alb_info.rlb_enabled); | 1721 | bond->alb_info.rlb_enabled); |
@@ -1670,6 +1727,9 @@ int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr) | |||
1670 | } | 1727 | } |
1671 | } | 1728 | } |
1672 | 1729 | ||
1730 | read_lock(&bond->lock); | ||
1731 | write_lock_bh(&bond->curr_slave_lock); | ||
1732 | |||
1673 | return 0; | 1733 | return 0; |
1674 | } | 1734 | } |
1675 | 1735 | ||