提交 c0f4ace7 编写于 作者: D David S. Miller

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: NDavid S. Miller <davem@davemloft.net>
...@@ -2344,7 +2344,7 @@ int __bond_3ad_get_active_agg_info(struct bonding *bond, ...@@ -2344,7 +2344,7 @@ int __bond_3ad_get_active_agg_info(struct bonding *bond,
struct slave *slave; struct slave *slave;
struct port *port; struct port *port;
bond_for_each_slave(bond, slave, iter) { bond_for_each_slave_rcu(bond, slave, iter) {
port = &(SLAVE_AD_INFO(slave).port); port = &(SLAVE_AD_INFO(slave).port);
if (port->aggregator && port->aggregator->is_active) { if (port->aggregator && port->aggregator->is_active) {
aggregator = port->aggregator; aggregator = port->aggregator;
...@@ -2369,9 +2369,9 @@ int bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info) ...@@ -2369,9 +2369,9 @@ int bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info)
{ {
int ret; int ret;
read_lock(&bond->lock); rcu_read_lock();
ret = __bond_3ad_get_active_agg_info(bond, ad_info); ret = __bond_3ad_get_active_agg_info(bond, ad_info);
read_unlock(&bond->lock); rcu_read_unlock();
return ret; return ret;
} }
...@@ -2388,7 +2388,6 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev) ...@@ -2388,7 +2388,6 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
int res = 1; int res = 1;
int agg_id; int agg_id;
read_lock(&bond->lock);
if (__bond_3ad_get_active_agg_info(bond, &ad_info)) { if (__bond_3ad_get_active_agg_info(bond, &ad_info)) {
pr_debug("%s: Error: __bond_3ad_get_active_agg_info failed\n", pr_debug("%s: Error: __bond_3ad_get_active_agg_info failed\n",
dev->name); dev->name);
...@@ -2406,7 +2405,7 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev) ...@@ -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); slave_agg_no = bond_xmit_hash(bond, skb, slaves_in_agg);
first_ok_slave = NULL; 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; agg = SLAVE_AD_INFO(slave).port.aggregator;
if (!agg || agg->aggregator_identifier != agg_id) if (!agg || agg->aggregator_identifier != agg_id)
continue; continue;
...@@ -2436,7 +2435,6 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev) ...@@ -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); res = bond_dev_queue_xmit(bond, skb, first_ok_slave->dev);
out: out:
read_unlock(&bond->lock);
if (res) { if (res) {
/* no suitable interface, frame not sent */ /* no suitable interface, frame not sent */
kfree_skb(skb); kfree_skb(skb);
......
...@@ -230,7 +230,7 @@ static struct slave *tlb_get_least_loaded_slave(struct bonding *bond) ...@@ -230,7 +230,7 @@ static struct slave *tlb_get_least_loaded_slave(struct bonding *bond)
max_gap = LLONG_MIN; max_gap = LLONG_MIN;
/* Find the slave with the largest gap */ /* 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)) { if (SLAVE_IS_OK(slave)) {
long long gap = compute_gap(slave); long long gap = compute_gap(slave);
...@@ -412,6 +412,39 @@ static struct slave *rlb_next_rx_slave(struct bonding *bond) ...@@ -412,6 +412,39 @@ static struct slave *rlb_next_rx_slave(struct bonding *bond)
return rx_slave; 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 /* teach the switch the mac of a disabled slave
* on the primary for fault tolerance * on the primary for fault tolerance
* *
...@@ -628,12 +661,14 @@ static struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bon ...@@ -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 alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
struct arp_pkt *arp = arp_pkt(skb); struct arp_pkt *arp = arp_pkt(skb);
struct slave *assigned_slave; struct slave *assigned_slave, *curr_active_slave;
struct rlb_client_info *client_info; struct rlb_client_info *client_info;
u32 hash_index = 0; u32 hash_index = 0;
_lock_rx_hashtbl(bond); _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)); hash_index = _simple_hash((u8 *)&arp->ip_dst, sizeof(arp->ip_dst));
client_info = &(bond_info->rx_hashtbl[hash_index]); 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 ...@@ -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. * that the new client can be assigned to this entry.
*/ */
if (bond->curr_active_slave && if (bond->curr_active_slave &&
client_info->slave != bond->curr_active_slave) { client_info->slave != curr_active_slave) {
client_info->slave = bond->curr_active_slave; client_info->slave = curr_active_slave;
rlb_update_client(client_info); rlb_update_client(client_info);
} }
} }
} }
/* assign a new slave */ /* assign a new slave */
assigned_slave = rlb_next_rx_slave(bond); assigned_slave = __rlb_next_rx_slave(bond);
if (assigned_slave) { if (assigned_slave) {
if (!(client_info->assigned && if (!(client_info->assigned &&
...@@ -728,7 +763,7 @@ static struct slave *rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond) ...@@ -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 /* Don't modify or load balance ARPs that do not originate locally
* (e.g.,arrive via a bridge). * (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; return NULL;
if (arp->op_code == htons(ARPOP_REPLY)) { if (arp->op_code == htons(ARPOP_REPLY)) {
...@@ -1343,11 +1378,6 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) ...@@ -1343,11 +1378,6 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
skb_reset_mac_header(skb); skb_reset_mac_header(skb);
eth_data = eth_hdr(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)) { switch (ntohs(skb->protocol)) {
case ETH_P_IP: { case ETH_P_IP: {
const struct iphdr *iph = ip_hdr(skb); const struct iphdr *iph = ip_hdr(skb);
...@@ -1429,12 +1459,12 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) ...@@ -1429,12 +1459,12 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
if (!tx_slave) { if (!tx_slave) {
/* unbalanced or unassigned, send through primary */ /* 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; bond_info->unbalanced_load += skb->len;
} }
if (tx_slave && SLAVE_IS_OK(tx_slave)) { 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, memcpy(eth_data->h_source,
tx_slave->dev->dev_addr, tx_slave->dev->dev_addr,
ETH_ALEN); ETH_ALEN);
...@@ -1449,8 +1479,6 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) ...@@ -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) { if (res) {
/* no suitable interface, frame not sent */ /* no suitable interface, frame not sent */
kfree_skb(skb); kfree_skb(skb);
......
...@@ -179,7 +179,9 @@ static ssize_t bonding_show_slaves(struct device *d, ...@@ -179,7 +179,9 @@ static ssize_t bonding_show_slaves(struct device *d,
struct slave *slave; struct slave *slave;
int res = 0; int res = 0;
read_lock(&bond->lock); if (!rtnl_trylock())
return restart_syscall();
bond_for_each_slave(bond, slave, iter) { bond_for_each_slave(bond, slave, iter) {
if (res > (PAGE_SIZE - IFNAMSIZ)) { if (res > (PAGE_SIZE - IFNAMSIZ)) {
/* not enough space for another interface name */ /* not enough space for another interface name */
...@@ -190,7 +192,9 @@ static ssize_t bonding_show_slaves(struct device *d, ...@@ -190,7 +192,9 @@ static ssize_t bonding_show_slaves(struct device *d,
} }
res += sprintf(buf + res, "%s ", slave->dev->name); res += sprintf(buf + res, "%s ", slave->dev->name);
} }
read_unlock(&bond->lock);
rtnl_unlock();
if (res) if (res)
buf[res-1] = '\n'; /* eat the leftover space */ buf[res-1] = '\n'; /* eat the leftover space */
...@@ -626,6 +630,9 @@ static ssize_t bonding_store_arp_targets(struct device *d, ...@@ -626,6 +630,9 @@ static ssize_t bonding_store_arp_targets(struct device *d,
unsigned long *targets_rx; unsigned long *targets_rx;
int ind, i, j, ret = -EINVAL; int ind, i, j, ret = -EINVAL;
if (!rtnl_trylock())
return restart_syscall();
targets = bond->params.arp_targets; targets = bond->params.arp_targets;
newtarget = in_aton(buf + 1); newtarget = in_aton(buf + 1);
/* look for adds */ /* look for adds */
...@@ -699,6 +706,7 @@ static ssize_t bonding_store_arp_targets(struct device *d, ...@@ -699,6 +706,7 @@ static ssize_t bonding_store_arp_targets(struct device *d,
ret = count; ret = count;
out: out:
rtnl_unlock();
return ret; return ret;
} }
static DEVICE_ATTR(arp_ip_target, S_IRUGO | S_IWUSR , bonding_show_arp_targets, bonding_store_arp_targets); 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, ...@@ -1467,7 +1475,6 @@ static ssize_t bonding_show_queue_id(struct device *d,
if (!rtnl_trylock()) if (!rtnl_trylock())
return restart_syscall(); return restart_syscall();
read_lock(&bond->lock);
bond_for_each_slave(bond, slave, iter) { bond_for_each_slave(bond, slave, iter) {
if (res > (PAGE_SIZE - IFNAMSIZ - 6)) { if (res > (PAGE_SIZE - IFNAMSIZ - 6)) {
/* not enough space for another interface_name:queue_id pair */ /* not enough space for another interface_name:queue_id pair */
...@@ -1479,9 +1486,9 @@ static ssize_t bonding_show_queue_id(struct device *d, ...@@ -1479,9 +1486,9 @@ static ssize_t bonding_show_queue_id(struct device *d,
res += sprintf(buf + res, "%s:%d ", res += sprintf(buf + res, "%s:%d ",
slave->dev->name, slave->queue_id); slave->dev->name, slave->queue_id);
} }
read_unlock(&bond->lock);
if (res) if (res)
buf[res-1] = '\n'; /* eat the leftover space */ buf[res-1] = '\n'; /* eat the leftover space */
rtnl_unlock(); rtnl_unlock();
return res; return res;
...@@ -1530,8 +1537,6 @@ static ssize_t bonding_store_queue_id(struct device *d, ...@@ -1530,8 +1537,6 @@ static ssize_t bonding_store_queue_id(struct device *d,
if (!sdev) if (!sdev)
goto err_no_cmd; goto err_no_cmd;
read_lock(&bond->lock);
/* Search for thes slave and check for duplicate qids */ /* Search for thes slave and check for duplicate qids */
update_slave = NULL; update_slave = NULL;
bond_for_each_slave(bond, slave, iter) { bond_for_each_slave(bond, slave, iter) {
...@@ -1542,23 +1547,20 @@ static ssize_t bonding_store_queue_id(struct device *d, ...@@ -1542,23 +1547,20 @@ static ssize_t bonding_store_queue_id(struct device *d,
*/ */
update_slave = slave; update_slave = slave;
else if (qid && qid == slave->queue_id) { else if (qid && qid == slave->queue_id) {
goto err_no_cmd_unlock; goto err_no_cmd;
} }
} }
if (!update_slave) if (!update_slave)
goto err_no_cmd_unlock; goto err_no_cmd;
/* Actually set the qids for the slave */ /* Actually set the qids for the slave */
update_slave->queue_id = qid; update_slave->queue_id = qid;
read_unlock(&bond->lock);
out: out:
rtnl_unlock(); rtnl_unlock();
return ret; return ret;
err_no_cmd_unlock:
read_unlock(&bond->lock);
err_no_cmd: err_no_cmd:
pr_info("invalid input for queue_id set for %s.\n", pr_info("invalid input for queue_id set for %s.\n",
bond->dev->name); bond->dev->name);
...@@ -1591,6 +1593,9 @@ static ssize_t bonding_store_slaves_active(struct device *d, ...@@ -1591,6 +1593,9 @@ static ssize_t bonding_store_slaves_active(struct device *d,
struct list_head *iter; struct list_head *iter;
struct slave *slave; struct slave *slave;
if (!rtnl_trylock())
return restart_syscall();
if (sscanf(buf, "%d", &new_value) != 1) { if (sscanf(buf, "%d", &new_value) != 1) {
pr_err("%s: no all_slaves_active value specified.\n", pr_err("%s: no all_slaves_active value specified.\n",
bond->dev->name); bond->dev->name);
...@@ -1610,7 +1615,6 @@ static ssize_t bonding_store_slaves_active(struct device *d, ...@@ -1610,7 +1615,6 @@ static ssize_t bonding_store_slaves_active(struct device *d,
goto out; goto out;
} }
read_lock(&bond->lock);
bond_for_each_slave(bond, slave, iter) { bond_for_each_slave(bond, slave, iter) {
if (!bond_is_active_slave(slave)) { if (!bond_is_active_slave(slave)) {
if (new_value) if (new_value)
...@@ -1619,8 +1623,8 @@ static ssize_t bonding_store_slaves_active(struct device *d, ...@@ -1619,8 +1623,8 @@ static ssize_t bonding_store_slaves_active(struct device *d,
slave->inactive = 1; slave->inactive = 1;
} }
} }
read_unlock(&bond->lock);
out: out:
rtnl_unlock();
return ret; return ret;
} }
static DEVICE_ATTR(all_slaves_active, S_IRUGO | S_IWUSR, static DEVICE_ATTR(all_slaves_active, S_IRUGO | S_IWUSR,
......
...@@ -464,6 +464,20 @@ static inline struct slave *bond_slave_has_mac(struct bonding *bond, ...@@ -464,6 +464,20 @@ static inline struct slave *bond_slave_has_mac(struct bonding *bond,
return NULL; 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 /* 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 * Returns -1 if not found, index if found
*/ */
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册