Skip to content

Commit 95ed0ed

Browse files
committed
Merge branch 'bond-link-status-fixes'
Mahesh Bandewar says: ==================== link-status fixes for mii-monitoring The mii monitoring is divided into two phases - inspect and commit. The inspect phase technically should not make any changes to the state and defer it to the commit phase. However detected link state inconsistencies on several machines and discovered that it's the result of some inconsistent update to link states and assumption that you *always* get rtnl-mutex. In reality when trylock() fails to acquire rtnl-mutex, the commit phase is postponed until next mii-mon run. At the next round because of the state change performed in the previous inspect-run, this round does not detect any changes and would skip calling commit phase. This would result in an inconsistent state until next link event happens (if it ever happens). During the the commit phase, it's always assumed that speed and duplex fetch is always successful, but that's always not the case. However the slave state is marked UP irrespective of speed / duplex fetch operation. If the speed / duplex fetch operation results in insane values for either of these two fields, then keeping internal link state UP is not going to provide fruitful results either. Please see into individual patches for more details. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 205ed44 + e292dca commit 95ed0ed

File tree

3 files changed

+49
-28
lines changed

3 files changed

+49
-28
lines changed

drivers/net/bonding/bond_3ad.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2446,9 +2446,9 @@ void bond_3ad_adapter_speed_duplex_changed(struct slave *slave)
24462446

24472447
spin_lock_bh(&slave->bond->mode_lock);
24482448
ad_update_actor_keys(port, false);
2449+
spin_unlock_bh(&slave->bond->mode_lock);
24492450
netdev_dbg(slave->bond->dev, "Port %d slave %s changed speed/duplex\n",
24502451
port->actor_port_number, slave->dev->name);
2451-
spin_unlock_bh(&slave->bond->mode_lock);
24522452
}
24532453

24542454
/**
@@ -2492,12 +2492,12 @@ void bond_3ad_handle_link_change(struct slave *slave, char link)
24922492
agg = __get_first_agg(port);
24932493
ad_agg_selection_logic(agg, &dummy);
24942494

2495+
spin_unlock_bh(&slave->bond->mode_lock);
2496+
24952497
netdev_dbg(slave->bond->dev, "Port %d changed link status to %s\n",
24962498
port->actor_port_number,
24972499
link == BOND_LINK_UP ? "UP" : "DOWN");
24982500

2499-
spin_unlock_bh(&slave->bond->mode_lock);
2500-
25012501
/* RTNL is held and mode_lock is released so it's safe
25022502
* to update slave_array here.
25032503
*/

drivers/net/bonding/bond_main.c

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -365,9 +365,10 @@ int bond_set_carrier(struct bonding *bond)
365365
/* Get link speed and duplex from the slave's base driver
366366
* using ethtool. If for some reason the call fails or the
367367
* values are invalid, set speed and duplex to -1,
368-
* and return.
368+
* and return. Return 1 if speed or duplex settings are
369+
* UNKNOWN; 0 otherwise.
369370
*/
370-
static void bond_update_speed_duplex(struct slave *slave)
371+
static int bond_update_speed_duplex(struct slave *slave)
371372
{
372373
struct net_device *slave_dev = slave->dev;
373374
struct ethtool_link_ksettings ecmd;
@@ -377,24 +378,27 @@ static void bond_update_speed_duplex(struct slave *slave)
377378
slave->duplex = DUPLEX_UNKNOWN;
378379

379380
res = __ethtool_get_link_ksettings(slave_dev, &ecmd);
380-
if (res < 0)
381-
return;
382-
383-
if (ecmd.base.speed == 0 || ecmd.base.speed == ((__u32)-1))
384-
return;
385-
381+
if (res < 0) {
382+
slave->link = BOND_LINK_DOWN;
383+
return 1;
384+
}
385+
if (ecmd.base.speed == 0 || ecmd.base.speed == ((__u32)-1)) {
386+
slave->link = BOND_LINK_DOWN;
387+
return 1;
388+
}
386389
switch (ecmd.base.duplex) {
387390
case DUPLEX_FULL:
388391
case DUPLEX_HALF:
389392
break;
390393
default:
391-
return;
394+
slave->link = BOND_LINK_DOWN;
395+
return 1;
392396
}
393397

394398
slave->speed = ecmd.base.speed;
395399
slave->duplex = ecmd.base.duplex;
396400

397-
return;
401+
return 0;
398402
}
399403

400404
const char *bond_slave_link_status(s8 link)
@@ -2033,8 +2037,7 @@ static int bond_miimon_inspect(struct bonding *bond)
20332037
if (link_state)
20342038
continue;
20352039

