mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-06-15 11:08:07 +00:00
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: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
c0f4ace79e
4 changed files with 78 additions and 34 deletions
|
@ -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)
|
||||||
{
|
{
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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
|
||||||
{
|
{
|
||||||
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
|
||||||
* 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)
|
||||||
/* 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)
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
||||||
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,
|
||||||
}
|
}
|
||||||
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,
|
||||||
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,
|
||||||
|
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
*/
|
*/
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Add table
Reference in a new issue