diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index b70ca0e41142..84d4e97007cb 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -3705,80 +3705,75 @@ static void bond_fold_stats(struct rtnl_link_stats64 *_res,
 	}
 }
 
-#ifdef CONFIG_LOCKDEP
-static int bond_get_lowest_level_rcu(struct net_device *dev)
-{
-	struct net_device *ldev, *next, *now, *dev_stack[MAX_NEST_DEV + 1];
-	struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1];
-	int cur = 0, max = 0;
-
-	now = dev;
-	iter = &dev->adj_list.lower;
-
-	while (1) {
-		next = NULL;
-		while (1) {
-			ldev = netdev_next_lower_dev_rcu(now, &iter);
-			if (!ldev)
-				break;
-
-			next = ldev;
-			niter = &ldev->adj_list.lower;
-			dev_stack[cur] = now;
-			iter_stack[cur++] = iter;
-			if (max <= cur)
-				max = cur;
-			break;
-		}
-
-		if (!next) {
-			if (!cur)
-				return max;
-			next = dev_stack[--cur];
-			niter = iter_stack[cur];
-		}
-
-		now = next;
-		iter = niter;
-	}
-
-	return max;
-}
-#endif
-
 static int bond_get_stats(struct net_device *bond_dev,
 			  struct rtnl_link_stats64 *stats)
 {
 	struct bonding *bond = netdev_priv(bond_dev);
-	struct rtnl_link_stats64 temp;
-	struct list_head *iter;
-	struct slave *slave;
-	int nest_level = 0;
-	int res = 0;
+	struct rtnl_link_stats64 *dev_stats;
+	struct bonding_slave_dev *s;
+	struct list_head slaves;
+	int res, num_slaves;
+	int i = 0;
 
-	rcu_read_lock();
-#ifdef CONFIG_LOCKDEP
-	nest_level = bond_get_lowest_level_rcu(bond_dev);
-#endif
+	res = bond_get_slaves(bond, &slaves, &num_slaves);
+	if (res)
+		return res;
 
-	spin_lock_nested(&bond->stats_lock, nest_level);
-	memcpy(stats, &bond->bond_stats, sizeof(*stats));
+	dev_stats = kcalloc(num_slaves, sizeof(*dev_stats), GFP_KERNEL);
+	if (!dev_stats) {
+		bond_put_slaves(&slaves);
+		return -ENOMEM;
+	}
 
-	bond_for_each_slave_rcu(bond, slave, iter) {
-		res = dev_get_stats(slave->dev, &temp);
+	/* Recurse with no locks taken */
+	list_for_each_entry(s, &slaves, list) {
+		res = dev_get_stats(s->ndev, &dev_stats[i]);
 		if (res)
 			goto out;
+		i++;
+	}
+
+	spin_lock(&bond->stats_lock);
+
+	memcpy(stats, &bond->bond_stats, sizeof(*stats));
+
+	/* Because we released the RCU lock in bond_get_slaves, the new slave
+	 * array might be different from the original one, so we need to take
+	 * it again and only update the stats of the slaves that still exist.
+	 */
+	rcu_read_lock();
+
+	i = 0;
+
+	list_for_each_entry(s, &slaves, list) {
+		struct list_head *iter;
+		struct slave *slave;
 
-		bond_fold_stats(stats, &temp, &slave->slave_stats);
+		bond_for_each_slave_rcu(bond, slave, iter) {
+			if (slave->dev != s->ndev)
+				continue;
 
-		/* save off the slave stats for the next run */
-		memcpy(&slave->slave_stats, &temp, sizeof(temp));
+			bond_fold_stats(stats, &dev_stats[i],
+					&slave->slave_stats);
+
+			/* save off the slave stats for the next run */
+			memcpy(&slave->slave_stats, &dev_stats[i],
+			       sizeof(dev_stats[i]));
+			break;
+		}
+
+		i++;
 	}
 
+	rcu_read_unlock();
+
 	memcpy(&bond->bond_stats, stats, sizeof(*stats));
-out:
+
 	spin_unlock(&bond->stats_lock);
-	rcu_read_unlock();
+
+out:
+	kfree(dev_stats);
+	bond_put_slaves(&slaves);
 
 	return res;
 }
diff --git a/include/net/bonding.h b/include/net/bonding.h
index adc3da776970..2df1f7ea9036 100644
--- a/include/net/bonding.h
+++ b/include/net/bonding.h
@@ -449,6 +449,59 @@ static inline void bond_hw_addr_copy(u8 *dst, const u8 *src, unsigned int len)
 	memcpy(dst, src, len);
 }
 
+/* Helpers for reference counting the struct net_device behind the bond slaves.
+ * These can be used to propagate the net_device_ops from the bond to the
+ * slaves while not holding rcu_read_lock() or the rtnl_mutex.
+ */
+struct bonding_slave_dev {
+	struct net_device *ndev;
+	struct list_head list;
+};
+
+static inline void bond_put_slaves(struct list_head *slaves)
+{
+	struct bonding_slave_dev *s, *tmp;
+
+	list_for_each_entry_safe(s, tmp, slaves, list) {
+		dev_put(s->ndev);
+		list_del(&s->list);
+		kfree(s);
+	}
+}
+
+static inline int bond_get_slaves(struct bonding *bond,
+				  struct list_head *slaves,
+				  int *num_slaves)
+{
+	struct list_head *iter;
+	struct slave *slave;
+
+	INIT_LIST_HEAD(slaves);
+	*num_slaves = 0;
+
+	rcu_read_lock();
+
+	bond_for_each_slave_rcu(bond, slave, iter) {
+		struct bonding_slave_dev *s;
+
+		s = kzalloc(sizeof(*s), GFP_ATOMIC);
+		if (!s) {
+			rcu_read_unlock();
+			bond_put_slaves(slaves);
+			return -ENOMEM;
+		}
+
+		s->ndev = slave->dev;
+		dev_hold(s->ndev);
+		list_add_tail(&s->list, slaves);
+		(*num_slaves)++;
+	}
+
+	rcu_read_unlock();
+
+	return 0;
+}
+
 #define BOND_PRI_RESELECT_ALWAYS	0
 #define BOND_PRI_RESELECT_BETTER	1
 #define BOND_PRI_RESELECT_FAILURE	2
