mirror of
https://github.com/torvalds/linux.git
synced 2024-11-24 13:11:40 +00:00
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 <davem@davemloft.net>
This commit is contained in:
commit
95ed0edd83
@ -2446,9 +2446,9 @@ void bond_3ad_adapter_speed_duplex_changed(struct slave *slave)
|
||||
|
||||
spin_lock_bh(&slave->bond->mode_lock);
|
||||
ad_update_actor_keys(port, false);
|
||||
spin_unlock_bh(&slave->bond->mode_lock);
|
||||
netdev_dbg(slave->bond->dev, "Port %d slave %s changed speed/duplex\n",
|
||||
port->actor_port_number, slave->dev->name);
|
||||
spin_unlock_bh(&slave->bond->mode_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2492,12 +2492,12 @@ void bond_3ad_handle_link_change(struct slave *slave, char link)
|
||||
agg = __get_first_agg(port);
|
||||
ad_agg_selection_logic(agg, &dummy);
|
||||
|
||||
spin_unlock_bh(&slave->bond->mode_lock);
|
||||
|
||||
netdev_dbg(slave->bond->dev, "Port %d changed link status to %s\n",
|
||||
port->actor_port_number,
|
||||
link == BOND_LINK_UP ? "UP" : "DOWN");
|
||||
|
||||
spin_unlock_bh(&slave->bond->mode_lock);
|
||||
|
||||
/* RTNL is held and mode_lock is released so it's safe
|
||||
* to update slave_array here.
|
||||
*/
|
||||
|
@ -365,9 +365,10 @@ down:
|
||||
/* Get link speed and duplex from the slave's base driver
|
||||
* using ethtool. If for some reason the call fails or the
|
||||
* values are invalid, set speed and duplex to -1,
|
||||
* and return.
|
||||
* and return. Return 1 if speed or duplex settings are
|
||||
* UNKNOWN; 0 otherwise.
|
||||
*/
|
||||
static void bond_update_speed_duplex(struct slave *slave)
|
||||
static int bond_update_speed_duplex(struct slave *slave)
|
||||
{
|
||||
struct net_device *slave_dev = slave->dev;
|
||||
struct ethtool_link_ksettings ecmd;
|
||||
@ -377,24 +378,27 @@ static void bond_update_speed_duplex(struct slave *slave)
|
||||
slave->duplex = DUPLEX_UNKNOWN;
|
||||
|
||||
res = __ethtool_get_link_ksettings(slave_dev, &ecmd);
|
||||
if (res < 0)
|
||||
return;
|
||||
|
||||
if (ecmd.base.speed == 0 || ecmd.base.speed == ((__u32)-1))
|
||||
return;
|
||||
|
||||
if (res < 0) {
|
||||
slave->link = BOND_LINK_DOWN;
|
||||
return 1;
|
||||
}
|
||||
if (ecmd.base.speed == 0 || ecmd.base.speed == ((__u32)-1)) {
|
||||
slave->link = BOND_LINK_DOWN;
|
||||
return 1;
|
||||
}
|
||||
switch (ecmd.base.duplex) {
|
||||
case DUPLEX_FULL:
|
||||
case DUPLEX_HALF:
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
slave->link = BOND_LINK_DOWN;
|
||||
return 1;
|
||||
}
|
||||
|
||||
slave->speed = ecmd.base.speed;
|
||||
slave->duplex = ecmd.base.duplex;
|
||||
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *bond_slave_link_status(s8 link)
|
||||
@ -2033,8 +2037,7 @@ static int bond_miimon_inspect(struct bonding *bond)
|
||||
if (link_state)
|
||||
continue;
|
||||
|
||||
bond_set_slave_link_state(slave, BOND_LINK_FAIL,
|
||||
BOND_SLAVE_NOTIFY_LATER);
|
||||
bond_propose_link_state(slave, BOND_LINK_FAIL);
|
||||
slave->delay = bond->params.downdelay;
|
||||
if (slave->delay) {
|
||||
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)
|
||||
case BOND_LINK_FAIL:
|
||||
if (link_state) {
|
||||
/* recovered before downdelay expired */
|
||||
bond_set_slave_link_state(slave, BOND_LINK_UP,
|
||||
BOND_SLAVE_NOTIFY_LATER);
|
||||
bond_propose_link_state(slave, BOND_LINK_UP);
|
||||
slave->last_link_up = jiffies;
|
||||
netdev_info(bond->dev, "link status up again after %d ms for interface %s\n",
|
||||
(bond->params.downdelay - slave->delay) *
|
||||
@ -2072,8 +2074,7 @@ static int bond_miimon_inspect(struct bonding *bond)
|
||||
if (!link_state)
|
||||
continue;
|
||||
|
||||
bond_set_slave_link_state(slave, BOND_LINK_BACK,
|
||||
BOND_SLAVE_NOTIFY_LATER);
|
||||
bond_propose_link_state(slave, BOND_LINK_BACK);
|
||||
slave->delay = bond->params.updelay;
|
||||
|
||||
if (slave->delay) {
|
||||
@ -2086,9 +2087,7 @@ static int bond_miimon_inspect(struct bonding *bond)
|
||||
/*FALLTHRU*/
|
||||
case BOND_LINK_BACK:
|
||||
if (!link_state) {
|
||||
bond_set_slave_link_state(slave,
|
||||
BOND_LINK_DOWN,
|
||||
BOND_SLAVE_NOTIFY_LATER);
|
||||
bond_propose_link_state(slave, BOND_LINK_DOWN);
|
||||
netdev_info(bond->dev, "link status down again after %d ms for interface %s\n",
|
||||
(bond->params.updelay - slave->delay) *
|
||||
bond->params.miimon,
|
||||
@ -2126,7 +2125,12 @@ static void bond_miimon_commit(struct bonding *bond)
|
||||
continue;
|
||||
|
||||
case BOND_LINK_UP:
|
||||
bond_update_speed_duplex(slave);
|
||||
if (bond_update_speed_duplex(slave)) {
|
||||
netdev_warn(bond->dev,
|
||||
"failed to get link speed/duplex for %s\n",
|
||||
slave->dev->name);
|
||||
continue;
|
||||
}
|
||||
bond_set_slave_link_state(slave, BOND_LINK_UP,
|
||||
BOND_SLAVE_NOTIFY_NOW);
|
||||
slave->last_link_up = jiffies;
|
||||
@ -2225,6 +2229,8 @@ static void bond_mii_monitor(struct work_struct *work)
|
||||
mii_work.work);
|
||||
bool should_notify_peers = false;
|
||||
unsigned long delay;
|
||||
struct slave *slave;
|
||||
struct list_head *iter;
|
||||
|
||||
delay = msecs_to_jiffies(bond->params.miimon);
|
||||
|
||||
@ -2245,6 +2251,9 @@ static void bond_mii_monitor(struct work_struct *work)
|
||||
goto re_arm;
|
||||
}
|
||||
|
||||
bond_for_each_slave(bond, slave, iter) {
|
||||
bond_commit_link_state(slave, BOND_SLAVE_NOTIFY_LATER);
|
||||
}
|
||||
bond_miimon_commit(bond);
|
||||
|
||||
rtnl_unlock(); /* might sleep, hold no other locks */
|
||||
|
@ -153,7 +153,8 @@ struct slave {
|
||||
unsigned long last_link_up;
|
||||
unsigned long last_rx;
|
||||
unsigned long target_last_arp_rx[BOND_MAX_ARP_TARGETS];
|
||||
s8 link; /* one of BOND_LINK_XXXX */
|
||||
s8 link; /* one of BOND_LINK_XXXX */
|
||||
s8 link_new_state; /* one of BOND_LINK_XXXX */
|
||||
s8 new_link;
|
||||
u8 backup:1, /* indicates backup slave. Value corresponds with
|
||||
BOND_STATE_ACTIVE and BOND_STATE_BACKUP */
|
||||
@ -504,13 +505,17 @@ static inline bool bond_is_slave_inactive(struct slave *slave)
|
||||
return slave->inactive;
|
||||
}
|
||||
|
||||
static inline void bond_set_slave_link_state(struct slave *slave, int state,
|
||||
bool notify)
|
||||
static inline void bond_propose_link_state(struct slave *slave, int state)
|
||||
{
|
||||
if (slave->link == state)
|
||||
slave->link_new_state = state;
|
||||
}
|
||||
|
||||
static inline void bond_commit_link_state(struct slave *slave, bool notify)
|
||||
{
|
||||
if (slave->link == slave->link_new_state)
|
||||
return;
|
||||
|
||||
slave->link = state;
|
||||
slave->link = slave->link_new_state;
|
||||
if (notify) {
|
||||
bond_queue_slave_event(slave);
|
||||
bond_lower_state_changed(slave);
|
||||
@ -523,6 +528,13 @@ static inline void bond_set_slave_link_state(struct slave *slave, int state,
|
||||
}
|
||||
}
|
||||
|
||||
static inline void bond_set_slave_link_state(struct slave *slave, int state,
|
||||
bool notify)
|
||||
{
|
||||
bond_propose_link_state(slave, state);
|
||||
bond_commit_link_state(slave, notify);
|
||||
}
|
||||
|
||||
static inline void bond_slave_link_notify(struct bonding *bond)
|
||||
{
|
||||
struct list_head *iter;
|
||||
|
Loading…
Reference in New Issue
Block a user