diff options
author | Ding Tianhong <dingtianhong@huawei.com> | 2014-01-27 22:48:53 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-01-29 02:48:33 -0500 |
commit | 6fde8f037e604e05df1529e4689041715d6d55d2 (patch) | |
tree | 4cdf943fb2d475899f0a0d5a40cd4002184faff1 | |
parent | 93e14b6d776e850a371fe4234a06088f210d8651 (diff) |
bonding: fix locking in bond_loadbalance_arp_mon()
The commit 1d3ee88ae0d605629bf369
(bonding: add netlink attributes to slave link dev)
has add rtmsg_ifinfo() in bond_set_active_slave() and
bond_set_backup_slave(), so the two function need to
called in RTNL lock, but bond_loadbalance_arp_mon()
only calling these functions in RCU, warning message
will occurs.
fix this by add a new function bond_slave_state_change(),
which will reset the slave's state after slave link check,
so remove the bond_set_xxx_slave() from the cycle and only
record the slave_state_changed, this will call the new
function to set all slaves to new state in RTNL later.
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_main.c | 29 | ||||
-rw-r--r-- | drivers/net/bonding/bonding.h | 13 |
2 files changed, 30 insertions, 12 deletions
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index dd75615d85f2..4c08018d7333 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c | |||
@@ -2346,7 +2346,7 @@ static void bond_loadbalance_arp_mon(struct work_struct *work) | |||
2346 | arp_work.work); | 2346 | arp_work.work); |
2347 | struct slave *slave, *oldcurrent; | 2347 | struct slave *slave, *oldcurrent; |
2348 | struct list_head *iter; | 2348 | struct list_head *iter; |
2349 | int do_failover = 0; | 2349 | int do_failover = 0, slave_state_changed = 0; |
2350 | 2350 | ||
2351 | if (!bond_has_slaves(bond)) | 2351 | if (!bond_has_slaves(bond)) |
2352 | goto re_arm; | 2352 | goto re_arm; |
@@ -2370,7 +2370,7 @@ static void bond_loadbalance_arp_mon(struct work_struct *work) | |||
2370 | bond_time_in_interval(bond, slave->dev->last_rx, 1)) { | 2370 | bond_time_in_interval(bond, slave->dev->last_rx, 1)) { |
2371 | 2371 | ||
2372 | slave->link = BOND_LINK_UP; | 2372 | slave->link = BOND_LINK_UP; |
2373 | bond_set_active_slave(slave); | 2373 | slave_state_changed = 1; |
2374 | 2374 | ||
2375 | /* primary_slave has no meaning in round-robin | 2375 | /* primary_slave has no meaning in round-robin |
2376 | * mode. the window of a slave being up and | 2376 | * mode. the window of a slave being up and |
@@ -2399,7 +2399,7 @@ static void bond_loadbalance_arp_mon(struct work_struct *work) | |||
2399 | !bond_time_in_interval(bond, slave->dev->last_rx, 2)) { | 2399 | !bond_time_in_interval(bond, slave->dev->last_rx, 2)) { |
2400 | 2400 | ||
2401 | slave->link = BOND_LINK_DOWN; | 2401 | slave->link = BOND_LINK_DOWN; |
2402 | bond_set_backup_slave(slave); | 2402 | slave_state_changed = 1; |
2403 | 2403 | ||
2404 | if (slave->link_failure_count < UINT_MAX) | 2404 | if (slave->link_failure_count < UINT_MAX) |
2405 | slave->link_failure_count++; | 2405 | slave->link_failure_count++; |
@@ -2426,19 +2426,24 @@ static void bond_loadbalance_arp_mon(struct work_struct *work) | |||
2426 | 2426 | ||
2427 | rcu_read_unlock(); | 2427 | rcu_read_unlock(); |
2428 | 2428 | ||
2429 | if (do_failover) { | 2429 | if (do_failover || slave_state_changed) { |
2430 | /* the bond_select_active_slave must hold RTNL | ||
2431 | * and curr_slave_lock for write. | ||
2432 | */ | ||
2433 | if (!rtnl_trylock()) | 2430 | if (!rtnl_trylock()) |
2434 | goto re_arm; | 2431 | goto re_arm; |
2435 | block_netpoll_tx(); | ||
2436 | write_lock_bh(&bond->curr_slave_lock); | ||
2437 | 2432 | ||
2438 | bond_select_active_slave(bond); | 2433 | if (slave_state_changed) { |
2434 | bond_slave_state_change(bond); | ||
2435 | } else if (do_failover) { | ||
2436 | /* the bond_select_active_slave must hold RTNL | ||
2437 | * and curr_slave_lock for write. | ||
2438 | */ | ||
2439 | block_netpoll_tx(); | ||
2440 | write_lock_bh(&bond->curr_slave_lock); | ||
2439 | 2441 | ||
2440 | write_unlock_bh(&bond->curr_slave_lock); | 2442 | bond_select_active_slave(bond); |
2441 | unblock_netpoll_tx(); | 2443 | |
2444 | write_unlock_bh(&bond->curr_slave_lock); | ||
2445 | unblock_netpoll_tx(); | ||
2446 | } | ||
2442 | rtnl_unlock(); | 2447 | rtnl_unlock(); |
2443 | } | 2448 | } |
2444 | 2449 | ||
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 1a9062f4e0d6..86ccfb9f71cc 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h | |||
@@ -303,6 +303,19 @@ static inline void bond_set_backup_slave(struct slave *slave) | |||
303 | } | 303 | } |
304 | } | 304 | } |
305 | 305 | ||
306 | static inline void bond_slave_state_change(struct bonding *bond) | ||
307 | { | ||
308 | struct list_head *iter; | ||
309 | struct slave *tmp; | ||
310 | |||
311 | bond_for_each_slave(bond, tmp, iter) { | ||
312 | if (tmp->link == BOND_LINK_UP) | ||
313 | bond_set_active_slave(tmp); | ||
314 | else if (tmp->link == BOND_LINK_DOWN) | ||
315 | bond_set_backup_slave(tmp); | ||
316 | } | ||
317 | } | ||
318 | |||
306 | static inline int bond_slave_state(struct slave *slave) | 319 | static inline int bond_slave_state(struct slave *slave) |
307 | { | 320 | { |
308 | return slave->backup; | 321 | return slave->backup; |