Skip to content

Commit 9e1aa8a

Browse files
Nithin Sujirgregkh
authored andcommitted
bonding: Don't update slave->link until ready to commit
[ Upstream commit 797a936 ] In the loadbalance arp monitoring scheme, when a slave link change is detected, the slave->link is immediately updated and slave_state_changed is set. Later down the function, the rtnl_lock is acquired and the changes are committed, updating the bond link state. However, the acquisition of the rtnl_lock can fail. The next time the monitor runs, since slave->link is already updated, it determines that link is unchanged. This results in the bond link state permanently out of sync with the slave link. This patch modifies bond_loadbalance_arp_mon() to handle link changes identical to bond_ab_arp_{inspect/commit}(). The new link state is maintained in slave->new_link until we're ready to commit at which point it's copied into slave->link. NOTE: miimon_{inspect/commit}() has a more complex state machine requiring the use of the bond_{propose,commit}_link_state() functions which maintains the intermediate state in slave->link_new_state. The arp monitors don't require that. Testing: This bug is very easy to reproduce with the following steps. 1. In a loop, toggle a slave link of a bond slave interface. 2. In a separate loop, do ifconfig up/down of an unrelated interface to create contention for rtnl_lock. Within a few iterations, the bond link goes out of sync with the slave link. Signed-off-by: Nithin Nayak Sujir <[email protected]> Cc: Mahesh Bandewar <[email protected]> Cc: Jay Vosburgh <[email protected]> Acked-by: Mahesh Bandewar <[email protected]> Signed-off-by: David S. Miller <[email protected]> Signed-off-by: Sasha Levin <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 12e0201 commit 9e1aa8a

File tree

1 file changed

+9
-2
lines changed

1 file changed

+9
-2
lines changed

drivers/net/bonding/bond_main.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2555,11 +2555,13 @@ static void bond_loadbalance_arp_mon(struct work_struct *work)
25552555
bond_for_each_slave_rcu(bond, slave, iter) {
25562556
unsigned long trans_start = dev_trans_start(slave->dev);
25572557

2558+
slave->new_link = BOND_LINK_NOCHANGE;
2559+
25582560
if (slave->link != BOND_LINK_UP) {
25592561
if (bond_time_in_interval(bond, trans_start, 1) &&
25602562
bond_time_in_interval(bond, slave->last_rx, 1)) {
25612563

2562-
slave->link = BOND_LINK_UP;
2564+
slave->new_link = BOND_LINK_UP;
25632565
slave_state_changed = 1;
25642566

25652567
/* primary_slave has no meaning in round-robin
@@ -2586,7 +2588,7 @@ static void bond_loadbalance_arp_mon(struct work_struct *work)
25862588
if (!bond_time_in_interval(bond, trans_start, 2) ||
25872589
!bond_time_in_interval(bond, slave->last_rx, 2)) {
25882590

2589-
slave->link = BOND_LINK_DOWN;
2591+
slave->new_link = BOND_LINK_DOWN;
25902592
slave_state_changed = 1;
25912593

25922594
if (slave->link_failure_count < UINT_MAX)
@@ -2617,6 +2619,11 @@ static void bond_loadbalance_arp_mon(struct work_struct *work)
26172619
if (!rtnl_trylock())
26182620
goto re_arm;
26192621

2622+
bond_for_each_slave(bond, slave, iter) {
2623+
if (slave->new_link != BOND_LINK_NOCHANGE)
2624+
slave->link = slave->new_link;
2625+
}
2626+
26202627
if (slave_state_changed) {
26212628
bond_slave_state_change(bond);
26222629
if (BOND_MODE(bond) == BOND_MODE_XOR)

0 commit comments

Comments
 (0)