]> Pileus Git - ~andy/linux/blobdiff - drivers/net/bonding/bond_main.c
bonding: add bond_time_in_interval() and use it for time comparison
[~andy/linux] / drivers / net / bonding / bond_main.c
index 07f257d44a1e00a67b84a58685c5a2e490ce5ca8..d58237b3dd98d4c45d2f4b08796a6a3dfb24eb67 100644 (file)
@@ -77,6 +77,7 @@
 #include <net/net_namespace.h>
 #include <net/netns/generic.h>
 #include <net/pkt_sched.h>
+#include <linux/rculist.h>
 #include "bonding.h"
 #include "bond_3ad.h"
 #include "bond_alb.h"
@@ -106,7 +107,7 @@ static char *arp_ip_target[BOND_MAX_ARP_TARGETS];
 static char *arp_validate;
 static char *arp_all_targets;
 static char *fail_over_mac;
-static int all_slaves_active = 0;
+static int all_slaves_active;
 static struct bond_params bonding_defaults;
 static int resend_igmp = BOND_DEFAULT_RESEND_IGMP;
 
@@ -273,7 +274,7 @@ const char *bond_mode_name(int mode)
                [BOND_MODE_ALB] = "adaptive load balancing",
        };
 
-       if (mode < 0 || mode > BOND_MODE_ALB)
+       if (mode < BOND_MODE_ROUNDROBIN || mode > BOND_MODE_ALB)
                return "unknown";
 
        return names[mode];
