History

bonding: fix state transition issue in link monitoring

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.

Jay Vosburgh committed 7 years ago

Commit 1899bb31 parent 41de23e2 files · +23 −24Browse files

Unified · Split

2 files
  1. drivers/net/bonding/bond_main.c +22 −22
  2. include/net/bonding.h +1 −2
drivers/net/bonding/bond_main.c+22−22
@@ -2083,8 +2083,7 @@ static int bond_miimon_inspect(struct bonding *bond) · 2082 unmodified lines
20832083 ignore_updelay = !rcu_dereference(bond->curr_active_slave);
20842084
20852085 bond_for_each_slave_rcu(bond, slave, iter) {
2086− slave->new_link = BOND_LINK_NOCHANGE;
2087− slave->link_new_state = slave->link;
2086+ bond_propose_link_state(slave, BOND_LINK_NOCHANGE);
20882087
20892088 link_state = bond_check_dev_link(bond, slave->dev, 0);
20902089
@@ -2118,7 +2117,7 @@ static int bond_miimon_inspect(struct bonding *bond) · 27 unmodified lines
21182117 }
21192118
21202119 if (slave->delay <= 0) {
2121− slave->new_link = BOND_LINK_DOWN;
2120+ bond_propose_link_state(slave, BOND_LINK_DOWN);
21222121 commit++;
21232122 continue;
21242123 }
@@ -2155,7 +2154,7 @@ static int bond_miimon_inspect(struct bonding *bond) · 30 unmodified lines
21552154 slave->delay = 0;
21562155
21572156 if (slave->delay <= 0) {
2158− slave->new_link = BOND_LINK_UP;
2157+ bond_propose_link_state(slave, BOND_LINK_UP);
21592158 commit++;
21602159 ignore_updelay = false;
21612160 continue;
@@ -2193,7 +2192,7 @@ static void bond_miimon_commit(struct bonding *bond) · 31 unmodified lines
21932192 struct slave *slave, *primary;
21942193
21952194 bond_for_each_slave(bond, slave, iter) {
2196− switch (slave->new_link) {
2195+ switch (slave->link_new_state) {
21972196 case BOND_LINK_NOCHANGE:
21982197 /* For 802.3ad mode, check current slave speed and
21992198 * duplex again in case its port was disabled after
@@ -2265,8 +2264,8 @@ static void bond_miimon_commit(struct bonding *bond) · 65 unmodified lines
22652264
22662265 default:
22672266 slave_err(bond->dev, slave->dev, "invalid new link %d on slave\n",
2268− slave->new_link);
2269− slave->new_link = BOND_LINK_NOCHANGE;
2267+ slave->link_new_state);
2268+ bond_propose_link_state(slave, BOND_LINK_NOCHANGE);
22702269
22712270 continue;
22722271 }
@@ -2674,13 +2673,13 @@ static void bond_loadbalance_arp_mon(struct bonding *bond) · 401 unmodified lines
26742673 bond_for_each_slave_rcu(bond, slave, iter) {
26752674 unsigned long trans_start = dev_trans_start(slave->dev);
26762675
2677− slave->new_link = BOND_LINK_NOCHANGE;
2676+ bond_propose_link_state(slave, BOND_LINK_NOCHANGE);
26782677
26792678 if (slave->link != BOND_LINK_UP) {
26802679 if (bond_time_in_interval(bond, trans_start, 1) &&
26812680 bond_time_in_interval(bond, slave->last_rx, 1)) {
26822681
2683− slave->new_link = BOND_LINK_UP;
2682+ bond_propose_link_state(slave, BOND_LINK_UP);
26842683 slave_state_changed = 1;
26852684
26862685 /* primary_slave has no meaning in round-robin
@@ -2705,7 +2704,7 @@ static void bond_loadbalance_arp_mon(struct bonding *bond) · 18 unmodified lines
27052704 if (!bond_time_in_interval(bond, trans_start, 2) ||
27062705 !bond_time_in_interval(bond, slave->last_rx, 2)) {
27072706
2708− slave->new_link = BOND_LINK_DOWN;
2707+ bond_propose_link_state(slave, BOND_LINK_DOWN);
27092708 slave_state_changed = 1;
27102709
27112710 if (slave->link_failure_count < UINT_MAX)
@@ -2736,8 +2735,8 @@ static void bond_loadbalance_arp_mon(struct bonding *bond) · 24 unmodified lines
27362735 goto re_arm;
27372736
27382737 bond_for_each_slave(bond, slave, iter) {
2739− if (slave->new_link != BOND_LINK_NOCHANGE)
2740− slave->link = slave->new_link;
2738+ if (slave->link_new_state != BOND_LINK_NOCHANGE)
2739+ slave->link = slave->link_new_state;
27412740 }
27422741
27432742 if (slave_state_changed) {
@@ -2760,9 +2759,9 @@ re_arm: · 16 unmodified lines
27602759 }
27612760
27622761 /* Called to inspect slaves for active-backup mode ARP monitor link state
2763− * changes. Sets new_link in slaves to specify what action should take
2764− * place for the slave. Returns 0 if no changes are found, >0 if changes
2765− * to link states must be committed.
2762+ * changes. Sets proposed link state in slaves to specify what action
2763+ * should take place for the slave. Returns 0 if no changes are found, >0
2764+ * if changes to link states must be committed.
27662765 *
27672766 * Called with rcu_read_lock held.
27682767 */
@@ -2774,12 +2773,12 @@ static int bond_ab_arp_inspect(struct bonding *bond) · 5 unmodified lines
27742773 int commit = 0;
27752774
27762775 bond_for_each_slave_rcu(bond, slave, iter) {
2777− slave->new_link = BOND_LINK_NOCHANGE;
2776+ bond_propose_link_state(slave, BOND_LINK_NOCHANGE);
27782777 last_rx = slave_last_rx(bond, slave);
27792778
27802779 if (slave->link != BOND_LINK_UP) {
27812780 if (bond_time_in_interval(bond, last_rx, 1)) {
2782− slave->new_link = BOND_LINK_UP;
2781+ bond_propose_link_state(slave, BOND_LINK_UP);
27832782 commit++;
27842783 }
27852784 continue;
@@ -2807,7 +2806,7 @@ static int bond_ab_arp_inspect(struct bonding *bond) · 21 unmodified lines
28072806 if (!bond_is_active_slave(slave) &&
28082807 !rcu_access_pointer(bond->current_arp_slave) &&
28092808 !bond_time_in_interval(bond, last_rx, 3)) {
2810− slave->new_link = BOND_LINK_DOWN;
2809+ bond_propose_link_state(slave, BOND_LINK_DOWN);
28112810 commit++;
28122811 }
28132812
@@ -2820,7 +2819,7 @@ static int bond_ab_arp_inspect(struct bonding *bond) · 6 unmodified lines
28202819 if (bond_is_active_slave(slave) &&
28212820 (!bond_time_in_interval(bond, trans_start, 2) ||
28222821 !bond_time_in_interval(bond, last_rx, 2))) {
2823− slave->new_link = BOND_LINK_DOWN;
2822+ bond_propose_link_state(slave, BOND_LINK_DOWN);
28242823 commit++;
28252824 }
28262825 }
@@ -2840,7 +2839,7 @@ static void bond_ab_arp_commit(struct bonding *bond) · 13 unmodified lines
28402839 struct slave *slave;
28412840
28422841 bond_for_each_slave(bond, slave, iter) {
2843− switch (slave->new_link) {
2842+ switch (slave->link_new_state) {
28442843 case BOND_LINK_NOCHANGE:
28452844 continue;
28462845
@@ -2890,8 +2889,9 @@ static void bond_ab_arp_commit(struct bonding *bond) · 43 unmodified lines
28902889 continue;
28912890
28922891 default:
2893− slave_err(bond->dev, slave->dev, "impossible: new_link %d on slave\n",
2894− slave->new_link);
2892+ slave_err(bond->dev, slave->dev,
2893+ "impossible: link_new_state %d on slave\n",
2894+ slave->link_new_state);
28952895 continue;
28962896 }
28972897
include/net/bonding.h+1−2
@@ -159,7 +159,6 @@ struct slave { · 158 unmodified lines
159159 unsigned long target_last_arp_rx[BOND_MAX_ARP_TARGETS];
160160 s8 link; /* one of BOND_LINK_XXXX */
161161 s8 link_new_state; /* one of BOND_LINK_XXXX */
162− s8 new_link;
163162 u8 backup:1, /* indicates backup slave. Value corresponds with
164163 BOND_STATE_ACTIVE and BOND_STATE_BACKUP */
165164 inactive:1, /* indicates inactive slave */
@@ -549,7 +548,7 @@ static inline void bond_propose_link_state(struct slave *slave, int state) · 383 unmodified lines
549548
550549 static inline void bond_commit_link_state(struct slave *slave, bool notify)
551550 {
552− if (slave->link == slave->link_new_state)
551+ if (slave->link_new_state == BOND_LINK_NOCHANGE)
553552 return;
554553
555554 slave->link = slave->link_new_state;