diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 8212d406f3bc..a1c156c145b2 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -2779,6 +2779,27 @@ static void bond_miimon_link_change(struct bonding *bond, } } +static bool bond_miimon_slave_down(struct bonding *bond, + struct slave *slave) +{ + if (slave->link_failure_count < UINT_MAX) + slave->link_failure_count++; + + bond_set_slave_link_state(slave, BOND_LINK_DOWN, + BOND_SLAVE_NOTIFY_NOW); + + if (BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP || + BOND_MODE(bond) == BOND_MODE_8023AD) + bond_set_slave_inactive_flags(slave, + BOND_SLAVE_NOTIFY_NOW); + + slave_info(bond->dev, slave->dev, "link status definitely down, disabling slave\n"); + + bond_miimon_link_change(bond, slave, BOND_LINK_DOWN); + + return slave == rcu_access_pointer(bond->curr_active_slave); +} + static void bond_miimon_commit(struct bonding *bond) { struct slave *slave, *primary, *active; @@ -2807,10 +2828,22 @@ static void bond_miimon_commit(struct bonding *bond) err = bond_update_speed_duplex(slave); netdev_unlock_ops(slave->dev); if (err && bond_needs_speed_duplex(bond)) { - slave->link = BOND_LINK_DOWN; if (net_ratelimit()) slave_warn(bond->dev, slave->dev, "failed to get link speed/duplex\n"); + /* Coming from FAIL/UP, the slave may still be + * in use and may be curr_active_slave, so take + * it through the full down path. Coming from + * DOWN/BACK, it was never brought up, so just + * revert it to DOWN. + */ + if (slave->link == BOND_LINK_FAIL || + slave->link == BOND_LINK_UP) { + if (bond_miimon_slave_down(bond, slave)) + do_failover = true; + continue; + } + slave->link = BOND_LINK_DOWN; continue; } bond_set_slave_link_state(slave, BOND_LINK_UP, @@ -2839,28 +2872,13 @@ static void bond_miimon_commit(struct bonding *bond) continue; case BOND_LINK_DOWN: - if (slave->link_failure_count < UINT_MAX) - slave->link_failure_count++; - - bond_set_slave_link_state(slave, BOND_LINK_DOWN, - BOND_SLAVE_NOTIFY_NOW); - - if (BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP || - BOND_MODE(bond) == BOND_MODE_8023AD) - bond_set_slave_inactive_flags(slave, - BOND_SLAVE_NOTIFY_NOW); - - slave_info(bond->dev, slave->dev, "link status definitely down, disabling slave\n"); - - bond_miimon_link_change(bond, slave, BOND_LINK_DOWN); - - if (slave == rcu_access_pointer(bond->curr_active_slave)) + if (bond_miimon_slave_down(bond, slave)) do_failover = true; - continue; case BOND_LINK_FAIL: case BOND_LINK_BACK: + bond_commit_link_state(slave, BOND_SLAVE_NOTIFY_LATER); slave_dbg(bond->dev, slave->dev, "link_new_state %d on slave\n", slave->link_new_state); continue; @@ -2894,8 +2912,6 @@ static void bond_mii_monitor(struct work_struct *work) { struct bonding *bond = container_of(work, struct bonding, mii_work.work); - struct list_head *iter; - struct slave *slave; unsigned long delay; bool commit; @@ -2917,13 +2933,8 @@ static void bond_mii_monitor(struct work_struct *work) goto re_arm; } - if (commit) { - bond_for_each_slave(bond, slave, iter) { - bond_commit_link_state(slave, - BOND_SLAVE_NOTIFY_LATER); - } + if (commit) bond_miimon_commit(bond); - } if (bond->send_peer_notif) bond_peer_notify_may_events(bond, true);