Merge tag 'linux-kselftest-5.9-rc5' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-2.6-microblaze.git] / drivers / net / bonding / bond_main.c
index 5ad43aa..42ef25e 100644 (file)
@@ -322,6 +322,7 @@ netdev_tx_t bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb,
 /**
  * bond_vlan_rx_add_vid - Propagates adding an id to slaves
  * @bond_dev: bonding net device that got called
+ * @proto: network protocol ID
  * @vid: vlan id being added
  */
 static int bond_vlan_rx_add_vid(struct net_device *bond_dev,
@@ -355,6 +356,7 @@ unwind:
 /**
  * bond_vlan_rx_kill_vid - Propagates deleting an id to slaves
  * @bond_dev: bonding net device that got called
+ * @proto: network protocol ID
  * @vid: vlan id being removed
  */
 static int bond_vlan_rx_kill_vid(struct net_device *bond_dev,
@@ -948,7 +950,7 @@ static bool bond_should_notify_peers(struct bonding *bond)
 /**
  * change_active_interface - change the active slave into the specified one
  * @bond: our bonding struct
- * @new: the new slave to make the active one
+ * @new_active: the new slave to make the active one
  *
  * Set the new slave to the bond's settings and unset them on the old
  * curr_active_slave.
@@ -2205,7 +2207,8 @@ static int bond_release_and_destroy(struct net_device *bond_dev,
        int ret;
 
        ret = __bond_release_one(bond_dev, slave_dev, false, true);
-       if (ret == 0 && !bond_has_slaves(bond)) {
+       if (ret == 0 && !bond_has_slaves(bond) &&
+           bond_dev->reg_state != NETREG_UNREGISTERING) {
                bond_dev->priv_flags |= IFF_DISABLE_NETPOLL;
                netdev_info(bond_dev, "Destroying bond\n");
                bond_remove_proc_entry(bond);
@@ -2271,7 +2274,7 @@ static int bond_miimon_inspect(struct bonding *bond)
                                             "active " : "backup ") : "",
                                           bond->params.downdelay * bond->params.miimon);
                        }
-                       /*FALLTHRU*/
+                       fallthrough;
                case BOND_LINK_FAIL:
                        if (link_state) {
                                /* recovered before downdelay expired */
@@ -2307,7 +2310,7 @@ static int bond_miimon_inspect(struct bonding *bond)
                                           bond->params.updelay *
                                           bond->params.miimon);
                        }
-                       /*FALLTHRU*/
+                       fallthrough;
                case BOND_LINK_BACK:
                        if (!link_state) {
                                bond_propose_link_state(slave, BOND_LINK_DOWN);
@@ -2945,6 +2948,9 @@ static int bond_ab_arp_inspect(struct bonding *bond)
                        if (bond_time_in_interval(bond, last_rx, 1)) {
                                bond_propose_link_state(slave, BOND_LINK_UP);
                                commit++;
+                       } else if (slave->link == BOND_LINK_BACK) {
+                               bond_propose_link_state(slave, BOND_LINK_FAIL);
+                               commit++;
                        }
                        continue;
                }
@@ -3053,6 +3059,19 @@ static void bond_ab_arp_commit(struct bonding *bond)
 
                        continue;
 
+               case BOND_LINK_FAIL:
+                       bond_set_slave_link_state(slave, BOND_LINK_FAIL,
+                                                 BOND_SLAVE_NOTIFY_NOW);
+                       bond_set_slave_inactive_flags(slave,
+                                                     BOND_SLAVE_NOTIFY_NOW);
+
+                       /* A slave has just been enslaved and has become
+                        * the current active slave.
+                        */
+                       if (rtnl_dereference(bond->curr_active_slave))
+                               RCU_INIT_POINTER(bond->current_arp_slave, NULL);
+                       continue;
+
                default:
                        slave_err(bond->dev, slave->dev,
                                  "impossible: link_new_state %d on slave\n",
@@ -3103,8 +3122,6 @@ static bool bond_ab_arp_probe(struct bonding *bond)
                        return should_notify_rtnl;
        }
 
-       bond_set_slave_inactive_flags(curr_arp_slave, BOND_SLAVE_NOTIFY_LATER);
-
        bond_for_each_slave_rcu(bond, slave, iter) {
                if (!found && !before && bond_slave_is_up(slave))
                        before = slave;
@@ -3305,7 +3322,7 @@ static int bond_slave_netdev_event(unsigned long event,
 
                if (BOND_MODE(bond) == BOND_MODE_8023AD)
                        bond_3ad_adapter_speed_duplex_changed(slave);
-               /* Fallthrough */
+               fallthrough;
        case NETDEV_DOWN:
                /* Refresh slave-array if applicable!
                 * If the setup does not use miimon or arpmon (mode-specific!),
@@ -3743,7 +3760,7 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd
                        return -EINVAL;
 
                mii->phy_id = 0;
-               /* Fall Through */
+               fallthrough;
        case SIOCGMIIREG:
                /* We do this again just in case we were called by SIOCGMIIREG
                 * instead of SIOCGMIIPHY.
@@ -4552,13 +4569,23 @@ static netdev_tx_t bond_start_xmit(struct sk_buff *skb, struct net_device *dev)
        return ret;
 }
 
+static u32 bond_mode_bcast_speed(struct slave *slave, u32 speed)
+{
+       if (speed == 0 || speed == SPEED_UNKNOWN)
+               speed = slave->speed;
+       else
+               speed = min(speed, slave->speed);
+
+       return speed;
+}
+
 static int bond_ethtool_get_link_ksettings(struct net_device *bond_dev,
                                           struct ethtool_link_ksettings *cmd)
 {
        struct bonding *bond = netdev_priv(bond_dev);
-       unsigned long speed = 0;
        struct list_head *iter;
        struct slave *slave;
+       u32 speed = 0;
 
        cmd->base.duplex = DUPLEX_UNKNOWN;
        cmd->base.port = PORT_OTHER;
@@ -4570,8 +4597,13 @@ static int bond_ethtool_get_link_ksettings(struct net_device *bond_dev,
         */
        bond_for_each_slave(bond, slave, iter) {
                if (bond_slave_can_tx(slave)) {
-                       if (slave->speed != SPEED_UNKNOWN)
-                               speed += slave->speed;
+                       if (slave->speed != SPEED_UNKNOWN) {
+                               if (BOND_MODE(bond) == BOND_MODE_BROADCAST)
+                                       speed = bond_mode_bcast_speed(slave,
+                                                                     speed);
+                               else
+                                       speed += slave->speed;
+                       }
                        if (cmd->base.duplex == DUPLEX_UNKNOWN &&
                            slave->duplex != DUPLEX_UNKNOWN)
                                cmd->base.duplex = slave->duplex;