aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordingtianhong <dingtianhong@huawei.com>2014-02-25 22:05:22 -0500
committerDavid S. Miller <davem@davemloft.net>2014-02-26 16:02:56 -0500
commit5e5b066535f0ee58e5de3a2db5fb56fa3cd7e3b1 (patch)
tree16a4489e7420d7ec1da6c1904588519dcea7a78a
parentbc90d2918b343e114ddda91802f05a05dfed559e (diff)
bonding: Fix RTNL: assertion failed at net/core/rtnetlink.c for 802.3ad mode
The problem was introduced by the commit 1d3ee88ae0d (bonding: add netlink attributes to slave link dev). The bond_set_active_slave() and bond_set_backup_slave() will use rtmsg_ifinfo to send slave's states, so these two functions should be called in RTNL. In 802.3ad mode, acquiring RTNL for the __enable_port and __disable_port cases is difficult, as those calls generally already hold the state machine lock, and cannot unconditionally call rtnl_lock because either they already hold RTNL (for calls via bond_3ad_unbind_slave) or due to the potential for deadlock with bond_3ad_adapter_speed_changed, bond_3ad_adapter_duplex_changed, bond_3ad_link_change, or bond_3ad_update_lacp_rate. All four of those are called with RTNL held, and acquire the state machine lock second. The calling contexts for __enable_port and __disable_port already hold the state machine lock, and may or may not need RTNL. According to the Jay's opinion, I don't think it is a problem that the slave don't send notify message synchronously when the status changed, normally the state machine is running every 100 ms, send the notify message at the end of the state machine if the slave's state changed should be better. I fix the problem through these steps: 1). add a new function bond_set_slave_state() which could change the slave's state and call rtmsg_ifinfo() according to the input parameters called notify. 2). Add a new slave parameter which called should_notify, if the slave's state changed and don't notify yet, the parameter will be set to 1, and then if the slave's state changed again, the param will be set to 0, it indicate that the slave's state has been restored, no need to notify any one. 3). the __enable_port and __disable_port should not call rtmsg_ifinfo in the state machine lock, any change in the state of slave could set a flag in the slave, it will indicated that an rtmsg_ifinfo should be called at the end of the state machine. Cc: Jay Vosburgh <fubar@us.ibm.com> Cc: Veaceslav Falico <vfalico@redhat.com> Cc: Andy Gospodarek <andy@greyhouse.net> Signed-off-by: Ding Tianhong <dingtianhong@huawei.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/bonding/bond_3ad.c22
-rw-r--r--drivers/net/bonding/bond_main.c41
-rw-r--r--drivers/net/bonding/bonding.h34
3 files changed, 75 insertions, 22 deletions
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index 6d20fbde8d43..6826e4f61060 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -181,7 +181,7 @@ static inline int __agg_has_partner(struct aggregator *agg)
181 */ 181 */
182static inline void __disable_port(struct port *port) 182static inline void __disable_port(struct port *port)
183{ 183{
184 bond_set_slave_inactive_flags(port->slave); 184 bond_set_slave_inactive_flags(port->slave, BOND_SLAVE_NOTIFY_LATER);
185} 185}
186 186
187/** 187/**
@@ -193,7 +193,7 @@ static inline void __enable_port(struct port *port)
193 struct slave *slave = port->slave; 193 struct slave *slave = port->slave;
194 194
195 if ((slave->link == BOND_LINK_UP) && IS_UP(slave->dev)) 195 if ((slave->link == BOND_LINK_UP) && IS_UP(slave->dev))
196 bond_set_slave_active_flags(slave); 196 bond_set_slave_active_flags(slave, BOND_SLAVE_NOTIFY_LATER);
197} 197}
198 198
199/** 199/**
@@ -2062,6 +2062,7 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
2062 struct list_head *iter; 2062 struct list_head *iter;
2063 struct slave *slave; 2063 struct slave *slave;
2064 struct port *port; 2064 struct port *port;
2065 bool should_notify_rtnl = BOND_SLAVE_NOTIFY_LATER;
2065 2066
2066 read_lock(&bond->lock); 2067 read_lock(&bond->lock);
2067 rcu_read_lock(); 2068 rcu_read_lock();
@@ -2119,8 +2120,25 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
2119 } 2120 }
2120 2121
2121re_arm: 2122re_arm:
2123 bond_for_each_slave_rcu(bond, slave, iter) {
2124 if (slave->should_notify) {
2125 should_notify_rtnl = BOND_SLAVE_NOTIFY_NOW;
2126 break;
2127 }
2128 }
2122 rcu_read_unlock(); 2129 rcu_read_unlock();
2123 read_unlock(&bond->lock); 2130 read_unlock(&bond->lock);
2131
2132 if (should_notify_rtnl && rtnl_trylock()) {
2133 bond_for_each_slave(bond, slave, iter) {
2134 if (slave->should_notify) {
2135 rtmsg_ifinfo(RTM_NEWLINK, slave->dev, 0,
2136 GFP_KERNEL);
2137 slave->should_notify = 0;
2138 }
2139 }
2140 rtnl_unlock();
2141 }
2124 queue_delayed_work(bond->wq, &bond->ad_work, ad_delta_in_ticks); 2142 queue_delayed_work(bond->wq, &bond->ad_work, ad_delta_in_ticks);
2125} 2143}
2126 2144
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 1c6104d3501d..e02029bbf5cc 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -829,21 +829,25 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
829 if (bond_is_lb(bond)) { 829 if (bond_is_lb(bond)) {
830 bond_alb_handle_active_change(bond, new_active); 830 bond_alb_handle_active_change(bond, new_active);
831 if (old_active) 831 if (old_active)
832 bond_set_slave_inactive_flags(old_active); 832 bond_set_slave_inactive_flags(old_active,
833 BOND_SLAVE_NOTIFY_NOW);
833 if (new_active) 834 if (new_active)
834 bond_set_slave_active_flags(new_active); 835 bond_set_slave_active_flags(new_active,
836 BOND_SLAVE_NOTIFY_NOW);
835 } else { 837 } else {
836 rcu_assign_pointer(bond->curr_active_slave, new_active); 838 rcu_assign_pointer(bond->curr_active_slave, new_active);
837 } 839 }
838 840
839 if (bond->params.mode == BOND_MODE_ACTIVEBACKUP) { 841 if (bond->params.mode == BOND_MODE_ACTIVEBACKUP) {
840 if (old_active) 842 if (old_active)
841 bond_set_slave_inactive_flags(old_active); 843 bond_set_slave_inactive_flags(old_active,
844 BOND_SLAVE_NOTIFY_NOW);
842 845
843 if (new_active) { 846 if (new_active) {
844 bool should_notify_peers = false; 847 bool should_notify_peers = false;
845 848
846 bond_set_slave_active_flags(new_active); 849 bond_set_slave_active_flags(new_active,
850 BOND_SLAVE_NOTIFY_NOW);
847 851
848 if (bond->params.fail_over_mac) 852 if (bond->params.fail_over_mac)
849 bond_do_fail_over_mac(bond, new_active, 853 bond_do_fail_over_mac(bond, new_active,
@@ -1463,14 +1467,15 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
1463 1467
1464 switch (bond->params.mode) { 1468 switch (bond->params.mode) {
1465 case BOND_MODE_ACTIVEBACKUP: 1469 case BOND_MODE_ACTIVEBACKUP:
1466 bond_set_slave_inactive_flags(new_slave); 1470 bond_set_slave_inactive_flags(new_slave,
1471 BOND_SLAVE_NOTIFY_NOW);
1467 break; 1472 break;
1468 case BOND_MODE_8023AD: 1473 case BOND_MODE_8023AD:
1469 /* in 802.3ad mode, the internal mechanism 1474 /* in 802.3ad mode, the internal mechanism
1470 * will activate the slaves in the selected 1475 * will activate the slaves in the selected
1471 * aggregator 1476 * aggregator
1472 */ 1477 */
1473 bond_set_slave_inactive_flags(new_slave); 1478 bond_set_slave_inactive_flags(new_slave, BOND_SLAVE_NOTIFY_NOW);
1474 /* if this is the first slave */ 1479 /* if this is the first slave */
1475 if (!prev_slave) { 1480 if (!prev_slave) {
1476 SLAVE_AD_INFO(new_slave).id = 1; 1481 SLAVE_AD_INFO(new_slave).id = 1;
@@ -1488,7 +1493,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
1488 case BOND_MODE_TLB: 1493 case BOND_MODE_TLB:
1489 case BOND_MODE_ALB: 1494 case BOND_MODE_ALB:
1490 bond_set_active_slave(new_slave); 1495 bond_set_active_slave(new_slave);
1491 bond_set_slave_inactive_flags(new_slave); 1496 bond_set_slave_inactive_flags(new_slave, BOND_SLAVE_NOTIFY_NOW);
1492 break; 1497 break;
1493 default: 1498 default:
1494 pr_debug("This slave is always active in trunk mode\n"); 1499 pr_debug("This slave is always active in trunk mode\n");
@@ -2015,7 +2020,8 @@ static void bond_miimon_commit(struct bonding *bond)
2015 2020
2016 if (bond->params.mode == BOND_MODE_ACTIVEBACKUP || 2021 if (bond->params.mode == BOND_MODE_ACTIVEBACKUP ||
2017 bond->params.mode == BOND_MODE_8023AD) 2022 bond->params.mode == BOND_MODE_8023AD)
2018 bond_set_slave_inactive_flags(slave); 2023 bond_set_slave_inactive_flags(slave,
2024 BOND_SLAVE_NOTIFY_NOW);
2019 2025
2020 pr_info("%s: link status definitely down for interface %s, disabling it\n", 2026 pr_info("%s: link status definitely down for interface %s, disabling it\n",
2021 bond->dev->name, slave->dev->name); 2027 bond->dev->name, slave->dev->name);
@@ -2562,7 +2568,8 @@ static void bond_ab_arp_commit(struct bonding *bond)
2562 slave->link = BOND_LINK_UP; 2568 slave->link = BOND_LINK_UP;
2563 if (bond->current_arp_slave) { 2569 if (bond->current_arp_slave) {
2564 bond_set_slave_inactive_flags( 2570 bond_set_slave_inactive_flags(
2565 bond->current_arp_slave); 2571 bond->current_arp_slave,
2572 BOND_SLAVE_NOTIFY_NOW);
2566 bond->current_arp_slave = NULL; 2573 bond->current_arp_slave = NULL;
2567 } 2574 }
2568 2575
@@ -2582,7 +2589,8 @@ static void bond_ab_arp_commit(struct bonding *bond)
2582 slave->link_failure_count++; 2589 slave->link_failure_count++;
2583 2590
2584 slave->link = BOND_LINK_DOWN; 2591 slave->link = BOND_LINK_DOWN;
2585 bond_set_slave_inactive_flags(slave); 2592 bond_set_slave_inactive_flags(slave,
2593 BOND_SLAVE_NOTIFY_NOW);
2586 2594
2587 pr_info("%s: link status definitely down for interface %s, disabling it\n", 2595 pr_info("%s: link status definitely down for interface %s, disabling it\n",
2588 bond->dev->name, slave->dev->name); 2596 bond->dev->name, slave->dev->name);
@@ -2657,7 +2665,7 @@ static bool bond_ab_arp_probe(struct bonding *bond)
2657 } 2665 }
2658 } 2666 }
2659 2667
2660 bond_set_slave_inactive_flags(curr_arp_slave); 2668 bond_set_slave_inactive_flags(curr_arp_slave, BOND_SLAVE_NOTIFY_NOW);
2661 2669
2662 bond_for_each_slave(bond, slave, iter) { 2670 bond_for_each_slave(bond, slave, iter) {
2663 if (!found && !before && IS_UP(slave->dev)) 2671 if (!found && !before && IS_UP(slave->dev))
@@ -2677,7 +2685,8 @@ static bool bond_ab_arp_probe(struct bonding *bond)
2677 if (slave->link_failure_count < UINT_MAX) 2685 if (slave->link_failure_count < UINT_MAX)
2678 slave->link_failure_count++; 2686 slave->link_failure_count++;
2679 2687
2680 bond_set_slave_inactive_flags(slave); 2688 bond_set_slave_inactive_flags(slave,
2689 BOND_SLAVE_NOTIFY_NOW);
2681 2690
2682 pr_info("%s: backup interface %s is now down.\n", 2691 pr_info("%s: backup interface %s is now down.\n",
2683 bond->dev->name, slave->dev->name); 2692 bond->dev->name, slave->dev->name);
@@ -2695,7 +2704,7 @@ static bool bond_ab_arp_probe(struct bonding *bond)
2695 } 2704 }
2696 2705
2697 new_slave->link = BOND_LINK_BACK; 2706 new_slave->link = BOND_LINK_BACK;
2698 bond_set_slave_active_flags(new_slave); 2707 bond_set_slave_active_flags(new_slave, BOND_SLAVE_NOTIFY_NOW);
2699 bond_arp_send_all(bond, new_slave); 2708 bond_arp_send_all(bond, new_slave);
2700 new_slave->jiffies = jiffies; 2709 new_slave->jiffies = jiffies;
2701 rcu_assign_pointer(bond->current_arp_slave, new_slave); 2710 rcu_assign_pointer(bond->current_arp_slave, new_slave);
@@ -3046,9 +3055,11 @@ static int bond_open(struct net_device *bond_dev)
3046 bond_for_each_slave(bond, slave, iter) { 3055 bond_for_each_slave(bond, slave, iter) {
3047 if ((bond->params.mode == BOND_MODE_ACTIVEBACKUP) 3056 if ((bond->params.mode == BOND_MODE_ACTIVEBACKUP)
3048 && (slave != bond->curr_active_slave)) { 3057 && (slave != bond->curr_active_slave)) {
3049 bond_set_slave_inactive_flags(slave); 3058 bond_set_slave_inactive_flags(slave,
3059 BOND_SLAVE_NOTIFY_NOW);
3050 } else { 3060 } else {
3051 bond_set_slave_active_flags(slave); 3061 bond_set_slave_active_flags(slave,
3062 BOND_SLAVE_NOTIFY_NOW);
3052 } 3063 }
3053 } 3064 }
3054 read_unlock(&bond->curr_slave_lock); 3065 read_unlock(&bond->curr_slave_lock);
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 86ccfb9f71cc..9b280ac8c454 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -195,7 +195,8 @@ struct slave {
195 s8 new_link; 195 s8 new_link;
196 u8 backup:1, /* indicates backup slave. Value corresponds with 196 u8 backup:1, /* indicates backup slave. Value corresponds with
197 BOND_STATE_ACTIVE and BOND_STATE_BACKUP */ 197 BOND_STATE_ACTIVE and BOND_STATE_BACKUP */
198 inactive:1; /* indicates inactive slave */ 198 inactive:1, /* indicates inactive slave */
199 should_notify:1; /* indicateds whether the state changed */
199 u8 duplex; 200 u8 duplex;
200 u32 original_mtu; 201 u32 original_mtu;
201 u32 link_failure_count; 202 u32 link_failure_count;
@@ -303,6 +304,24 @@ static inline void bond_set_backup_slave(struct slave *slave)
303 } 304 }
304} 305}
305 306
307static inline void bond_set_slave_state(struct slave *slave,
308 int slave_state, bool notify)
309{
310 if (slave->backup == slave_state)
311 return;
312
313 slave->backup = slave_state;
314 if (notify) {
315 rtmsg_ifinfo(RTM_NEWLINK, slave->dev, 0, GFP_KERNEL);
316 slave->should_notify = 0;
317 } else {
318 if (slave->should_notify)
319 slave->should_notify = 0;
320 else
321 slave->should_notify = 1;
322 }
323}
324
306static inline void bond_slave_state_change(struct bonding *bond) 325static inline void bond_slave_state_change(struct bonding *bond)
307{ 326{
308 struct list_head *iter; 327 struct list_head *iter;
@@ -343,6 +362,9 @@ static inline bool bond_is_active_slave(struct slave *slave)
343#define BOND_ARP_VALIDATE_ALL (BOND_ARP_VALIDATE_ACTIVE | \ 362#define BOND_ARP_VALIDATE_ALL (BOND_ARP_VALIDATE_ACTIVE | \
344 BOND_ARP_VALIDATE_BACKUP) 363 BOND_ARP_VALIDATE_BACKUP)
345 364
365#define BOND_SLAVE_NOTIFY_NOW true
366#define BOND_SLAVE_NOTIFY_LATER false
367
346static inline int slave_do_arp_validate(struct bonding *bond, 368static inline int slave_do_arp_validate(struct bonding *bond,
347 struct slave *slave) 369 struct slave *slave)
348{ 370{
@@ -394,17 +416,19 @@ static inline void bond_netpoll_send_skb(const struct slave *slave,
394} 416}
395#endif 417#endif
396 418
397static inline void bond_set_slave_inactive_flags(struct slave *slave) 419static inline void bond_set_slave_inactive_flags(struct slave *slave,
420 bool notify)
398{ 421{
399 if (!bond_is_lb(slave->bond)) 422 if (!bond_is_lb(slave->bond))
400 bond_set_backup_slave(slave); 423 bond_set_slave_state(slave, BOND_STATE_BACKUP, notify);
401 if (!slave->bond->params.all_slaves_active) 424 if (!slave->bond->params.all_slaves_active)
402 slave->inactive = 1; 425 slave->inactive = 1;
403} 426}
404 427
405static inline void bond_set_slave_active_flags(struct slave *slave) 428static inline void bond_set_slave_active_flags(struct slave *slave,
429 bool notify)
406{ 430{
407 bond_set_active_slave(slave); 431 bond_set_slave_state(slave, BOND_STATE_ACTIVE, notify);
408 slave->inactive = 0; 432 slave->inactive = 0;
409} 433}
410 434