Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c0f4ace7 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'bonding_rcu'



bonding: patchset for rcu use in bonding

====================
The Patch Set convert the xmit of 3ad and alb mode to use rcu lock.
dd rtnl lock and remove read lock for bond sysfs.

v2 because the bond_for_each_slave_rcu without rcu_read_lock() will occurs one warming, so
add new function for alb xmit path to avoid warming.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents da33edcc 4d1ae5fb
Loading
Loading
Loading
Loading
+4 −6
Original line number Diff line number Diff line
@@ -2344,7 +2344,7 @@ int __bond_3ad_get_active_agg_info(struct bonding *bond,
	struct slave *slave;
	struct port *port;

	bond_for_each_slave(bond, slave, iter) {
	bond_for_each_slave_rcu(bond, slave, iter) {
		port = &(SLAVE_AD_INFO(slave).port);
		if (port->aggregator && port->aggregator->is_active) {
			aggregator = port->aggregator;
@@ -2369,9 +2369,9 @@ int bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info)
{
	int ret;

	read_lock(&bond->lock);
	rcu_read_lock();
	ret = __bond_3ad_get_active_agg_info(bond, ad_info);
	read_unlock(&bond->lock);
	rcu_read_unlock();

	return ret;
}
@@ -2388,7 +2388,6 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
	int res = 1;
	int agg_id;

	read_lock(&bond->lock);
	if (__bond_3ad_get_active_agg_info(bond, &ad_info)) {
		pr_debug("%s: Error: __bond_3ad_get_active_agg_info failed\n",
			 dev->name);
@@ -2406,7 +2405,7 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
	slave_agg_no = bond_xmit_hash(bond, skb, slaves_in_agg);
	first_ok_slave = NULL;

	bond_for_each_slave(bond, slave, iter) {
	bond_for_each_slave_rcu(bond, slave, iter) {
		agg = SLAVE_AD_INFO(slave).port.aggregator;
		if (!agg || agg->aggregator_identifier != agg_id)
			continue;
@@ -2436,7 +2435,6 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
		res = bond_dev_queue_xmit(bond, skb, first_ok_slave->dev);

out:
	read_unlock(&bond->lock);
	if (res) {
		/* no suitable interface, frame not sent */
		kfree_skb(skb);
+43 −15
Original line number Diff line number Diff line
@@ -230,7 +230,7 @@ static struct slave *tlb_get_least_loaded_slave(struct bonding *bond)
	max_gap = LLONG_MIN;

	/* Find the slave with the largest gap */
	bond_for_each_slave(bond, slave, iter) {
	bond_for_each_slave_rcu(bond, slave, iter) {
		if (SLAVE_IS_OK(slave)) {
			long long gap = compute_gap(slave);

@@ -412,6 +412,39 @@ static struct slave *rlb_next_rx_slave(struct bonding *bond)
	return rx_slave;
}

/* Caller must hold rcu_read_lock() for read */
static struct slave *__rlb_next_rx_slave(struct bonding *bond)
{
	struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
	struct slave *before = NULL, *rx_slave = NULL, *slave;
	struct list_head *iter;
	bool found = false;

	bond_for_each_slave_rcu(bond, slave, iter) {
		if (!SLAVE_IS_OK(slave))
			continue;
		if (!found) {
			if (!before || before->speed < slave->speed)
				before = slave;
		} else {
			if (!rx_slave || rx_slave->speed < slave->speed)
				rx_slave = slave;
		}
		if (slave == bond_info->rx_slave)
			found = true;
	}
	/* we didn't find anything after the current or we have something
	 * better before and up to the current slave
	 */
	if (!rx_slave || (before && rx_slave->speed < before->speed))
		rx_slave = before;

	if (rx_slave)
		bond_info->rx_slave = rx_slave;

	return rx_slave;
}

/* teach the switch the mac of a disabled slave
 * on the primary for fault tolerance
 *
@@ -628,12 +661,14 @@ static struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bon
{
	struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
	struct arp_pkt *arp = arp_pkt(skb);
	struct slave *assigned_slave;
	struct slave *assigned_slave, *curr_active_slave;
	struct rlb_client_info *client_info;
	u32 hash_index = 0;

	_lock_rx_hashtbl(bond);

	curr_active_slave = rcu_dereference(bond->curr_active_slave);

	hash_index = _simple_hash((u8 *)&arp->ip_dst, sizeof(arp->ip_dst));
	client_info = &(bond_info->rx_hashtbl[hash_index]);

@@ -658,14 +693,14 @@ static struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bon
			 * that the new client can be assigned to this entry.
			 */
			if (bond->curr_active_slave &&
			    client_info->slave != bond->curr_active_slave) {
				client_info->slave = bond->curr_active_slave;
			    client_info->slave != curr_active_slave) {
				client_info->slave = curr_active_slave;
				rlb_update_client(client_info);
			}
		}
	}
	/* assign a new slave */
	assigned_slave = rlb_next_rx_slave(bond);
	assigned_slave = __rlb_next_rx_slave(bond);

	if (assigned_slave) {
		if (!(client_info->assigned &&
@@ -728,7 +763,7 @@ static struct slave *rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond)
	/* Don't modify or load balance ARPs that do not originate locally
	 * (e.g.,arrive via a bridge).
	 */
	if (!bond_slave_has_mac(bond, arp->mac_src))
	if (!bond_slave_has_mac_rcu(bond, arp->mac_src))
		return NULL;

	if (arp->op_code == htons(ARPOP_REPLY)) {
@@ -1343,11 +1378,6 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
	skb_reset_mac_header(skb);
	eth_data = eth_hdr(skb);

	/* make sure that the curr_active_slave do not change during tx
	 */
	read_lock(&bond->lock);
	read_lock(&bond->curr_slave_lock);

	switch (ntohs(skb->protocol)) {
	case ETH_P_IP: {
		const struct iphdr *iph = ip_hdr(skb);
@@ -1429,12 +1459,12 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)

	if (!tx_slave) {
		/* unbalanced or unassigned, send through primary */
		tx_slave = bond->curr_active_slave;
		tx_slave = rcu_dereference(bond->curr_active_slave);
		bond_info->unbalanced_load += skb->len;
	}

	if (tx_slave && SLAVE_IS_OK(tx_slave)) {
		if (tx_slave != bond->curr_active_slave) {
		if (tx_slave != rcu_dereference(bond->curr_active_slave)) {
			memcpy(eth_data->h_source,
			       tx_slave->dev->dev_addr,
			       ETH_ALEN);
@@ -1449,8 +1479,6 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
		}
	}

	read_unlock(&bond->curr_slave_lock);
	read_unlock(&bond->lock);
	if (res) {
		/* no suitable interface, frame not sent */
		kfree_skb(skb);
+17 −13
Original line number Diff line number Diff line
@@ -179,7 +179,9 @@ static ssize_t bonding_show_slaves(struct device *d,
	struct slave *slave;
	int res = 0;

	read_lock(&bond->lock);
	if (!rtnl_trylock())
		return restart_syscall();

	bond_for_each_slave(bond, slave, iter) {
		if (res > (PAGE_SIZE - IFNAMSIZ)) {
			/* not enough space for another interface name */
@@ -190,7 +192,9 @@ static ssize_t bonding_show_slaves(struct device *d,
		}
		res += sprintf(buf + res, "%s ", slave->dev->name);
	}
	read_unlock(&bond->lock);

	rtnl_unlock();

	if (res)
		buf[res-1] = '\n'; /* eat the leftover space */

@@ -626,6 +630,9 @@ static ssize_t bonding_store_arp_targets(struct device *d,
	unsigned long *targets_rx;
	int ind, i, j, ret = -EINVAL;

	if (!rtnl_trylock())
		return restart_syscall();

	targets = bond->params.arp_targets;
	newtarget = in_aton(buf + 1);
	/* look for adds */
@@ -699,6 +706,7 @@ static ssize_t bonding_store_arp_targets(struct device *d,

	ret = count;
out:
	rtnl_unlock();
	return ret;
}
static DEVICE_ATTR(arp_ip_target, S_IRUGO | S_IWUSR , bonding_show_arp_targets, bonding_store_arp_targets);
@@ -1467,7 +1475,6 @@ static ssize_t bonding_show_queue_id(struct device *d,
	if (!rtnl_trylock())
		return restart_syscall();

	read_lock(&bond->lock);
	bond_for_each_slave(bond, slave, iter) {
		if (res > (PAGE_SIZE - IFNAMSIZ - 6)) {
			/* not enough space for another interface_name:queue_id pair */
@@ -1479,9 +1486,9 @@ static ssize_t bonding_show_queue_id(struct device *d,
		res += sprintf(buf + res, "%s:%d ",
			       slave->dev->name, slave->queue_id);
	}
	read_unlock(&bond->lock);
	if (res)
		buf[res-1] = '\n'; /* eat the leftover space */

	rtnl_unlock();

	return res;
@@ -1530,8 +1537,6 @@ static ssize_t bonding_store_queue_id(struct device *d,
	if (!sdev)
		goto err_no_cmd;

	read_lock(&bond->lock);

	/* Search for thes slave and check for duplicate qids */
	update_slave = NULL;
	bond_for_each_slave(bond, slave, iter) {
@@ -1542,23 +1547,20 @@ static ssize_t bonding_store_queue_id(struct device *d,
			 */
			update_slave = slave;
		else if (qid && qid == slave->queue_id) {
			goto err_no_cmd_unlock;
			goto err_no_cmd;
		}
	}

	if (!update_slave)
		goto err_no_cmd_unlock;
		goto err_no_cmd;

	/* Actually set the qids for the slave */
	update_slave->queue_id = qid;

	read_unlock(&bond->lock);
out:
	rtnl_unlock();
	return ret;

err_no_cmd_unlock:
	read_unlock(&bond->lock);
err_no_cmd:
	pr_info("invalid input for queue_id set for %s.\n",
		bond->dev->name);
@@ -1591,6 +1593,9 @@ static ssize_t bonding_store_slaves_active(struct device *d,
	struct list_head *iter;
	struct slave *slave;

	if (!rtnl_trylock())
		return restart_syscall();

	if (sscanf(buf, "%d", &new_value) != 1) {
		pr_err("%s: no all_slaves_active value specified.\n",
		       bond->dev->name);
@@ -1610,7 +1615,6 @@ static ssize_t bonding_store_slaves_active(struct device *d,
		goto out;
	}

	read_lock(&bond->lock);
	bond_for_each_slave(bond, slave, iter) {
		if (!bond_is_active_slave(slave)) {
			if (new_value)
@@ -1619,8 +1623,8 @@ static ssize_t bonding_store_slaves_active(struct device *d,
				slave->inactive = 1;
		}
	}
	read_unlock(&bond->lock);
out:
	rtnl_unlock();
	return ret;
}
static DEVICE_ATTR(all_slaves_active, S_IRUGO | S_IWUSR,
+14 −0
Original line number Diff line number Diff line
@@ -464,6 +464,20 @@ static inline struct slave *bond_slave_has_mac(struct bonding *bond,
	return NULL;
}

/* Caller must hold rcu_read_lock() for read */
static inline struct slave *bond_slave_has_mac_rcu(struct bonding *bond,
					       const u8 *mac)
{
	struct list_head *iter;
	struct slave *tmp;

	bond_for_each_slave_rcu(bond, tmp, iter)
		if (ether_addr_equal_64bits(mac, tmp->dev->dev_addr))
			return tmp;

	return NULL;
}

/* Check if the ip is present in arp ip list, or first free slot if ip == 0
 * Returns -1 if not found, index if found
 */