summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/net/bonding/bond_3ad.c6
-rw-r--r--drivers/net/bonding/bond_main.c49
-rw-r--r--include/net/bonding.h22
3 files changed, 49 insertions, 28 deletions
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index 508713b4e533..c5fd4259da33 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -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.
*/
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index ba934020dfaa..6cea964ab70a 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -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 */
diff --git a/include/net/bonding.h b/include/net/bonding.h
index 3c857778a6ca..fb2dd97857c4 100644
--- a/include/net/bonding.h
+++ b/include/net/bonding.h
@@ -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)
+{
+ slave->link_new_state = state;
+}
+
+static inline void bond_commit_link_state(struct slave *slave, bool notify)
{
- if (slave->link == state)
+ 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;