+++ /dev/null
-From foo@baz Sun 10 Nov 2019 06:21:03 PM CET
-From: Jay Vosburgh <jay.vosburgh@canonical.com>
-Date: Fri, 1 Nov 2019 21:56:42 -0700
-Subject: bonding: fix state transition issue in link monitoring
-
-From: Jay Vosburgh <jay.vosburgh@canonical.com>
-
-[ Upstream commit 1899bb325149e481de31a4f32b59ea6f24e176ea ]
-
-Since de77ecd4ef02 ("bonding: improve link-status update in
-mii-monitoring"), the bonding driver has utilized two separate variables
-to indicate the next link state a particular slave should transition to.
-Each is used to communicate to a different portion of the link state
-change commit logic; one to the bond_miimon_commit function itself, and
-another to the state transition logic.
-
- Unfortunately, the two variables can become unsynchronized,
-resulting in incorrect link state transitions within bonding. This can
-cause slaves to become stuck in an incorrect link state until a
-subsequent carrier state transition.
-
- The issue occurs when a special case in bond_slave_netdev_event
-sets slave->link directly to BOND_LINK_FAIL. On the next pass through
-bond_miimon_inspect after the slave goes carrier up, the BOND_LINK_FAIL
-case will set the proposed next state (link_new_state) to BOND_LINK_UP,
-but the new_link to BOND_LINK_DOWN. The setting of the final link state
-from new_link comes after that from link_new_state, and so the slave
-will end up incorrectly in _DOWN state.
-
- Resolve this by combining the two variables into one.
-
-Reported-by: Aleksei Zakharov <zakharov.a.g@yandex.ru>
-Reported-by: Sha Zhang <zhangsha.zhang@huawei.com>
-Cc: Mahesh Bandewar <maheshb@google.com>
-Fixes: de77ecd4ef02 ("bonding: improve link-status update in mii-monitoring")
-Signed-off-by: Jay Vosburgh <jay.vosburgh@canonical.com>
-Signed-off-by: David S. Miller <davem@davemloft.net>
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
----
- drivers/net/bonding/bond_main.c | 40 ++++++++++++++++++++--------------------
- include/net/bonding.h | 1 -
- 2 files changed, 20 insertions(+), 21 deletions(-)
-
---- a/drivers/net/bonding/bond_main.c
-+++ b/drivers/net/bonding/bond_main.c
-@@ -2031,7 +2031,7 @@ static int bond_miimon_inspect(struct bo
- ignore_updelay = !rcu_dereference(bond->curr_active_slave);
-
- bond_for_each_slave_rcu(bond, slave, iter) {
-- slave->new_link = BOND_LINK_NOCHANGE;
-+ bond_propose_link_state(slave, BOND_LINK_NOCHANGE);
-
- link_state = bond_check_dev_link(bond, slave->dev, 0);
-
-@@ -2068,7 +2068,7 @@ static int bond_miimon_inspect(struct bo
- }
-
- if (slave->delay <= 0) {
-- slave->new_link = BOND_LINK_DOWN;
-+ bond_propose_link_state(slave, BOND_LINK_DOWN);
- commit++;
- continue;
- }
-@@ -2109,7 +2109,7 @@ static int bond_miimon_inspect(struct bo
- slave->delay = 0;
-
- if (slave->delay <= 0) {
-- slave->new_link = BOND_LINK_UP;
-+ bond_propose_link_state(slave, BOND_LINK_UP);
- commit++;
- ignore_updelay = false;
- continue;
-@@ -2129,7 +2129,7 @@ static void bond_miimon_commit(struct bo
- struct slave *slave, *primary;
-
- bond_for_each_slave(bond, slave, iter) {
-- switch (slave->new_link) {
-+ switch (slave->link_new_state) {
- case BOND_LINK_NOCHANGE:
- /* For 802.3ad mode, check current slave speed and
- * duplex again in case its port was disabled after
-@@ -2222,8 +2222,8 @@ static void bond_miimon_commit(struct bo
-
- default:
- netdev_err(bond->dev, "invalid new link %d on slave %s\n",
-- slave->new_link, slave->dev->name);
-- slave->new_link = BOND_LINK_NOCHANGE;
-+ slave->link_new_state, slave->dev->name);
-+ bond_propose_link_state(slave, BOND_LINK_NOCHANGE);
-
- continue;
- }
-@@ -2618,13 +2618,13 @@ static void bond_loadbalance_arp_mon(str
- bond_for_each_slave_rcu(bond, slave, iter) {
- unsigned long trans_start = dev_trans_start(slave->dev);
-
-- slave->new_link = BOND_LINK_NOCHANGE;
-+ bond_propose_link_state(slave, BOND_LINK_NOCHANGE);
-
- if (slave->link != BOND_LINK_UP) {
- if (bond_time_in_interval(bond, trans_start, 1) &&
- bond_time_in_interval(bond, slave->last_rx, 1)) {
-
-- slave->new_link = BOND_LINK_UP;
-+ bond_propose_link_state(slave, BOND_LINK_UP);
- slave_state_changed = 1;
-
- /* primary_slave has no meaning in round-robin
-@@ -2651,7 +2651,7 @@ static void bond_loadbalance_arp_mon(str
- if (!bond_time_in_interval(bond, trans_start, 2) ||
- !bond_time_in_interval(bond, slave->last_rx, 2)) {
-
-- slave->new_link = BOND_LINK_DOWN;
-+ bond_propose_link_state(slave, BOND_LINK_DOWN);
- slave_state_changed = 1;
-
- if (slave->link_failure_count < UINT_MAX)
-@@ -2683,8 +2683,8 @@ static void bond_loadbalance_arp_mon(str
- goto re_arm;
-
- bond_for_each_slave(bond, slave, iter) {
-- if (slave->new_link != BOND_LINK_NOCHANGE)
-- slave->link = slave->new_link;
-+ if (slave->link_new_state != BOND_LINK_NOCHANGE)
-+ slave->link = slave->link_new_state;
- }
-
- if (slave_state_changed) {
-@@ -2707,9 +2707,9 @@ re_arm:
- }
-
- /* Called to inspect slaves for active-backup mode ARP monitor link state
-- * changes. Sets new_link in slaves to specify what action should take
-- * place for the slave. Returns 0 if no changes are found, >0 if changes
-- * to link states must be committed.
-+ * changes. Sets proposed link state in slaves to specify what action
-+ * should take place for the slave. Returns 0 if no changes are found, >0
-+ * if changes to link states must be committed.
- *
- * Called with rcu_read_lock held.
- */
-@@ -2721,12 +2721,12 @@ static int bond_ab_arp_inspect(struct bo
- int commit = 0;
-
- bond_for_each_slave_rcu(bond, slave, iter) {
-- slave->new_link = BOND_LINK_NOCHANGE;
-+ bond_propose_link_state(slave, BOND_LINK_NOCHANGE);
- last_rx = slave_last_rx(bond, slave);
-
- if (slave->link != BOND_LINK_UP) {
- if (bond_time_in_interval(bond, last_rx, 1)) {
-- slave->new_link = BOND_LINK_UP;
-+ bond_propose_link_state(slave, BOND_LINK_UP);
- commit++;
- }
- continue;
-@@ -2754,7 +2754,7 @@ static int bond_ab_arp_inspect(struct bo
- if (!bond_is_active_slave(slave) &&
- !rcu_access_pointer(bond->current_arp_slave) &&
- !bond_time_in_interval(bond, last_rx, 3)) {
-- slave->new_link = BOND_LINK_DOWN;
-+ bond_propose_link_state(slave, BOND_LINK_DOWN);
- commit++;
- }
-
-@@ -2767,7 +2767,7 @@ static int bond_ab_arp_inspect(struct bo
- if (bond_is_active_slave(slave) &&
- (!bond_time_in_interval(bond, trans_start, 2) ||
- !bond_time_in_interval(bond, last_rx, 2))) {
-- slave->new_link = BOND_LINK_DOWN;
-+ bond_propose_link_state(slave, BOND_LINK_DOWN);
- commit++;
- }
- }
-@@ -2787,7 +2787,7 @@ static void bond_ab_arp_commit(struct bo
- struct slave *slave;
-
- bond_for_each_slave(bond, slave, iter) {
-- switch (slave->new_link) {
-+ switch (slave->link_new_state) {
- case BOND_LINK_NOCHANGE:
- continue;
-
-@@ -2840,7 +2840,7 @@ static void bond_ab_arp_commit(struct bo
-
- default:
- netdev_err(bond->dev, "impossible: new_link %d on slave %s\n",
-- slave->new_link, slave->dev->name);
-+ slave->link_new_state, slave->dev->name);
- continue;
- }
-
---- a/include/net/bonding.h
-+++ b/include/net/bonding.h
-@@ -148,7 +148,6 @@ struct slave {
- unsigned long last_rx;
- unsigned long target_last_arp_rx[BOND_MAX_ARP_TARGETS];
- s8 link; /* one of BOND_LINK_XXXX */
-- s8 new_link;
- u8 backup:1, /* indicates backup slave. Value corresponds with
- BOND_STATE_ACTIVE and BOND_STATE_BACKUP */
- inactive:1, /* indicates inactive slave */