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
2083 ignore_updelay = !rcu_dereference(bond->curr_active_slave);2083 ignore_updelay = !rcu_dereference(bond->curr_active_slave);
2084 2084
2085 bond_for_each_slave_rcu(bond, slave, iter) {2085 bond_for_each_slave_rcu(bond, slave, iter) {
2086 slave->new_link = BOND_LINK_NOCHANGE;2086 bond_propose_link_state(slave, BOND_LINK_NOCHANGE);
2087 slave->link_new_state = slave->link;
2088 2087
2089 link_state = bond_check_dev_link(bond, slave->dev, 0);2088 link_state = bond_check_dev_link(bond, slave->dev, 0);
2090 2089
@@ -2118,7 +2117,7 @@ static int bond_miimon_inspect(struct bonding *bond) · 27 unmodified lines
2118 }2117 }
2119 2118
2120 if (slave->delay <= 0) {2119 if (slave->delay <= 0) {
2121 slave->new_link = BOND_LINK_DOWN;2120 bond_propose_link_state(slave, BOND_LINK_DOWN);
2122 commit++;2121 commit++;
2123 continue;2122 continue;
2124 }2123 }
@@ -2155,7 +2154,7 @@ static int bond_miimon_inspect(struct bonding *bond) · 30 unmodified lines
2155 slave->delay = 0;2154 slave->delay = 0;
2156 2155
2157 if (slave->delay <= 0) {2156 if (slave->delay <= 0) {
2158 slave->new_link = BOND_LINK_UP;2157 bond_propose_link_state(slave, BOND_LINK_UP);
2159 commit++;2158 commit++;
2160 ignore_updelay = false;2159 ignore_updelay = false;
2161 continue;2160 continue;
@@ -2193,7 +2192,7 @@ static void bond_miimon_commit(struct bonding *bond) · 31 unmodified lines
2193 struct slave *slave, *primary;2192 struct slave *slave, *primary;
2194 2193
2195 bond_for_each_slave(bond, slave, iter) {2194 bond_for_each_slave(bond, slave, iter) {
2196 switch (slave->new_link) {2195 switch (slave->link_new_state) {
2197 case BOND_LINK_NOCHANGE:2196 case BOND_LINK_NOCHANGE:
2198 /* For 802.3ad mode, check current slave speed and2197 /* For 802.3ad mode, check current slave speed and
2199 * duplex again in case its port was disabled after2198 * duplex again in case its port was disabled after
@@ -2265,8 +2264,8 @@ static void bond_miimon_commit(struct bonding *bond) · 65 unmodified lines
2265 2264
2266 default:2265 default:
2267 slave_err(bond->dev, slave->dev, "invalid new link %d on slave\n",2266 slave_err(bond->dev, slave->dev, "invalid new link %d on slave\n",
2268 slave->new_link);2267 slave->link_new_state);
2269 slave->new_link = BOND_LINK_NOCHANGE;2268 bond_propose_link_state(slave, BOND_LINK_NOCHANGE);
2270 2269
2271 continue;2270 continue;
2272 }2271 }
@@ -2674,13 +2673,13 @@ static void bond_loadbalance_arp_mon(struct bonding *bond) · 401 unmodified lines
2674 bond_for_each_slave_rcu(bond, slave, iter) {2673 bond_for_each_slave_rcu(bond, slave, iter) {
2675 unsigned long trans_start = dev_trans_start(slave->dev);2674 unsigned long trans_start = dev_trans_start(slave->dev);
2676 2675
2677 slave->new_link = BOND_LINK_NOCHANGE;2676 bond_propose_link_state(slave, BOND_LINK_NOCHANGE);
2678 2677
2679 if (slave->link != BOND_LINK_UP) {2678 if (slave->link != BOND_LINK_UP) {
2680 if (bond_time_in_interval(bond, trans_start, 1) &&2679 if (bond_time_in_interval(bond, trans_start, 1) &&
2681 bond_time_in_interval(bond, slave->last_rx, 1)) {2680 bond_time_in_interval(bond, slave->last_rx, 1)) {
2682 2681
2683 slave->new_link = BOND_LINK_UP;2682 bond_propose_link_state(slave, BOND_LINK_UP);
2684 slave_state_changed = 1;2683 slave_state_changed = 1;
2685 2684
2686 /* primary_slave has no meaning in round-robin2685 /* primary_slave has no meaning in round-robin
@@ -2705,7 +2704,7 @@ static void bond_loadbalance_arp_mon(struct bonding *bond) · 18 unmodified lines
2705 if (!bond_time_in_interval(bond, trans_start, 2) ||2704 if (!bond_time_in_interval(bond, trans_start, 2) ||
2706 !bond_time_in_interval(bond, slave->last_rx, 2)) {2705 !bond_time_in_interval(bond, slave->last_rx, 2)) {
2707 2706
2708 slave->new_link = BOND_LINK_DOWN;2707 bond_propose_link_state(slave, BOND_LINK_DOWN);
2709 slave_state_changed = 1;2708 slave_state_changed = 1;
2710 2709
2711 if (slave->link_failure_count < UINT_MAX)2710 if (slave->link_failure_count < UINT_MAX)
@@ -2736,8 +2735,8 @@ static void bond_loadbalance_arp_mon(struct bonding *bond) · 24 unmodified lines
2736 goto re_arm;2735 goto re_arm;
2737 2736
2738 bond_for_each_slave(bond, slave, iter) {2737 bond_for_each_slave(bond, slave, iter) {
2739 if (slave->new_link != BOND_LINK_NOCHANGE)2738 if (slave->link_new_state != BOND_LINK_NOCHANGE)
2740 slave->link = slave->new_link;2739 slave->link = slave->link_new_state;
2741 }2740 }
2742 2741
2743 if (slave_state_changed) {2742 if (slave_state_changed) {
@@ -2760,9 +2759,9 @@ re_arm: · 16 unmodified lines
2760}2759}
2761 2760
2762/* Called to inspect slaves for active-backup mode ARP monitor link state2761/* Called to inspect slaves for active-backup mode ARP monitor link state
2763 * changes. Sets new_link in slaves to specify what action should take2762 * changes. Sets proposed link state in slaves to specify what action
2764 * place for the slave. Returns 0 if no changes are found, >0 if changes2763 * should take place for the slave. Returns 0 if no changes are found, >0
2765 * to link states must be committed.2764 * if changes to link states must be committed.
2766 *2765 *
2767 * Called with rcu_read_lock held.2766 * Called with rcu_read_lock held.
2768 */2767 */
@@ -2774,12 +2773,12 @@ static int bond_ab_arp_inspect(struct bonding *bond) · 5 unmodified lines
2774 int commit = 0;2773 int commit = 0;
2775 2774
2776 bond_for_each_slave_rcu(bond, slave, iter) {2775 bond_for_each_slave_rcu(bond, slave, iter) {
2777 slave->new_link = BOND_LINK_NOCHANGE;2776 bond_propose_link_state(slave, BOND_LINK_NOCHANGE);
2778 last_rx = slave_last_rx(bond, slave);2777 last_rx = slave_last_rx(bond, slave);
2779 2778
2780 if (slave->link != BOND_LINK_UP) {2779 if (slave->link != BOND_LINK_UP) {
2781 if (bond_time_in_interval(bond, last_rx, 1)) {2780 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);
2783 commit++;2782 commit++;
2784 }2783 }
2785 continue;2784 continue;
@@ -2807,7 +2806,7 @@ static int bond_ab_arp_inspect(struct bonding *bond) · 21 unmodified lines
2807 if (!bond_is_active_slave(slave) &&2806 if (!bond_is_active_slave(slave) &&
2808 !rcu_access_pointer(bond->current_arp_slave) &&2807 !rcu_access_pointer(bond->current_arp_slave) &&
2809 !bond_time_in_interval(bond, last_rx, 3)) {2808 !bond_time_in_interval(bond, last_rx, 3)) {
2810 slave->new_link = BOND_LINK_DOWN;2809 bond_propose_link_state(slave, BOND_LINK_DOWN);
2811 commit++;2810 commit++;
2812 }2811 }
2813 2812
@@ -2820,7 +2819,7 @@ static int bond_ab_arp_inspect(struct bonding *bond) · 6 unmodified lines
2820 if (bond_is_active_slave(slave) &&2819 if (bond_is_active_slave(slave) &&
2821 (!bond_time_in_interval(bond, trans_start, 2) ||2820 (!bond_time_in_interval(bond, trans_start, 2) ||
2822 !bond_time_in_interval(bond, last_rx, 2))) {2821 !bond_time_in_interval(bond, last_rx, 2))) {
2823 slave->new_link = BOND_LINK_DOWN;2822 bond_propose_link_state(slave, BOND_LINK_DOWN);
2824 commit++;2823 commit++;
2825 }2824 }
2826 }2825 }
@@ -2840,7 +2839,7 @@ static void bond_ab_arp_commit(struct bonding *bond) · 13 unmodified lines
2840 struct slave *slave;2839 struct slave *slave;
2841 2840
2842 bond_for_each_slave(bond, slave, iter) {2841 bond_for_each_slave(bond, slave, iter) {
2843 switch (slave->new_link) {2842 switch (slave->link_new_state) {
2844 case BOND_LINK_NOCHANGE:2843 case BOND_LINK_NOCHANGE:
2845 continue;2844 continue;
2846 2845
@@ -2890,8 +2889,9 @@ static void bond_ab_arp_commit(struct bonding *bond) · 43 unmodified lines
2890 continue;2889 continue;
2891 2890
2892 default:2891 default:
2893 slave_err(bond->dev, slave->dev, "impossible: new_link %d on slave\n",2892 slave_err(bond->dev, slave->dev,
2894 slave->new_link);2893 "impossible: link_new_state %d on slave\n",
2894 slave->link_new_state);
2895 continue;2895 continue;
2896 }2896 }
2897 2897
include/net/bonding.h+1−2
@@ -159,7 +159,6 @@ struct slave { · 158 unmodified lines
159 unsigned long target_last_arp_rx[BOND_MAX_ARP_TARGETS];159 unsigned long target_last_arp_rx[BOND_MAX_ARP_TARGETS];
160 s8 link; /* one of BOND_LINK_XXXX */160 s8 link; /* one of BOND_LINK_XXXX */
161 s8 link_new_state; /* one of BOND_LINK_XXXX */161 s8 link_new_state; /* one of BOND_LINK_XXXX */
162 s8 new_link;
163 u8 backup:1, /* indicates backup slave. Value corresponds with162 u8 backup:1, /* indicates backup slave. Value corresponds with
164 BOND_STATE_ACTIVE and BOND_STATE_BACKUP */163 BOND_STATE_ACTIVE and BOND_STATE_BACKUP */
165 inactive:1, /* indicates inactive slave */164 inactive:1, /* indicates inactive slave */
@@ -549,7 +548,7 @@ static inline void bond_propose_link_state(struct slave *slave, int state) · 383 unmodified lines
549 548
550static inline void bond_commit_link_state(struct slave *slave, bool notify)549static inline void bond_commit_link_state(struct slave *slave, bool notify)
551{550{
552 if (slave->link == slave->link_new_state)551 if (slave->link_new_state == BOND_LINK_NOCHANGE)
553 return;552 return;
554 553
555 slave->link = slave->link_new_state;554 slave->link = slave->link_new_state;