Skip to content

Commit

Permalink
Merge branch 'bond_rcu'
Browse files Browse the repository at this point in the history
Nikolay Aleksandrov says:

====================
 This patchset aims to lay the groundwork, and do the initial conversion to
RCUism. I decided that it'll be much better to make the bonding RCU
conversion gradual, so patches can be reviewed and tested better rather
than having one huge patch (which I did in the beginning, before this).
The first patch is straightforward and it converts the bonding to the
standard list API, simplifying a lot of code, removing unnecessary local
variables and allowing to use the nice rculist API later. It also takes
care of some minor styling issues (re-arranging local variables longest ->
shortest, removing brackets for single statement if/else, leaving new line
before return statement etc.).
 The second patch simplifies the conversion by removing unnecessary
read_lock(&bond->curr_slave_lock) in xmit paths that are to be converted
later, because we only care if the pointer is NULL or a slave there, since
we already have bond->lock the slave can't go away.
 The third patch simplifies the broadcast xmit function by removing
the use of curr_active_slave and converting to standard list API. Also this
design of the broadcast xmit function avoids a subtle double packet tx race
when converted to RCU.
 The fourth patch factors out the code that transmits skb through a slave
with given id (i.e. rr_tx_counter in rr mode, hashed value in xor mode) and
simplifies the active-backup xmit path because bond_dev_queue_xmit always
consumes the skb. The new bond_xmit_slave_id function is used in rr and xor
modes currently, but the plans are to use it in 3ad mode as well thus it's
made global. I've left the function prototype to be 81 chars so I wouldn't
break it, if this is an issue I can always break it in more lines.
 The fifth patch introduces RCU by converting attach/detach and release to
RCU. It also converts dereferencing of curr_active_slave to rcu_dereference
although it's not fully converted to RCU, that is needed for the converted
xmit paths. And it converts roundrobin, broadcast, xor and active-backup
xmit paths to RCU. The 3ad and ALB/TLB modes acquire read_lock(&bond->lock)
to make sure that no slave will be removed and to sync properly with
enslave and release as before.
 This way for the price of a little complexity, we'll be able to convert
individual parts of the bonding to RCU, and test them easier in the
process. If this patchset is accepted in some form, I'll post followups
in the next weeks that gradually convert the bonding to RCU and remove the
need for the rwlocks.
 For performance notes please refer to patch 5 (RCU conversion one).
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Aug 1, 2013
2 parents 439677d + 278b208 commit a594e4f
Show file tree
Hide file tree
Showing 6 changed files with 310 additions and 383 deletions.
44 changes: 28 additions & 16 deletions drivers/net/bonding/bond_3ad.c
Original file line number Diff line number Diff line change
Expand Up @@ -143,10 +143,9 @@ static inline struct bonding *__get_bond_by_port(struct port *port)
*/
static inline struct port *__get_first_port(struct bonding *bond)
{
if (bond->slave_cnt == 0)
return NULL;
struct slave *first_slave = bond_first_slave(bond);

return &(SLAVE_AD_INFO(bond->first_slave).port);
return first_slave ? &(SLAVE_AD_INFO(first_slave).port) : NULL;
}

/**
Expand All @@ -159,13 +158,16 @@ static inline struct port *__get_first_port(struct bonding *bond)
static inline struct port *__get_next_port(struct port *port)
{
struct bonding *bond = __get_bond_by_port(port);
struct slave *slave = port->slave;
struct slave *slave = port->slave, *slave_next;

// If there's no bond for this port, or this is the last slave
if ((bond == NULL) || (slave->next == bond->first_slave))
if (bond == NULL)
return NULL;
slave_next = bond_next_slave(bond, slave);
if (!slave_next || bond_is_first_slave(bond, slave_next))
return NULL;

return &(SLAVE_AD_INFO(slave->next).port);
return &(SLAVE_AD_INFO(slave_next).port);
}

/**
Expand All @@ -178,12 +180,14 @@ static inline struct port *__get_next_port(struct port *port)
static inline struct aggregator *__get_first_agg(struct port *port)
{
struct bonding *bond = __get_bond_by_port(port);
struct slave *first_slave;

// If there's no bond for this port, or bond has no slaves
if ((bond == NULL) || (bond->slave_cnt == 0))
if (bond == NULL)
return NULL;
first_slave = bond_first_slave(bond);

return &(SLAVE_AD_INFO(bond->first_slave).aggregator);
return first_slave ? &(SLAVE_AD_INFO(first_slave).aggregator) : NULL;
}

/**
Expand All @@ -195,14 +199,17 @@ static inline struct aggregator *__get_first_agg(struct port *port)
*/
static inline struct aggregator *__get_next_agg(struct aggregator *aggregator)
{
struct slave *slave = aggregator->slave;
struct slave *slave = aggregator->slave, *slave_next;
struct bonding *bond = bond_get_bond_by_slave(slave);

// If there's no bond for this aggregator, or this is the last slave
if ((bond == NULL) || (slave->next == bond->first_slave))
if (bond == NULL)
return NULL;
slave_next = bond_next_slave(bond, slave);
if (!slave_next || bond_is_first_slave(bond, slave_next))
return NULL;

return &(SLAVE_AD_INFO(slave->next).aggregator);
return &(SLAVE_AD_INFO(slave_next).aggregator);
}