@@ -441,10 +442,10 @@ static int bond_vlan_rx_add_vid(struct net_device *bond_dev,
                                __be16 proto, u16 vid)
 {
        struct bonding *bond = netdev_priv(bond_dev);
-       struct slave *slave, *stop_at;
-       int i, res;
+       struct slave *slave;
+       int res;
 
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                res = vlan_vid_add(slave->dev, proto, vid);
                if (res)
                        goto unwind;
@@ -461,8 +462,7 @@ static int bond_vlan_rx_add_vid(struct net_device *bond_dev,
 
 unwind:
        /* unwind from head to the slave that failed */
-       stop_at = slave;
-       bond_for_each_slave_from_to(bond, slave, i, bond->first_slave, stop_at)
+       bond_for_each_slave_continue_reverse(bond, slave)
                vlan_vid_del(slave->dev, proto, vid);
 
        return res;
@@ -478,9 +478,9 @@ static int bond_vlan_rx_kill_vid(struct net_device *bond_dev,
 {
        struct bonding *bond = netdev_priv(bond_dev);
        struct slave *slave;
-       int i, res;
+       int res;
 
-       bond_for_each_slave(bond, slave, i)
+       bond_for_each_slave(bond, slave)
                vlan_vid_del(slave->dev, proto, vid);
 
        res = bond_del_vlan(bond, vid);
@@ -532,15 +532,14 @@ static void bond_del_vlans_from_slave(struct bonding *bond,
 static int bond_set_carrier(struct bonding *bond)
 {
        struct slave *slave;
-       int i;
 
-       if (bond->slave_cnt == 0)
+       if (list_empty(&bond->slave_list))
                goto down;
 
        if (bond->params.mode == BOND_MODE_8023AD)
                return bond_3ad_set_carrier(bond);
 
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                if (slave->link == BOND_LINK_UP) {
                        if (!netif_carrier_ok(bond->dev)) {
                                netif_carrier_on(bond->dev);
@@ -681,8 +680,8 @@ static int bond_set_promiscuity(struct bonding *bond, int inc)
                }
        } else {
                struct slave *slave;
-               int i;
-               bond_for_each_slave(bond, slave, i) {
+
+               bond_for_each_slave(bond, slave) {
                        err = dev_set_promiscuity(slave->dev, inc);
                        if (err)
                                return err;
@@ -705,8 +704,8 @@ static int bond_set_allmulti(struct bonding *bond, int inc)
                }
        } else {
                struct slave *slave;
-               int i;
-               bond_for_each_slave(bond, slave, i) {
+
+               bond_for_each_slave(bond, slave) {
                        err = dev_set_allmulti(slave->dev, inc);
                        if (err)
                                return err;
@@ -715,15 +714,6 @@ static int bond_set_allmulti(struct bonding *bond, int inc)
        return err;
 }
 
-static void __bond_resend_igmp_join_requests(struct net_device *dev)
-{
-       struct in_device *in_dev;
-
-       in_dev = __in_dev_get_rcu(dev);
-       if (in_dev)
-               ip_mc_rejoin_groups(in_dev);
-}
-
 /*
  * Retrieve the list of registered multicast addresses for the bonding
  * device and retransmit an IGMP JOIN request to the current active
@@ -731,33 +721,12 @@ static void __bond_resend_igmp_join_requests(struct net_device *dev)
  */
 static void bond_resend_igmp_join_requests(struct bonding *bond)
 {
-       struct net_device *bond_dev, *vlan_dev, *upper_dev;
-       struct vlan_entry *vlan;
-
-       read_lock(&bond->lock);
-       rcu_read_lock();
-
-       bond_dev = bond->dev;
-
-       /* rejoin all groups on bond device */
-       __bond_resend_igmp_join_requests(bond_dev);
-
-       /*
-        * if bond is enslaved to a bridge,
-        * then rejoin all groups on its master
-        */
-       upper_dev = netdev_master_upper_dev_get_rcu(bond_dev);
-       if (upper_dev && upper_dev->priv_flags & IFF_EBRIDGE)
-               __bond_resend_igmp_join_requests(upper_dev);
-
-       /* rejoin all groups on vlan devices */
-       list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
-               vlan_dev = __vlan_find_dev_deep(bond_dev, htons(ETH_P_8021Q),
-                                               vlan->vlan_id);
-               if (vlan_dev)
-                       __bond_resend_igmp_join_requests(vlan_dev);
+       if (!rtnl_trylock()) {
+               queue_delayed_work(bond->wq, &bond->mcast_work, 1);
+               return;
        }
-       rcu_read_unlock();
+       call_netdevice_notifiers(NETDEV_RESEND_IGMP, bond->dev);
+       rtnl_unlock();
 
        /* We use curr_slave_lock to protect against concurrent access to
         * igmp_retrans from multiple running instances of this function and
@@ -769,7 +738,6 @@ static void bond_resend_igmp_join_requests(struct bonding *bond)
                queue_delayed_work(bond->wq, &bond->mcast_work, HZ/5);
        }
        write_unlock_bh(&bond->curr_slave_lock);
-       read_unlock(&bond->lock);
 }
 
 static void bond_resend_igmp_join_requests_delayed(struct work_struct *work)
@@ -966,9 +934,8 @@ static struct slave *bond_find_best_slave(struct bonding *bond)
        new_active = bond->curr_active_slave;
 
        if (!new_active) { /* there were no active slaves left */
-               if (bond->slave_cnt > 0)   /* found one slave */
-                       new_active = bond->first_slave;
-               else
+               new_active = bond_first_slave(bond);
+               if (!new_active)
                        return NULL; /* still no slave, return NULL */
        }
 
@@ -1071,7 +1038,7 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
                if (new_active)
                        bond_set_slave_active_flags(new_active);
        } else {
-               bond->curr_active_slave = new_active;
+               rcu_assign_pointer(bond->curr_active_slave, new_active);
        }
 
        if (bond->params.mode == BOND_MODE_ACTIVEBACKUP) {
@@ -1115,7 +1082,7 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
            ((USES_PRIMARY(bond->params.mode) && new_active) ||
             bond->params.mode == BOND_MODE_ROUNDROBIN)) {
                bond->igmp_retrans = bond->params.resend_igmp;
-               queue_delayed_work(bond->wq, &bond->mcast_work, 0);
+               queue_delayed_work(bond->wq, &bond->mcast_work, 1);
        }
 }
 
@@ -1161,17 +1128,7 @@ void bond_select_active_slave(struct bonding *bond)
  */
 static void bond_attach_slave(struct bonding *bond, struct slave *new_slave)
 {
-       if (bond->first_slave == NULL) { /* attaching the first slave */
-               new_slave->next = new_slave;
-               new_slave->prev = new_slave;
-               bond->first_slave = new_slave;
-       } else {
-               new_slave->next = bond->first_slave;
-               new_slave->prev = bond->first_slave->prev;
-               new_slave->next->prev = new_slave;
-               new_slave->prev->next = new_slave;
-       }
-
+       list_add_tail_rcu(&new_slave->list, &bond->slave_list);
        bond->slave_cnt++;
 }
 
@@ -1187,22 +1144,7 @@ static void bond_attach_slave(struct bonding *bond, struct slave *new_slave)
  */
 static void bond_detach_slave(struct bonding *bond, struct slave *slave)
 {
-       if (slave->next)
-               slave->next->prev = slave->prev;
-
-       if (slave->prev)
-               slave->prev->next = slave->next;
-
-       if (bond->first_slave == slave) { /* slave is the first slave */
-               if (bond->slave_cnt > 1) { /* there are more slave */
-                       bond->first_slave = slave->next;
-               } else {
-                       bond->first_slave = NULL; /* slave was the last one */
-               }
-       }
-
-       slave->next = NULL;
-       slave->prev = NULL;
+       list_del_rcu(&slave->list);
        bond->slave_cnt--;
 }
 
@@ -1249,47 +1191,31 @@ static void bond_poll_controller(struct net_device *bond_dev)
 {
 }
 
-static void __bond_netpoll_cleanup(struct bonding *bond)
+static void bond_netpoll_cleanup(struct net_device *bond_dev)
 {
+       struct bonding *bond = netdev_priv(bond_dev);
        struct slave *slave;
-       int i;
 
-       bond_for_each_slave(bond, slave, i)
+       bond_for_each_slave(bond, slave)
                if (IS_UP(slave->dev))
                        slave_disable_netpoll(slave);
 }
-static void bond_netpoll_cleanup(struct net_device *bond_dev)
-{
-       struct bonding *bond = netdev_priv(bond_dev);
-
-       read_lock(&bond->lock);
-       __bond_netpoll_cleanup(bond);
-       read_unlock(&bond->lock);
-}
 
 static int bond_netpoll_setup(struct net_device *dev, struct netpoll_info *ni, gfp_t gfp)
 {
        struct bonding *bond = netdev_priv(dev);
        struct slave *slave;
-       int i, err = 0;
+       int err = 0;
 
-       read_lock(&bond->lock);
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                err = slave_enable_netpoll(slave);
                if (err) {
-                       __bond_netpoll_cleanup(bond);
+                       bond_netpoll_cleanup(dev);
                        break;
                }
        }
-       read_unlock(&bond->lock);
        return err;
 }
-
-static struct netpoll_info *bond_netpoll_info(struct bonding *bond)
-{
-       return bond->dev->npinfo;
-}
-
 #else
 static inline int slave_enable_netpoll(struct slave *slave)
 {
@@ -1311,11 +1237,10 @@ static netdev_features_t bond_fix_features(struct net_device *dev,
        struct slave *slave;
        struct bonding *bond = netdev_priv(dev);
        netdev_features_t mask;
-       int i;
 
        read_lock(&bond->lock);
 
-       if (!bond->first_slave) {
+       if (list_empty(&bond->slave_list)) {
                /* Disable adding VLANs to empty bond. But why? --mq */
                features |= NETIF_F_VLAN_CHALLENGED;
                goto out;
@@ -1325,7 +1250,7 @@ static netdev_features_t bond_fix_features(struct net_device *dev,
        features &= ~NETIF_F_ONE_FOR_ALL;
        features |= NETIF_F_ALL_FOR_ALL;
 
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                features = netdev_increment_features(features,
                                                     slave->dev->features,
                                                     mask);
@@ -1349,15 +1274,14 @@ static void bond_compute_features(struct bonding *bond)
        unsigned short max_hard_header_len = ETH_HLEN;
        unsigned int gso_max_size = GSO_MAX_SIZE;
        u16 gso_max_segs = GSO_MAX_SEGS;
-       int i;
        unsigned int flags, dst_release_flag = IFF_XMIT_DST_RELEASE;
 
        read_lock(&bond->lock);
 
-       if (!bond->first_slave)
+       if (list_empty(&bond->slave_list))
                goto done;
 
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                vlan_features = netdev_increment_features(vlan_features,
                        slave->dev->vlan_features, BOND_VLAN_FEATURES);
 
@@ -1545,7 +1469,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
         * bond ether type mutual exclusion - don't allow slaves of dissimilar
         * ether type (eg ARPHRD_ETHER and ARPHRD_INFINIBAND) share the same bond
         */
-       if (bond->slave_cnt == 0) {
+       if (list_empty(&bond->slave_list)) {
                if (bond_dev->type != slave_dev->type) {
                        pr_debug("%s: change device type from %d to %d\n",
                                 bond_dev->name,
@@ -1584,7 +1508,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
        }
 
        if (slave_ops->ndo_set_mac_address == NULL) {
-               if (bond->slave_cnt == 0) {
+               if (list_empty(&bond->slave_list)) {
                        pr_warning("%s: Warning: The first slave device specified does not support setting the MAC address. Setting fail_over_mac to active.",
                                   bond_dev->name);
                        bond->params.fail_over_mac = BOND_FOM_ACTIVE;
@@ -1600,7 +1524,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
 
        /* If this is the first slave, then we need to set the master's hardware
         * address to be the same as the slave's. */
-       if (!bond->slave_cnt && bond->dev->addr_assign_type == NET_ADDR_RANDOM)
+       if (list_empty(&bond->slave_list) &&
+           bond->dev->addr_assign_type == NET_ADDR_RANDOM)
                bond_set_dev_addr(bond->dev, slave_dev);
 
        new_slave = kzalloc(sizeof(struct slave), GFP_KERNEL);
@@ -1608,7 +1533,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
                res = -ENOMEM;
                goto err_undo_flags;
        }
-
+       INIT_LIST_HEAD(&new_slave->list);
        /*
         * Set the new_slave's queue_id to be zero.  Queue ID mapping
         * is set via sysfs or module option if desired.
@@ -1794,15 +1719,18 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
                 */
                bond_set_slave_inactive_flags(new_slave);
                /* if this is the first slave */
-               if (bond->slave_cnt == 1) {
+               if (bond_first_slave(bond) == new_slave) {
                        SLAVE_AD_INFO(new_slave).id = 1;
                        /* Initialize AD with the number of times that the AD timer is called in 1 second
                         * can be called only after the mac address of the bond is set
                         */
                        bond_3ad_initialize(bond, 1000/AD_TIMER_INTERVAL);
                } else {
+                       struct slave *prev_slave;
+
+                       prev_slave = bond_prev_slave(bond, new_slave);
                        SLAVE_AD_INFO(new_slave).id =
-                               SLAVE_AD_INFO(new_slave->prev).id + 1;
+                               SLAVE_AD_INFO(prev_slave).id + 1;
                }
 
                bond_3ad_bind_slave(new_slave);
@@ -1824,7 +1752,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
                 * so we can change it without calling change_active_interface()
                 */
                if (!bond->curr_active_slave && new_slave->link == BOND_LINK_UP)
-                       bond->curr_active_slave = new_slave;
+                       rcu_assign_pointer(bond->curr_active_slave, new_slave);
 
                break;
        } /* switch(bond_mode) */
@@ -1834,7 +1762,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
        bond_set_carrier(bond);
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
-       slave_dev->npinfo = bond_netpoll_info(bond);
+       slave_dev->npinfo = bond->dev->npinfo;
        if (slave_dev->npinfo) {
                if (slave_enable_netpoll(new_slave)) {
                        read_unlock(&bond->lock);
@@ -1921,7 +1849,7 @@ err_free:
 err_undo_flags:
        bond_compute_features(bond);
        /* Enslave of first slave has failed and we need to fix master's mac */
-       if (bond->slave_cnt == 0 &&
+       if (list_empty(&bond->slave_list) &&
            ether_addr_equal(bond_dev->dev_addr, slave_dev->dev_addr))
                eth_hw_addr_random(bond_dev);
 
@@ -1977,15 +1905,6 @@ static int __bond_release_one(struct net_device *bond_dev,
        netdev_rx_handler_unregister(slave_dev);
        write_lock_bh(&bond->lock);
 
-       if (!all && !bond->params.fail_over_mac) {
-               if (ether_addr_equal(bond_dev->dev_addr, slave->perm_hwaddr) &&
-                   bond->slave_cnt > 1)
-                       pr_warning("%s: Warning: the permanent HWaddr of %s - %pM - is still in use by %s. Set the HWaddr of %s to a different address to avoid conflicts.\n",
-                                  bond_dev->name, slave_dev->name,
-                                  slave->perm_hwaddr,
-                                  bond_dev->name, slave_dev->name);
-       }
-
        /* Inform AD package of unbinding of slave. */
        if (bond->params.mode == BOND_MODE_8023AD) {
                /* must be called before the slave is
@@ -2006,6 +1925,15 @@ static int __bond_release_one(struct net_device *bond_dev,
        /* release the slave from its bond */
        bond_detach_slave(bond, slave);
 
+       if (!all && !bond->params.fail_over_mac) {
+               if (ether_addr_equal(bond_dev->dev_addr, slave->perm_hwaddr) &&
+                   !list_empty(&bond->slave_list))
+                       pr_warn("%s: Warning: the permanent HWaddr of %s - %pM - is still in use by %s. Set the HWaddr of %s to a different address to avoid conflicts.\n",
+                                  bond_dev->name, slave_dev->name,
+                                  slave->perm_hwaddr,
+                                  bond_dev->name, slave_dev->name);
+       }
+
        if (bond->primary_slave == slave)
                bond->primary_slave = NULL;
 
@@ -2024,7 +1952,7 @@ static int __bond_release_one(struct net_device *bond_dev,
        }
 
        if (all) {
-               bond->curr_active_slave = NULL;
+               rcu_assign_pointer(bond->curr_active_slave, NULL);
        } else if (oldcurrent == slave) {
                /*
                 * Note that we hold RTNL over this sequence, so there
@@ -2042,7 +1970,7 @@ static int __bond_release_one(struct net_device *bond_dev,
                write_lock_bh(&bond->lock);
        }
 
-       if (bond->slave_cnt == 0) {
+       if (list_empty(&bond->slave_list)) {
                bond_set_carrier(bond);
                eth_hw_addr_random(bond_dev);
 
@@ -2056,8 +1984,9 @@ static int __bond_release_one(struct net_device *bond_dev,
 
        write_unlock_bh(&bond->lock);
        unblock_netpoll_tx();
+       synchronize_rcu();
 
-       if (bond->slave_cnt == 0) {
+       if (list_empty(&bond->slave_list)) {
                call_netdevice_notifiers(NETDEV_CHANGEADDR, bond->dev);
                call_netdevice_notifiers(NETDEV_RELEASE, bond->dev);
        }
@@ -2128,7 +2057,7 @@ static int  bond_release_and_destroy(struct net_device *bond_dev,
        int ret;
 
        ret = bond_release(bond_dev, slave_dev);
-       if ((ret == 0) && (bond->slave_cnt == 0)) {
+       if (ret == 0 && list_empty(&bond->slave_list)) {
                bond_dev->priv_flags |= IFF_DISABLE_NETPOLL;
                pr_info("%s: destroying bond %s.\n",
                        bond_dev->name, bond_dev->name);
@@ -2165,23 +2094,19 @@ static int bond_ioctl_change_active(struct net_device *bond_dev, struct net_devi
 
        read_lock(&bond->lock);
 
-       read_lock(&bond->curr_slave_lock);
        old_active = bond->curr_active_slave;
-       read_unlock(&bond->curr_slave_lock);
-
        new_active = bond_get_slave_by_dev(bond, slave_dev);
-
        /*
         * Changing to the current active: do nothing; return success.
         */
-       if (new_active && (new_active == old_active)) {
+       if (new_active && new_active == old_active) {
                read_unlock(&bond->lock);
                return 0;
        }
 
-       if ((new_active) &&
-           (old_active) &&
-           (new_active->link == BOND_LINK_UP) &&
+       if (new_active &&
+           old_active &&
+           new_active->link == BOND_LINK_UP &&
            IS_UP(new_active->dev)) {
                block_netpoll_tx();
                write_lock_bh(&bond->curr_slave_lock);
@@ -2213,13 +2138,12 @@ static int bond_info_query(struct net_device *bond_dev, struct ifbond *info)
 static int bond_slave_info_query(struct net_device *bond_dev, struct ifslave *info)
 {
        struct bonding *bond = netdev_priv(bond_dev);
+       int i = 0, res = -ENODEV;
        struct slave *slave;
-       int i, res = -ENODEV;
 
        read_lock(&bond->lock);
-
-       bond_for_each_slave(bond, slave, i) {
-               if (i == (int)info->slave_id) {
+       bond_for_each_slave(bond, slave) {
+               if (i++ == (int)info->slave_id) {
                        res = 0;
                        strcpy(info->slave_name, slave->dev->name);
                        info->link = slave->link;
@@ -2228,7 +2152,6 @@ static int bond_slave_info_query(struct net_device *bond_dev, struct ifslave *in
                        break;
                }
        }
-
        read_unlock(&bond->lock);
 
        return res;
@@ -2239,13 +2162,13 @@ static int bond_slave_info_query(struct net_device *bond_dev, struct ifslave *in
 
 static int bond_miimon_inspect(struct bonding *bond)
 {
+       int link_state, commit = 0;
        struct slave *slave;
-       int i, link_state, commit = 0;
        bool ignore_updelay;
 
        ignore_updelay = !bond->curr_active_slave ? true : false;
 
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                slave->new_link = BOND_LINK_NOCHANGE;
 
                link_state = bond_check_dev_link(bond, slave->dev, 0);
@@ -2340,9 +2263,8 @@ static int bond_miimon_inspect(struct bonding *bond)
 static void bond_miimon_commit(struct bonding *bond)
 {
        struct slave *slave;
-       int i;
 
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                switch (slave->new_link) {
                case BOND_LINK_NOCHANGE:
                        continue;
@@ -2447,7 +2369,7 @@ void bond_mii_monitor(struct work_struct *work)
 
        delay = msecs_to_jiffies(bond->params.miimon);
 
-       if (bond->slave_cnt == 0)
+       if (list_empty(&bond->slave_list))
                goto re_arm;
 
        should_notify_peers = bond_should_notify_peers(bond);
@@ -2713,6 +2635,20 @@ out_unlock:
        return RX_HANDLER_ANOTHER;
 }
 
+/* function to verify if we're in the arp_interval timeslice, returns true if
+ * (last_act - arp_interval) <= jiffies <= (last_act + mod * arp_interval +
+ * arp_interval/2) . the arp_interval/2 is needed for really fast networks.
+ */
+static bool bond_time_in_interval(struct bonding *bond, unsigned long last_act,
+                                 int mod)
+{
+       int delta_in_ticks = msecs_to_jiffies(bond->params.arp_interval);
+
+       return time_in_range(jiffies,
+                            last_act - delta_in_ticks,
+                            last_act + mod * delta_in_ticks + delta_in_ticks/2);
+}
+
 /*
  * this function is called regularly to monitor each slave's link
  * ensuring that traffic is being sent and received when arp monitoring
@@ -2726,21 +2662,13 @@ void bond_loadbalance_arp_mon(struct work_struct *work)
                                            arp_work.work);
        struct slave *slave, *oldcurrent;
        int do_failover = 0;
-       int delta_in_ticks, extra_ticks;
-       int i;
 
        read_lock(&bond->lock);
 
-       delta_in_ticks = msecs_to_jiffies(bond->params.arp_interval);
-       extra_ticks = delta_in_ticks / 2;
-
-       if (bond->slave_cnt == 0)
+       if (list_empty(&bond->slave_list))
                goto re_arm;
 
-       read_lock(&bond->curr_slave_lock);
        oldcurrent = bond->curr_active_slave;
-       read_unlock(&bond->curr_slave_lock);
-
        /* see if any of the previous devices are up now (i.e. they have
         * xmt and rcv traffic). the curr_active_slave does not come into
         * the picture unless it is null. also, slave->jiffies is not needed
@@ -2749,16 +2677,12 @@ void bond_loadbalance_arp_mon(struct work_struct *work)
         * TODO: what about up/down delay in arp mode? it wasn't here before
         *       so it can wait
         */
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                unsigned long trans_start = dev_trans_start(slave->dev);
 
                if (slave->link != BOND_LINK_UP) {
-                       if (time_in_range(jiffies,
-                               trans_start - delta_in_ticks,
-                               trans_start + delta_in_ticks + extra_ticks) &&
-                           time_in_range(jiffies,
-                               slave->dev->last_rx - delta_in_ticks,
-                               slave->dev->last_rx + delta_in_ticks + extra_ticks)) {
+                       if (bond_time_in_interval(bond, trans_start, 1) &&
+                           bond_time_in_interval(bond, slave->dev->last_rx, 1)) {
 
                                slave->link  = BOND_LINK_UP;
                                bond_set_active_slave(slave);
@@ -2786,12 +2710,8 @@ void bond_loadbalance_arp_mon(struct work_struct *work)
                         * when the source ip is 0, so don't take the link down
                         * if we don't know our ip yet
                         */
-                       if (!time_in_range(jiffies,
-                               trans_start - delta_in_ticks,
-                               trans_start + 2 * delta_in_ticks + extra_ticks) ||
-                           !time_in_range(jiffies,
-                               slave->dev->last_rx - delta_in_ticks,
-                               slave->dev->last_rx + 2 * delta_in_ticks + extra_ticks)) {
+                       if (!bond_time_in_interval(bond, trans_start, 2) ||
+                           !bond_time_in_interval(bond, slave->dev->last_rx, 2)) {
 
                                slave->link  = BOND_LINK_DOWN;
                                bond_set_backup_slave(slave);
@@ -2831,7 +2751,8 @@ void bond_loadbalance_arp_mon(struct work_struct *work)
 
 re_arm:
        if (bond->params.arp_interval)
-               queue_delayed_work(bond->wq, &bond->arp_work, delta_in_ticks);
+               queue_delayed_work(bond->wq, &bond->arp_work,
+                                  msecs_to_jiffies(bond->params.arp_interval));
 
        read_unlock(&bond->lock);
 }
@@ -2844,32 +2765,21 @@ re_arm:
  *
  * Called with bond->lock held for read.
  */
-static int bond_ab_arp_inspect(struct bonding *bond, int delta_in_ticks)
+static int bond_ab_arp_inspect(struct bonding *bond)
 {
+       unsigned long trans_start, last_rx;
        struct slave *slave;
-       int i, commit = 0;
-       unsigned long trans_start;
-       int extra_ticks;
+       int commit = 0;
 
-       /* All the time comparisons below need some extra time. Otherwise, on
-        * fast networks the ARP probe/reply may arrive within the same jiffy
-        * as it was sent.  Then, the next time the ARP monitor is run, one
-        * arp_interval will already have passed in the comparisons.
-        */
-       extra_ticks = delta_in_ticks / 2;
-
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                slave->new_link = BOND_LINK_NOCHANGE;
+               last_rx = slave_last_rx(bond, slave);
 
                if (slave->link != BOND_LINK_UP) {
-                       if (time_in_range(jiffies,
-                               slave_last_rx(bond, slave) - delta_in_ticks,
-                               slave_last_rx(bond, slave) + delta_in_ticks + extra_ticks)) {
-
+                       if (bond_time_in_interval(bond, last_rx, 1)) {
                                slave->new_link = BOND_LINK_UP;
                                commit++;
                        }
-
                        continue;
                }
 
@@ -2878,9 +2788,7 @@ static int bond_ab_arp_inspect(struct bonding *bond, int delta_in_ticks)
                 * active.  This avoids bouncing, as the last receive
                 * times need a full ARP monitor cycle to be updated.
                 */
-               if (time_in_range(jiffies,
-                                 slave->jiffies - delta_in_ticks,
-                                 slave->jiffies + 2 * delta_in_ticks + extra_ticks))
+               if (bond_time_in_interval(bond, slave->jiffies, 2))
                        continue;
 
                /*
@@ -2898,10 +2806,7 @@ static int bond_ab_arp_inspect(struct bonding *bond, int delta_in_ticks)
                 */
                if (!bond_is_active_slave(slave) &&
                    !bond->current_arp_slave &&
-                   !time_in_range(jiffies,
-                       slave_last_rx(bond, slave) - delta_in_ticks,
-                       slave_last_rx(bond, slave) + 3 * delta_in_ticks + extra_ticks)) {
-
+                   !bond_time_in_interval(bond, last_rx, 3)) {
                        slave->new_link = BOND_LINK_DOWN;
                        commit++;
                }
@@ -2914,13 +2819,8 @@ static int bond_ab_arp_inspect(struct bonding *bond, int delta_in_ticks)
                 */
                trans_start = dev_trans_start(slave->dev);
                if (bond_is_active_slave(slave) &&
-                   (!time_in_range(jiffies,
-                       trans_start - delta_in_ticks,
-                       trans_start + 2 * delta_in_ticks + extra_ticks) ||
-                    !time_in_range(jiffies,
-                       slave_last_rx(bond, slave) - delta_in_ticks,
-                       slave_last_rx(bond, slave) + 2 * delta_in_ticks + extra_ticks))) {
-
+                   (!bond_time_in_interval(bond, trans_start, 2) ||
+                    !bond_time_in_interval(bond, last_rx, 2))) {
                        slave->new_link = BOND_LINK_DOWN;
                        commit++;
                }
@@ -2935,24 +2835,21 @@ static int bond_ab_arp_inspect(struct bonding *bond, int delta_in_ticks)
  *
  * Called with RTNL and bond->lock for read.
  */
-static void bond_ab_arp_commit(struct bonding *bond, int delta_in_ticks)
+static void bond_ab_arp_commit(struct bonding *bond)
 {
-       struct slave *slave;
-       int i;
        unsigned long trans_start;
+       struct slave *slave;
 
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                switch (slave->new_link) {
                case BOND_LINK_NOCHANGE:
                        continue;
 
                case BOND_LINK_UP:
                        trans_start = dev_trans_start(slave->dev);
-                       if ((!bond->curr_active_slave &&
-                            time_in_range(jiffies,
-                                          trans_start - delta_in_ticks,
-                                          trans_start + delta_in_ticks + delta_in_ticks / 2)) ||
-                           bond->curr_active_slave != slave) {
+                       if (bond->curr_active_slave != slave ||
+                           (!bond->curr_active_slave &&
+                            bond_time_in_interval(bond, trans_start, 1))) {
                                slave->link = BOND_LINK_UP;
                                if (bond->current_arp_slave) {
                                        bond_set_slave_inactive_flags(
@@ -3014,7 +2911,7 @@ do_failover:
  */
 static void bond_ab_arp_probe(struct bonding *bond)
 {
-       struct slave *slave;
+       struct slave *slave, *next_slave;
        int i;
 
        read_lock(&bond->curr_slave_lock);
@@ -3038,7 +2935,7 @@ static void bond_ab_arp_probe(struct bonding *bond)
         */
 
        if (!bond->current_arp_slave) {
-               bond->current_arp_slave = bond->first_slave;
+               bond->current_arp_slave = bond_first_slave(bond);
                if (!bond->current_arp_slave)
                        return;
        }
@@ -3046,7 +2943,8 @@ static void bond_ab_arp_probe(struct bonding *bond)
        bond_set_slave_inactive_flags(bond->current_arp_slave);
 
        /* search for next candidate */
-       bond_for_each_slave_from(bond, slave, i, bond->current_arp_slave->next) {
+       next_slave = bond_next_slave(bond, bond->current_arp_slave);
+       bond_for_each_slave_from(bond, slave, i, next_slave) {
                if (IS_UP(slave->dev)) {
                        slave->link = BOND_LINK_BACK;
                        bond_set_slave_active_flags(slave);
@@ -3087,12 +2985,12 @@ void bond_activebackup_arp_mon(struct work_struct *work)
 
        delta_in_ticks = msecs_to_jiffies(bond->params.arp_interval);
 
-       if (bond->slave_cnt == 0)
+       if (list_empty(&bond->slave_list))
                goto re_arm;
 
        should_notify_peers = bond_should_notify_peers(bond);
 
-       if (bond_ab_arp_inspect(bond, delta_in_ticks)) {
+       if (bond_ab_arp_inspect(bond)) {
                read_unlock(&bond->lock);
 
                /* Race avoidance with bond_close flush of workqueue */
@@ -3105,7 +3003,7 @@ void bond_activebackup_arp_mon(struct work_struct *work)
 
                read_lock(&bond->lock);
 
-               bond_ab_arp_commit(bond, delta_in_ticks);
+               bond_ab_arp_commit(bond);
 
                read_unlock(&bond->lock);
                rtnl_unlock();
@@ -3234,6 +3132,10 @@ static int bond_slave_netdev_event(unsigned long event,
        case NETDEV_FEAT_CHANGE:
                bond_compute_features(bond);
                break;
+       case NETDEV_RESEND_IGMP:
+               /* Propagate to master device */
+               call_netdevice_notifiers(event, slave->bond->dev);
+               break;
        default:
                break;
        }
@@ -3403,13 +3305,12 @@ static int bond_open(struct net_device *bond_dev)
 {
        struct bonding *bond = netdev_priv(bond_dev);
        struct slave *slave;
-       int i;
 
        /* reset slave->backup and slave->inactive */
        read_lock(&bond->lock);
-       if (bond->slave_cnt > 0) {
+       if (!list_empty(&bond->slave_list)) {
                read_lock(&bond->curr_slave_lock);
-               bond_for_each_slave(bond, slave, i) {
+               bond_for_each_slave(bond, slave) {
                        if ((bond->params.mode == BOND_MODE_ACTIVEBACKUP)
                                && (slave != bond->curr_active_slave)) {
                                bond_set_slave_inactive_flags(slave);
@@ -3477,13 +3378,11 @@ static struct rtnl_link_stats64 *bond_get_stats(struct net_device *bond_dev,
        struct bonding *bond = netdev_priv(bond_dev);
        struct rtnl_link_stats64 temp;
        struct slave *slave;
-       int i;
 
        memset(stats, 0, sizeof(*stats));
 
        read_lock_bh(&bond->lock);
-
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                const struct rtnl_link_stats64 *sstats =
                        dev_get_stats(slave->dev, &temp);
 
@@ -3513,7 +3412,6 @@ static struct rtnl_link_stats64 *bond_get_stats(struct net_device *bond_dev,
                stats->tx_heartbeat_errors += sstats->tx_heartbeat_errors;
                stats->tx_window_errors += sstats->tx_window_errors;
        }
-
        read_unlock_bh(&bond->lock);
 
        return stats;
@@ -3652,7 +3550,6 @@ static void bond_set_rx_mode(struct net_device *bond_dev)
 {
        struct bonding *bond = netdev_priv(bond_dev);
        struct slave *slave;
-       int i;
 
        read_lock(&bond->lock);
 
@@ -3665,7 +3562,7 @@ static void bond_set_rx_mode(struct net_device *bond_dev)
                }
                read_unlock(&bond->curr_slave_lock);
        } else {
-               bond_for_each_slave(bond, slave, i) {
+               bond_for_each_slave(bond, slave) {
                        dev_uc_sync_multiple(slave->dev, bond_dev);
                        dev_mc_sync_multiple(slave->dev, bond_dev);
                }
@@ -3677,16 +3574,15 @@ static void bond_set_rx_mode(struct net_device *bond_dev)
 static int bond_neigh_init(struct neighbour *n)
 {
        struct bonding *bond = netdev_priv(n->dev);
-       struct slave *slave = bond->first_slave;
        const struct net_device_ops *slave_ops;
        struct neigh_parms parms;
+       struct slave *slave;
        int ret;
 
+       slave = bond_first_slave(bond);
        if (!slave)
                return 0;
-
        slave_ops = slave->dev->netdev_ops;
-
        if (!slave_ops->ndo_neigh_setup)
                return 0;
 
@@ -3714,11 +3610,17 @@ static int bond_neigh_init(struct neighbour *n)
  * The bonding ndo_neigh_setup is called at init time beofre any
  * slave exists. So we must declare proxy setup function which will
  * be used at run time to resolve the actual slave neigh param setup.
+ *
+ * It's also called by master devices (such as vlans) to setup their
+ * underlying devices. In that case - do nothing, we're already set up from
+ * our init.
  */
 static int bond_neigh_setup(struct net_device *dev,
                            struct neigh_parms *parms)
 {
-       parms->neigh_setup   = bond_neigh_init;
+       /* modify only our neigh_parms */
+       if (parms->dev == dev)
+               parms->neigh_setup = bond_neigh_init;
 
        return 0;
 }
@@ -3729,9 +3631,8 @@ static int bond_neigh_setup(struct net_device *dev,
 static int bond_change_mtu(struct net_device *bond_dev, int new_mtu)
 {
        struct bonding *bond = netdev_priv(bond_dev);
-       struct slave *slave, *stop_at;
+       struct slave *slave;
        int res = 0;
-       int i;
 
        pr_debug("bond=%p, name=%s, new_mtu=%d\n", bond,
                 (bond_dev ? bond_dev->name : "None"), new_mtu);
@@ -3751,10 +3652,10 @@ static int bond_change_mtu(struct net_device *bond_dev, int new_mtu)
         * call to the base driver.
         */
 
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                pr_debug("s %p s->p %p c_m %p\n",
                         slave,
-                        slave->prev,
+                        bond_prev_slave(bond, slave),
                         slave->dev->netdev_ops->ndo_change_mtu);
 
                res = dev_set_mtu(slave->dev, new_mtu);
@@ -3779,8 +3680,7 @@ static int bond_change_mtu(struct net_device *bond_dev, int new_mtu)
 
 unwind:
        /* unwind from head to the slave that failed */
-       stop_at = slave;
-       bond_for_each_slave_from_to(bond, slave, i, bond->first_slave, stop_at) {
+       bond_for_each_slave_continue_reverse(bond, slave) {
                int tmp_res;
 
                tmp_res = dev_set_mtu(slave->dev, bond_dev->mtu);
@@ -3804,9 +3704,8 @@ static int bond_set_mac_address(struct net_device *bond_dev, void *addr)
 {
        struct bonding *bond = netdev_priv(bond_dev);
        struct sockaddr *sa = addr, tmp_sa;
-       struct slave *slave, *stop_at;
+       struct slave *slave;
        int res = 0;
-       int i;
 
        if (bond->params.mode == BOND_MODE_ALB)
                return bond_alb_set_mac_address(bond_dev, addr);
@@ -3839,7 +3738,7 @@ static int bond_set_mac_address(struct net_device *bond_dev, void *addr)
         * call to the base driver.
         */
 
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                const struct net_device_ops *slave_ops = slave->dev->netdev_ops;
                pr_debug("slave %p %s\n", slave, slave->dev->name);
 
@@ -3871,8 +3770,7 @@ unwind:
        tmp_sa.sa_family = bond_dev->type;
 
        /* unwind from head to the slave that failed */
-       stop_at = slave;
-       bond_for_each_slave_from_to(bond, slave, i, bond->first_slave, stop_at) {
+       bond_for_each_slave_continue_reverse(bond, slave) {
                int tmp_res;
 
                tmp_res = dev_set_mac_address(slave->dev, &tmp_sa);
@@ -3885,12 +3783,50 @@ unwind:
        return res;
 }
 
+/**
+ * bond_xmit_slave_id - transmit skb through slave with slave_id
+ * @bond: bonding device that is transmitting
+ * @skb: buffer to transmit
+ * @slave_id: slave id up to slave_cnt-1 through which to transmit
+ *
+ * This function tries to transmit through slave with slave_id but in case
+ * it fails, it tries to find the first available slave for transmission.
+ * The skb is consumed in all cases, thus the function is void.
+ */
+void bond_xmit_slave_id(struct bonding *bond, struct sk_buff *skb, int slave_id)
+{
+       struct slave *slave;
+       int i = slave_id;
+
+       /* Here we start from the slave with slave_id */
+       bond_for_each_slave_rcu(bond, slave) {
+               if (--i < 0) {
+                       if (slave_can_tx(slave)) {
+                               bond_dev_queue_xmit(bond, skb, slave->dev);
+                               return;
+                       }
+               }
+       }
+
+       /* Here we start from the first slave up to slave_id */
+       i = slave_id;
+       bond_for_each_slave_rcu(bond, slave) {
+               if (--i < 0)
+                       break;
+               if (slave_can_tx(slave)) {
+                       bond_dev_queue_xmit(bond, skb, slave->dev);
+                       return;
+               }
+       }
+       /* no slave that can tx has been found */
+       kfree_skb(skb);
+}
+
 static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *bond_dev)
 {
        struct bonding *bond = netdev_priv(bond_dev);
-       struct slave *slave, *start_at;
-       int i, slave_no, res = 1;
        struct iphdr *iph = ip_hdr(skb);
+       struct slave *slave;
 
        /*
         * Start with the curr_active_slave that joined the bond as the
@@ -3899,50 +3835,20 @@ static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *bond_dev
         * send the join/membership reports.  The curr_active_slave found
         * will send all of this type of traffic.
         */
-       if ((iph->protocol == IPPROTO_IGMP) &&
-           (skb->protocol == htons(ETH_P_IP))) {
-
-               read_lock(&bond->curr_slave_lock);
-               slave = bond->curr_active_slave;
-               read_unlock(&bond->curr_slave_lock);
-
-               if (!slave)
-                       goto out;
+       if (iph->protocol == IPPROTO_IGMP && skb->protocol == htons(ETH_P_IP)) {
+               slave = rcu_dereference(bond->curr_active_slave);
+               if (slave && slave_can_tx(slave))
+                       bond_dev_queue_xmit(bond, skb, slave->dev);
+               else
+                       bond_xmit_slave_id(bond, skb, 0);
        } else {
-               /*
-                * Concurrent TX may collide on rr_tx_counter; we accept
-                * that as being rare enough not to justify using an
-                * atomic op here.
-                */
-               slave_no = bond->rr_tx_counter++ % bond->slave_cnt;
-
-               bond_for_each_slave(bond, slave, i) {
-                       slave_no--;
-                       if (slave_no < 0)
-                               break;
-               }
-       }
-
-       start_at = slave;
-       bond_for_each_slave_from(bond, slave, i, start_at) {
-               if (IS_UP(slave->dev) &&
-                   (slave->link == BOND_LINK_UP) &&
-                   bond_is_active_slave(slave)) {
-                       res = bond_dev_queue_xmit(bond, skb, slave->dev);
-                       break;
-               }
-       }
-
-out:
-       if (res) {
-               /* no suitable interface, frame not sent */
-               kfree_skb(skb);
+               bond_xmit_slave_id(bond, skb,
+                                  bond->rr_tx_counter++ % bond->slave_cnt);
        }
 
        return NETDEV_TX_OK;
 }
 
-
 /*
  * in active-backup mode, we know that bond->curr_active_slave is always valid if
  * the bond has a usable interface.
@@ -3950,18 +3856,12 @@ out:
 static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *bond_dev)
 {
        struct bonding *bond = netdev_priv(bond_dev);
-       int res = 1;
-
-       read_lock(&bond->curr_slave_lock);
-
-       if (bond->curr_active_slave)
-               res = bond_dev_queue_xmit(bond, skb,
-                       bond->curr_active_slave->dev);
-
-       read_unlock(&bond->curr_slave_lock);
+       struct slave *slave;
 
-       if (res)
-               /* no suitable interface, frame not sent */
+       slave = rcu_dereference(bond->curr_active_slave);
+       if (slave)
+               bond_dev_queue_xmit(bond, skb, slave->dev);
+       else
                kfree_skb(skb);
 
        return NETDEV_TX_OK;
@@ -3975,87 +3875,39 @@ static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *bond_d
 static int bond_xmit_xor(struct sk_buff *skb, struct net_device *bond_dev)
 {
        struct bonding *bond = netdev_priv(bond_dev);
-       struct slave *slave, *start_at;
-       int slave_no;
-       int i;
-       int res = 1;
-
-       slave_no = bond->xmit_hash_policy(skb, bond->slave_cnt);
-
-       bond_for_each_slave(bond, slave, i) {
-               slave_no--;
-               if (slave_no < 0)
-                       break;
-       }
-
-       start_at = slave;
 
-       bond_for_each_slave_from(bond, slave, i, start_at) {
-               if (IS_UP(slave->dev) &&
-                   (slave->link == BOND_LINK_UP) &&
-                   bond_is_active_slave(slave)) {
-                       res = bond_dev_queue_xmit(bond, skb, slave->dev);
-                       break;
-               }
-       }
-
-       if (res) {
-               /* no suitable interface, frame not sent */
-               kfree_skb(skb);
-       }
+       bond_xmit_slave_id(bond, skb,
+                          bond->xmit_hash_policy(skb, bond->slave_cnt));
 
        return NETDEV_TX_OK;
 }
 
-/*
- * in broadcast mode, we send everything to all usable interfaces.
- */
+/* in broadcast mode, we send everything to all usable interfaces. */
 static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *bond_dev)
 {
        struct bonding *bond = netdev_priv(bond_dev);
-       struct slave *slave, *start_at;
-       struct net_device *tx_dev = NULL;
-       int i;
-       int res = 1;
-
-       read_lock(&bond->curr_slave_lock);
-       start_at = bond->curr_active_slave;
-       read_unlock(&bond->curr_slave_lock);
-
-       if (!start_at)
-               goto out;
+       struct slave *slave = NULL;
 
-       bond_for_each_slave_from(bond, slave, i, start_at) {
-               if (IS_UP(slave->dev) &&
-                   (slave->link == BOND_LINK_UP) &&
-                   bond_is_active_slave(slave)) {
-                       if (tx_dev) {
-                               struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
-                               if (!skb2) {
-                                       pr_err("%s: Error: bond_xmit_broadcast(): skb_clone() failed\n",
-                                              bond_dev->name);
-                                       continue;
-                               }
+       bond_for_each_slave_rcu(bond, slave) {
+               if (bond_is_last_slave(bond, slave))
+                       break;
+               if (IS_UP(slave->dev) && slave->link == BOND_LINK_UP) {
+                       struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
 
-                               res = bond_dev_queue_xmit(bond, skb2, tx_dev);
-                               if (res) {
-                                       kfree_skb(skb2);
-                                       continue;
-                               }
+                       if (!skb2) {
+                               pr_err("%s: Error: bond_xmit_broadcast(): skb_clone() failed\n",
+                                      bond_dev->name);
+                               continue;
                        }
-                       tx_dev = slave->dev;
+                       /* bond_dev_queue_xmit always returns 0 */
+                       bond_dev_queue_xmit(bond, skb2, slave->dev);
                }
        }
-
-       if (tx_dev)
-               res = bond_dev_queue_xmit(bond, skb, tx_dev);
-
-out:
-       if (res)
-               /* no suitable interface, frame not sent */
+       if (slave && IS_UP(slave->dev) && slave->link == BOND_LINK_UP)
+               bond_dev_queue_xmit(bond, skb, slave->dev);
+       else
                kfree_skb(skb);
 
-       /* frame sent to all suitable interfaces */
        return NETDEV_TX_OK;
 }
 
@@ -4083,15 +3935,15 @@ static void bond_set_xmit_hash_policy(struct bonding *bond)
 static inline int bond_slave_override(struct bonding *bond,
                                      struct sk_buff *skb)
 {
-       int i, res = 1;
        struct slave *slave = NULL;
        struct slave *check_slave;
+       int res = 1;
 
        if (!skb->queue_mapping)
                return 1;
 
        /* Find out if any slaves have the same mapping as this skb. */
-       bond_for_each_slave(bond, check_slave, i) {
+       bond_for_each_slave_rcu(bond, check_slave) {
                if (check_slave->queue_id == skb->queue_mapping) {
                        slave = check_slave;
                        break;
@@ -4176,14 +4028,12 @@ static netdev_tx_t bond_start_xmit(struct sk_buff *skb, struct net_device *dev)
        if (is_netpoll_tx_blocked(dev))
                return NETDEV_TX_BUSY;
 
-       read_lock(&bond->lock);
-
-       if (bond->slave_cnt)
+       rcu_read_lock();
+       if (!list_empty(&bond->slave_list))
                ret = __bond_start_xmit(skb, dev);
        else
                kfree_skb(skb);
-
-       read_unlock(&bond->lock);
+       rcu_read_unlock();
 
        return ret;
 }
@@ -4224,9 +4074,8 @@ static int bond_ethtool_get_settings(struct net_device *bond_dev,
                                     struct ethtool_cmd *ecmd)
 {
        struct bonding *bond = netdev_priv(bond_dev);
-       struct slave *slave;
-       int i;
        unsigned long speed = 0;
+       struct slave *slave;
 
        ecmd->duplex = DUPLEX_UNKNOWN;
        ecmd->port = PORT_OTHER;
@@ -4237,7 +4086,7 @@ static int bond_ethtool_get_settings(struct net_device *bond_dev,
         * this is an accurate maximum.
         */
        read_lock(&bond->lock);
-       bond_for_each_slave(bond, slave, i) {
+       bond_for_each_slave(bond, slave) {
                if (SLAVE_IS_OK(slave)) {
                        if (slave->speed != SPEED_UNKNOWN)
                                speed += slave->speed;
@@ -4248,6 +4097,7 @@ static int bond_ethtool_get_settings(struct net_device *bond_dev,
        }
        ethtool_cmd_speed_set(ecmd, speed ? : SPEED_UNKNOWN);
        read_unlock(&bond->lock);
+
        return 0;
 }
 
@@ -4311,7 +4161,7 @@ static void bond_setup(struct net_device *bond_dev)
        /* initialize rwlocks */
        rwlock_init(&bond->lock);
        rwlock_init(&bond->curr_slave_lock);
-
+       INIT_LIST_HEAD(&bond->slave_list);
        bond->params = bonding_defaults;
 
        /* Initialize pointers */
@@ -4368,13 +4218,14 @@ static void bond_setup(struct net_device *bond_dev)
 static void bond_uninit(struct net_device *bond_dev)
 {
        struct bonding *bond = netdev_priv(bond_dev);
+       struct slave *slave, *tmp_slave;
        struct vlan_entry *vlan, *tmp;
 
        bond_netpoll_cleanup(bond_dev);
 
        /* Release the bonded slaves */
-       while (bond->first_slave != NULL)
-               __bond_release_one(bond_dev, bond->first_slave->dev, true);
+       list_for_each_entry_safe(slave, tmp_slave, &bond->slave_list, list)
+               __bond_release_one(bond_dev, slave->dev, true);
        pr_info("%s: released all slaves\n", bond_dev->name);
 
        list_del(&bond->bond_list);