|
@@ -365,9 +365,10 @@ down:
|
|
/* Get link speed and duplex from the slave's base driver
|
|
/* Get link speed and duplex from the slave's base driver
|
|
* using ethtool. If for some reason the call fails or the
|
|
* using ethtool. If for some reason the call fails or the
|
|
* values are invalid, set speed and duplex to -1,
|
|
* 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 net_device *slave_dev = slave->dev;
|
|
struct ethtool_link_ksettings ecmd;
|
|
struct ethtool_link_ksettings ecmd;
|
|
@@ -377,24 +378,27 @@ static void bond_update_speed_duplex(struct slave *slave)
|
|
slave->duplex = DUPLEX_UNKNOWN;
|
|
slave->duplex = DUPLEX_UNKNOWN;
|
|
|
|
|
|
res = __ethtool_get_link_ksettings(slave_dev, &ecmd);
|
|
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) {
|
|
switch (ecmd.base.duplex) {
|
|
case DUPLEX_FULL:
|
|
case DUPLEX_FULL:
|
|
case DUPLEX_HALF:
|
|
case DUPLEX_HALF:
|
|
break;
|
|
break;
|
|
default:
|
|
default:
|
|
- return;
|
|
|
|
|
|
+ slave->link = BOND_LINK_DOWN;
|
|
|
|
+ return 1;
|
|
}
|
|
}
|
|
|
|
|
|
slave->speed = ecmd.base.speed;
|
|
slave->speed = ecmd.base.speed;
|
|
slave->duplex = ecmd.base.duplex;
|
|
slave->duplex = ecmd.base.duplex;
|
|
|
|
|
|
- return;
|
|
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
|
|
|
|
const char *bond_slave_link_status(s8 link)
|
|
const char *bond_slave_link_status(s8 link)
|
|
@@ -2033,8 +2037,7 @@ static int bond_miimon_inspect(struct bonding *bond)
|
|
if (link_state)
|
|
if (link_state)
|
|
continue;
|
|
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;
|
|
slave->delay = bond->params.downdelay;
|
|
if (slave->delay) {
|
|
if (slave->delay) {
|
|
netdev_info(bond->dev, "link status down for %sinterface %s, disabling it in %d ms\n",
|
|
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:
|
|
case BOND_LINK_FAIL:
|
|
if (link_state) {
|
|
if (link_state) {
|
|
/* recovered before downdelay expired */
|
|
/* 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;
|
|
slave->last_link_up = jiffies;
|
|
netdev_info(bond->dev, "link status up again after %d ms for interface %s\n",
|
|
netdev_info(bond->dev, "link status up again after %d ms for interface %s\n",
|
|
(bond->params.downdelay - slave->delay) *
|
|
(bond->params.downdelay - slave->delay) *
|
|
@@ -2072,8 +2074,7 @@ static int bond_miimon_inspect(struct bonding *bond)
|
|
if (!link_state)
|
|
if (!link_state)
|
|
continue;
|
|
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;
|
|
slave->delay = bond->params.updelay;
|
|
|
|
|
|
if (slave->delay) {
|
|
if (slave->delay) {
|
|
@@ -2086,9 +2087,7 @@ static int bond_miimon_inspect(struct bonding *bond)
|
|
/*FALLTHRU*/
|
|
/*FALLTHRU*/
|
|
case BOND_LINK_BACK:
|
|
case BOND_LINK_BACK:
|
|
if (!link_state) {
|
|
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",
|
|
netdev_info(bond->dev, "link status down again after %d ms for interface %s\n",
|
|
(bond->params.updelay - slave->delay) *
|
|
(bond->params.updelay - slave->delay) *
|
|
bond->params.miimon,
|
|
bond->params.miimon,
|
|
@@ -2126,7 +2125,12 @@ static void bond_miimon_commit(struct bonding *bond)
|
|
continue;
|
|
continue;
|
|
|
|
|
|
case BOND_LINK_UP:
|
|
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_set_slave_link_state(slave, BOND_LINK_UP,
|
|
BOND_SLAVE_NOTIFY_NOW);
|
|
BOND_SLAVE_NOTIFY_NOW);
|
|
slave->last_link_up = jiffies;
|
|
slave->last_link_up = jiffies;
|
|
@@ -2225,6 +2229,8 @@ static void bond_mii_monitor(struct work_struct *work)
|
|
mii_work.work);
|
|
mii_work.work);
|
|
bool should_notify_peers = false;
|
|
bool should_notify_peers = false;
|
|
unsigned long delay;
|
|
unsigned long delay;
|
|
|
|
+ struct slave *slave;
|
|
|
|
+ struct list_head *iter;
|
|
|
|
|
|
delay = msecs_to_jiffies(bond->params.miimon);
|
|
delay = msecs_to_jiffies(bond->params.miimon);
|
|
|
|
|
|
@@ -2245,6 +2251,9 @@ static void bond_mii_monitor(struct work_struct *work)
|
|
goto re_arm;
|
|
goto re_arm;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ bond_for_each_slave(bond, slave, iter) {
|
|
|
|
+ bond_commit_link_state(slave, BOND_SLAVE_NOTIFY_LATER);
|
|
|
|
+ }
|
|
bond_miimon_commit(bond);
|
|
bond_miimon_commit(bond);
|
|
|
|
|
|
rtnl_unlock(); /* might sleep, hold no other locks */
|
|
rtnl_unlock(); /* might sleep, hold no other locks */
|