/*
Expand Down Expand Up @@ -2110,7 +2117,7 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
read_lock(&bond->lock);

//check if there are any slaves
if (bond->slave_cnt == 0)
if (list_empty(&bond->slave_list))
goto re_arm;

// check if agg_select_timer timer after initialize is timed out
Expand Down Expand Up @@ -2336,8 +2343,12 @@ void bond_3ad_handle_link_change(struct slave *slave, char link)
int bond_3ad_set_carrier(struct bonding *bond)
{
struct aggregator *active;
struct slave *first_slave;

active = __get_active_agg(&(SLAVE_AD_INFO(bond->first_slave).aggregator));
first_slave = bond_first_slave(bond);
if (!first_slave)
return 0;
active = __get_active_agg(&(SLAVE_AD_INFO(first_slave).aggregator));
if (active) {
/* are enough slaves available to consider link up? */
if (active->num_of_ports < bond->params.min_links) {
Expand Down Expand Up @@ -2415,6 +2426,7 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
struct ad_info ad_info;
int res = 1;

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);
Expand All @@ -2432,7 +2444,7 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)

slave_agg_no = bond->xmit_hash_policy(skb, slaves_in_agg);

bond_for_each_slave(bond, slave, i) {
bond_for_each_slave(bond, slave) {
struct aggregator *agg = SLAVE_AD_INFO(slave).port.aggregator;

if (agg && (agg->aggregator_identifier == agg_id)) {
Expand Down Expand Up @@ -2464,6 +2476,7 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
}

out:
read_unlock(&bond->lock);
if (res) {
/* no suitable interface, frame not sent */
kfree_skb(skb);
Expand Down Expand Up @@ -2501,15 +2514,14 @@ int bond_3ad_lacpdu_recv(const struct sk_buff *skb, struct bonding *bond,
*/
void bond_3ad_update_lacp_rate(struct bonding *bond)
{
int i;
struct slave *slave;
struct port *port = NULL;
int lacp_fast;

write_lock_bh(&bond->lock);
lacp_fast = bond->params.lacp_fast;

bond_for_each_slave(bond, slave, i) {
bond_for_each_slave(bond, slave) {
port = &(SLAVE_AD_INFO(slave).port);
if (port->slave == NULL)
continue;
Expand Down
57 changes: 24 additions & 33 deletions drivers/net/bonding/bond_alb.c
Original file line number Diff line number Diff line change
Expand Up @@ -224,13 +224,12 @@ static struct slave *tlb_get_least_loaded_slave(struct bonding *bond)
{
struct slave *slave, *least_loaded;
long long max_gap;
int i;

least_loaded = NULL;
max_gap = LLONG_MIN;

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

Expand Down Expand Up @@ -386,11 +385,10 @@ static struct slave *rlb_next_rx_slave(struct bonding *bond)
struct slave *rx_slave, *slave, *start_at;
int i = 0;

if (bond_info->next_rx_slave) {
if (bond_info->next_rx_slave)
start_at = bond_info->next_rx_slave;
} else {
start_at = bond->first_slave;
}
else
start_at = bond_first_slave(bond);

rx_slave = NULL;

Expand All @@ -405,7 +403,8 @@ static struct slave *rlb_next_rx_slave(struct bonding *bond)
}

if (rx_slave) {
bond_info->next_rx_slave = rx_slave->next;
slave = bond_next_slave(bond, rx_slave);
bond_info->next_rx_slave = slave;
}

return rx_slave;
Expand Down Expand Up @@ -1173,9 +1172,8 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav
{
struct slave *tmp_slave1, *free_mac_slave = NULL;
struct slave *has_bond_addr = bond->curr_active_slave;
int i;

if (bond->slave_cnt == 0) {
if (list_empty(&bond->slave_list)) {
/* this is the first slave */
return 0;
}
Expand All @@ -1196,7 +1194,7 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav
/* The slave's address is equal to the address of the bond.
* Search for a spare address in the bond for this slave.
*/
bond_for_each_slave(bond, tmp_slave1, i) {
bond_for_each_slave(bond, tmp_slave1) {
if (!bond_slave_has_mac(bond, tmp_slave1->perm_hwaddr)) {
/* no slave has tmp_slave1's perm addr
* as its curr addr
Expand Down Expand Up @@ -1246,17 +1244,15 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav
*/
static int alb_set_mac_address(struct bonding *bond, void *addr)
{
struct sockaddr sa;
struct slave *slave, *stop_at;
char tmp_addr[ETH_ALEN];
struct slave *slave;
struct sockaddr sa;
int res;
int i;

if (bond->alb_info.rlb_enabled) {
if (bond->alb_info.rlb_enabled)
return 0;
}

bond_for_each_slave(bond, slave, i) {
bond_for_each_slave(bond, slave) {
/* save net_device's current hw address */
memcpy(tmp_addr, slave->dev->dev_addr, ETH_ALEN);

Expand All @@ -1276,8 +1272,7 @@ static int alb_set_mac_address(struct bonding *bond, void *addr)
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) {
memcpy(tmp_addr, slave->dev->dev_addr, ETH_ALEN);
dev_set_mac_address(slave->dev, &sa);
memcpy(slave->dev->dev_addr, tmp_addr, ETH_ALEN);
Expand Down Expand Up @@ -1342,6 +1337,7 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)

/* 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)) {
Expand Down Expand Up @@ -1446,11 +1442,12 @@ 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);
}

return NETDEV_TX_OK;
}

Expand All @@ -1460,11 +1457,10 @@ void bond_alb_monitor(struct work_struct *work)
alb_work.work);
struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
struct slave *slave;
int i;

read_lock(&bond->lock);

if (bond->slave_cnt == 0) {
if (list_empty(&bond->slave_list)) {
bond_info->tx_rebalance_counter = 0;
bond_info->lp_counter = 0;
goto re_arm;
Expand All @@ -1482,9 +1478,8 @@ void bond_alb_monitor(struct work_struct *work)
*/
read_lock(&bond->curr_slave_lock);

bond_for_each_slave(bond, slave, i) {
bond_for_each_slave(bond, slave)
alb_send_learning_packets(slave, slave->dev->dev_addr);
}

read_unlock(&bond->curr_slave_lock);

Expand All @@ -1496,7 +1491,7 @@ void bond_alb_monitor(struct work_struct *work)

read_lock(&bond->curr_slave_lock);

bond_for_each_slave(bond, slave, i) {
bond_for_each_slave(bond, slave) {
tlb_clear_slave(bond, slave, 1);
if (slave == bond->curr_active_slave) {
SLAVE_TLB_INFO(slave).load =
Expand Down Expand Up @@ -1602,9 +1597,8 @@ int bond_alb_init_slave(struct bonding *bond, struct slave *slave)
*/
void bond_alb_deinit_slave(struct bonding *bond, struct slave *slave)
{
if (bond->slave_cnt > 1) {
if (!list_empty(&bond->slave_list))
alb_change_hw_addr_on_detach(bond, slave);
}

tlb_clear_slave(bond, slave, 0);

Expand Down Expand Up @@ -1661,9 +1655,8 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave
{
struct slave *swap_slave;

if (bond->curr_active_slave == new_slave) {
if (bond->curr_active_slave == new_slave)
return;
}

if (bond->curr_active_slave && bond->alb_info.primary_is_promisc) {
dev_set_promiscuity(bond->curr_active_slave->dev, -1);
Expand All @@ -1672,11 +1665,10 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave
}

swap_slave = bond->curr_active_slave;
bond->curr_active_slave = new_slave;
rcu_assign_pointer(bond->curr_active_slave, new_slave);

if (!new_slave || (bond->slave_cnt == 0)) {
if (!new_slave || list_empty(&bond->slave_list))
return;
}

/* set the new curr_active_slave to the bonds mac address
* i.e. swap mac addresses of old curr_active_slave and new curr_active_slave
Expand All @@ -1689,9 +1681,8 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave
* ignored so we can mess with their MAC addresses without
* fear of interference from transmit activity.
*/
if (swap_slave) {
if (swap_slave)
tlb_clear_slave(bond, swap_slave, 1);
}
tlb_clear_slave(bond, new_slave, 1);

write_unlock_bh(&bond->curr_slave_lock);
Expand Down
Loading

0 comments on commit a594e4f

Please sign in to comment.