2036-
bond_set_slave_link_state(slave, BOND_LINK_FAIL,
2037-
BOND_SLAVE_NOTIFY_LATER);
2040+
bond_propose_link_state(slave, BOND_LINK_FAIL);
20382041
slave->delay = bond->params.downdelay;
20392042
if (slave->delay) {
20402043
netdev_info(bond->dev, "link status down for %sinterface %s, disabling it in %d ms\n",
@@ -2049,8 +2052,7 @@ static int bond_miimon_inspect(struct bonding *bond)
20492052
case BOND_LINK_FAIL:
20502053
if (link_state) {
20512054
/* recovered before downdelay expired */
2052-
bond_set_slave_link_state(slave, BOND_LINK_UP,
2053-
BOND_SLAVE_NOTIFY_LATER);
2055+
bond_propose_link_state(slave, BOND_LINK_UP);
20542056
slave->last_link_up = jiffies;
20552057
netdev_info(bond->dev, "link status up again after %d ms for interface %s\n",
20562058
(bond->params.downdelay - slave->delay) *
@@ -2072,8 +2074,7 @@ static int bond_miimon_inspect(struct bonding *bond)
20722074
if (!link_state)
20732075
continue;
20742076

2075-
bond_set_slave_link_state(slave, BOND_LINK_BACK,
2076-
BOND_SLAVE_NOTIFY_LATER);
2077+
bond_propose_link_state(slave, BOND_LINK_BACK);
20772078
slave->delay = bond->params.updelay;
20782079

20792080
if (slave->delay) {
@@ -2086,9 +2087,7 @@ static int bond_miimon_inspect(struct bonding *bond)
20862087
/*FALLTHRU*/
20872088
case BOND_LINK_BACK:
20882089
if (!link_state) {
2089-
bond_set_slave_link_state(slave,
2090-
BOND_LINK_DOWN,
2091-
BOND_SLAVE_NOTIFY_LATER);
2090+
bond_propose_link_state(slave, BOND_LINK_DOWN);
20922091
netdev_info(bond->dev, "link status down again after %d ms for interface %s\n",
20932092
(bond->params.updelay - slave->delay) *
20942093
bond->params.miimon,
@@ -2126,7 +2125,12 @@ static void bond_miimon_commit(struct bonding *bond)
21262125
continue;
21272126

21282127
case BOND_LINK_UP:
2129-
bond_update_speed_duplex(slave);
2128+
if (bond_update_speed_duplex(slave)) {
2129+
netdev_warn(bond->dev,
2130+
"failed to get link speed/duplex for %s\n",
2131+
slave->dev->name);
2132+
continue;
2133+
}
21302134
bond_set_slave_link_state(slave, BOND_LINK_UP,
21312135
BOND_SLAVE_NOTIFY_NOW);
21322136
slave->last_link_up = jiffies;
@@ -2225,6 +2229,8 @@ static void bond_mii_monitor(struct work_struct *work)
22252229
mii_work.work);
22262230
bool should_notify_peers = false;
22272231
unsigned long delay;
2232+
struct slave *slave;
2233+
struct list_head *iter;
22282234

22292235
delay = msecs_to_jiffies(bond->params.miimon);
22302236

@@ -2245,6 +2251,9 @@ static void bond_mii_monitor(struct work_struct *work)
22452251
goto re_arm;
22462252
}
22472253

2254+
bond_for_each_slave(bond, slave, iter) {
2255+
bond_commit_link_state(slave, BOND_SLAVE_NOTIFY_LATER);
2256+
}
22482257
bond_miimon_commit(bond);
22492258

22502259
rtnl_unlock(); /* might sleep, hold no other locks */

include/net/bonding.h

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,8 @@ struct slave {
153153
unsigned long last_link_up;
154154
unsigned long last_rx;
155155
unsigned long target_last_arp_rx[BOND_MAX_ARP_TARGETS];
156-
s8 link; /* one of BOND_LINK_XXXX */
156+
s8 link; /* one of BOND_LINK_XXXX */
157+
s8 link_new_state; /* one of BOND_LINK_XXXX */
157158
s8 new_link;
158159
u8 backup:1, /* indicates backup slave. Value corresponds with
159160
BOND_STATE_ACTIVE and BOND_STATE_BACKUP */
@@ -504,13 +505,17 @@ static inline bool bond_is_slave_inactive(struct slave *slave)
504505
return slave->inactive;
505506
}
506507

507-
static inline void bond_set_slave_link_state(struct slave *slave, int state,
508-
bool notify)
508+
static inline void bond_propose_link_state(struct slave *slave, int state)
509+
{
510+
slave->link_new_state = state;
511+
}
512+
513+
static inline void bond_commit_link_state(struct slave *slave, bool notify)
509514
{
510-
if (slave->link == state)
515+
if (slave->link == slave->link_new_state)
511516
return;
512517

513-
slave->link = state;
518+
slave->link = slave->link_new_state;
514519
if (notify) {
515520
bond_queue_slave_event(slave);
516521
bond_lower_state_changed(slave);
@@ -523,6 +528,13 @@ static inline void bond_set_slave_link_state(struct slave *slave, int state,
523528
}
524529
}
525530

531+
static inline void bond_set_slave_link_state(struct slave *slave, int state,
532+
bool notify)
533+
{
534+
bond_propose_link_state(slave, state);
535+
bond_commit_link_state(slave, notify);
536+
}
537+
526538
static inline void bond_slave_link_notify(struct bonding *bond)
527539
{
528540
struct list_head *iter;

0 commit comments

Comments
 (0)