Skip to content

Commit 278b208

Browse files
nikolay@redhat.comdavem330
authored andcommitted
bonding: initial RCU conversion
This patch does the initial bonding conversion to RCU. After it the following modes are protected by RCU alone: roundrobin, active-backup, broadcast and xor. Modes ALB/TLB and 3ad still acquire bond->lock for reading, and will be dealt with later. curr_active_slave needs to be dereferenced via rcu in the converted modes because the only thing protecting the slave after this patch is rcu_read_lock, so we need the proper barrier for weakly ordered archs and to make sure we don't have stale pointer. It's not tagged with __rcu yet because there's still work to be done to remove the curr_slave_lock, so sparse will complain when rcu_assign_pointer and rcu_dereference are used, but the alternative to use rcu_dereference_protected would've created much bigger code churn which is more difficult to test and review. That will be converted in time. 1. Active-backup mode 1.1 Perf recording while doing iperf -P 4 - old bonding: iperf spent 0.55% in bonding, system spent 0.29% CPU in bonding - new bonding: iperf spent 0.29% in bonding, system spent 0.15% CPU in bonding 1.2. Bandwidth measurements - old bonding: 16.1 gbps consistently - new bonding: 17.5 gbps consistently 2. Round-robin mode 2.1 Perf recording while doing iperf -P 4 - old bonding: iperf spent 0.51% in bonding, system spent 0.24% CPU in bonding - new bonding: iperf spent 0.16% in bonding, system spent 0.11% CPU in bonding 2.2 Bandwidth measurements - old bonding: 8 gbps (variable due to packet reorderings) - new bonding: 10 gbps (variable due to packet reorderings) Of course the latency has improved in all converted modes, and moreover while doing enslave/release (since it doesn't affect tx anymore). Also I've stress tested all modes doing enslave/release in a loop while transmitting traffic. Signed-off-by: Nikolay Aleksandrov <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 1507722 commit 278b208

File tree

5 files changed

+32
-29
lines changed

5 files changed

+32
-29
lines changed

drivers/net/bonding/bond_3ad.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2426,6 +2426,7 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
24262426
struct ad_info ad_info;
24272427
int res = 1;
24282428

2429+
read_lock(&bond->lock);
24292430
if (__bond_3ad_get_active_agg_info(bond, &ad_info)) {
24302431
pr_debug("%s: Error: __bond_3ad_get_active_agg_info failed\n",
24312432
dev->name);
@@ -2475,6 +2476,7 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
24752476
}
24762477

24772478
out:
2479+
read_unlock(&bond->lock);
24782480
if (res) {
24792481
/* no suitable interface, frame not sent */
24802482
kfree_skb(skb);

drivers/net/bonding/bond_alb.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1337,6 +1337,7 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
13371337

13381338
/* make sure that the curr_active_slave do not change during tx
13391339
*/
1340+
read_lock(&bond->lock);
13401341
read_lock(&bond->curr_slave_lock);
13411342

13421343
switch (ntohs(skb->protocol)) {
@@ -1441,11 +1442,12 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
14411442
}
14421443

14431444
read_unlock(&bond->curr_slave_lock);
1444-
1445+
read_unlock(&bond->lock);
14451446
if (res) {
14461447
/* no suitable interface, frame not sent */
14471448
kfree_skb(skb);
14481449
}
1450+
14491451
return NETDEV_TX_OK;
14501452
}
14511453

@@ -1663,7 +1665,7 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave
16631665
}
16641666

16651667
swap_slave = bond->curr_active_slave;
1666-
bond->curr_active_slave = new_slave;
1668+
rcu_assign_pointer(bond->curr_active_slave, new_slave);
16671669

16681670
if (!new_slave || list_empty(&bond->slave_list))
16691671
return;

drivers/net/bonding/bond_main.c

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@
7777
#include <net/net_namespace.h>
7878
#include <net/netns/generic.h>
7979
#include <net/pkt_sched.h>
80+
#include <linux/rculist.h>
8081
#include "bonding.h"
8182
#include "bond_3ad.h"
8283
#include "bond_alb.h"
@@ -1037,7 +1038,7 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
10371038
if (new_active)
10381039
bond_set_slave_active_flags(new_active);
10391040
} else {
1040-
bond->curr_active_slave = new_active;
1041+
rcu_assign_pointer(bond->curr_active_slave, new_active);
10411042
}
10421043

10431044
if (bond->params.mode == BOND_MODE_ACTIVEBACKUP) {
@@ -1127,7 +1128,7 @@ void bond_select_active_slave(struct bonding *bond)
11271128
*/
11281129
static void bond_attach_slave(struct bonding *bond, struct slave *new_slave)
11291130
{
1130-
list_add_tail(&new_slave->list, &bond->slave_list);
1131+
list_add_tail_rcu(&new_slave->list, &bond->slave_list);
11311132
bond->slave_cnt++;
11321133
}
11331134

@@ -1143,7 +1144,7 @@ static void bond_attach_slave(struct bonding *bond, struct slave *new_slave)
11431144
*/
11441145
static void bond_detach_slave(struct bonding *bond, struct slave *slave)
11451146
{
1146-
list_del(&slave->list);
1147+
list_del_rcu(&slave->list);
11471148
bond->slave_cnt--;
11481149
}
11491150

@@ -1751,7 +1752,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
17511752
* so we can change it without calling change_active_interface()
17521753
*/
17531754
if (!bond->curr_active_slave && new_slave->link == BOND_LINK_UP)
1754-
bond->curr_active_slave = new_slave;
1755+
rcu_assign_pointer(bond->curr_active_slave, new_slave);
17551756

17561757
break;
17571758
} /* switch(bond_mode) */
@@ -1951,7 +1952,7 @@ static int __bond_release_one(struct net_device *bond_dev,
19511952
}
19521953

19531954
if (all) {
1954-
bond->curr_active_slave = NULL;
1955+
rcu_assign_pointer(bond->curr_active_slave, NULL);
19551956
} else if (oldcurrent == slave) {
19561957
/*
19571958
* Note that we hold RTNL over this sequence, so there
@@ -1983,6 +1984,7 @@ static int __bond_release_one(struct net_device *bond_dev,
19831984

19841985
write_unlock_bh(&bond->lock);
19851986
unblock_netpoll_tx();
1987+
synchronize_rcu();
19861988

19871989
if (list_empty(&bond->slave_list)) {
19881990
call_netdevice_notifiers(NETDEV_CHANGEADDR, bond->dev);
@@ -3811,7 +3813,7 @@ void bond_xmit_slave_id(struct bonding *bond, struct sk_buff *skb, int slave_id)
38113813
int i = slave_id;
38123814

38133815
/* Here we start from the slave with slave_id */
3814-
bond_for_each_slave(bond, slave) {
3816+
bond_for_each_slave_rcu(bond, slave) {
38153817
if (--i < 0) {
38163818
if (slave_can_tx(slave)) {
38173819
bond_dev_queue_xmit(bond, skb, slave->dev);
@@ -3822,7 +3824,7 @@ void bond_xmit_slave_id(struct bonding *bond, struct sk_buff *skb, int slave_id)
38223824

38233825
/* Here we start from the first slave up to slave_id */
38243826
i = slave_id;
3825-
bond_for_each_slave(bond, slave) {
3827+
bond_for_each_slave_rcu(bond, slave) {
38263828
if (--i < 0)
38273829
break;
38283830
if (slave_can_tx(slave)) {
@@ -3848,7 +3850,7 @@ static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *bond_dev
38483850
* will send all of this type of traffic.
38493851
*/
38503852
if (iph->protocol == IPPROTO_IGMP && skb->protocol == htons(ETH_P_IP)) {
3851-
slave = bond->curr_active_slave;
3853+
slave = rcu_dereference(bond->curr_active_slave);
38523854
if (slave && slave_can_tx(slave))
38533855
bond_dev_queue_xmit(bond, skb, slave->dev);
38543856
else
@@ -3870,7 +3872,7 @@ static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *bond_d
38703872
struct bonding *bond = netdev_priv(bond_dev);
38713873
struct slave *slave;
38723874

3873-
slave = bond->curr_active_slave;
3875+
slave = rcu_dereference(bond->curr_active_slave);
38743876
if (slave)
38753877
bond_dev_queue_xmit(bond, skb, slave->dev);
38763878
else
@@ -3900,7 +3902,7 @@ static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *bond_dev)
39003902
struct bonding *bond = netdev_priv(bond_dev);
39013903
struct slave *slave = NULL;
39023904

3903-
bond_for_each_slave(bond, slave) {
3905+
bond_for_each_slave_rcu(bond, slave) {
39043906
if (bond_is_last_slave(bond, slave))
39053907
break;
39063908
if (IS_UP(slave->dev) && slave->link == BOND_LINK_UP) {
@@ -3955,7 +3957,7 @@ static inline int bond_slave_override(struct bonding *bond,
39553957
return 1;
39563958

39573959
/* Find out if any slaves have the same mapping as this skb. */
3958-
bond_for_each_slave(bond, check_slave) {
3960+
bond_for_each_slave_rcu(bond, check_slave) {
39593961
if (check_slave->queue_id == skb->queue_mapping) {
39603962
slave = check_slave;
39613963
break;
@@ -4040,14 +4042,12 @@ static netdev_tx_t bond_start_xmit(struct sk_buff *skb, struct net_device *dev)
40404042
if (is_netpoll_tx_blocked(dev))
40414043
return NETDEV_TX_BUSY;
40424044

4043-
read_lock(&bond->lock);
4044-
4045+
rcu_read_lock();
40454046
if (!list_empty(&bond->slave_list))
40464047
ret = __bond_start_xmit(skb, dev);
40474048
else
40484049
kfree_skb(skb);
4049-
4050-
read_unlock(&bond->lock);
4050+
rcu_read_unlock();
40514051

40524052
return ret;
40534053
}

drivers/net/bonding/bond_sysfs.c

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1243,16 +1243,16 @@ static ssize_t bonding_show_active_slave(struct device *d,
12431243
struct device_attribute *attr,
12441244
char *buf)
12451245
{
1246-
struct slave *curr;
12471246
struct bonding *bond = to_bond(d);
1247+
struct slave *curr;
12481248
int count = 0;
12491249

1250-
read_lock(&bond->curr_slave_lock);
1251-
curr = bond->curr_active_slave;
1252-
read_unlock(&bond->curr_slave_lock);
1253-
1250+
rcu_read_lock();
1251+
curr = rcu_dereference(bond->curr_active_slave);
12541252
if (USES_PRIMARY(bond->params.mode) && curr)
12551253
count = sprintf(buf, "%s\n", curr->dev->name);
1254+
rcu_read_unlock();
1255+
12561256
return count;
12571257
}
12581258

@@ -1284,7 +1284,7 @@ static ssize_t bonding_store_active_slave(struct device *d,
12841284
if (!strlen(ifname) || buf[0] == '\n') {
12851285
pr_info("%s: Clearing current active slave.\n",
12861286
bond->dev->name);
1287-
bond->curr_active_slave = NULL;
1287+
rcu_assign_pointer(bond->curr_active_slave, NULL);
12881288
bond_select_active_slave(bond);
12891289
goto out;
12901290
}
@@ -1347,14 +1347,9 @@ static ssize_t bonding_show_mii_status(struct device *d,
13471347
struct device_attribute *attr,
13481348
char *buf)
13491349
{
1350-
struct slave *curr;
13511350
struct bonding *bond = to_bond(d);
13521351

1353-
read_lock(&bond->curr_slave_lock);
1354-
curr = bond->curr_active_slave;
1355-
read_unlock(&bond->curr_slave_lock);
1356-
1357-
return sprintf(buf, "%s\n", curr ? "up" : "down");
1352+
return sprintf(buf, "%s\n", bond->curr_active_slave ? "up" : "down");
13581353
}
13591354
static DEVICE_ATTR(mii_status, S_IRUGO, bonding_show_mii_status, NULL);
13601355

drivers/net/bonding/bonding.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,10 @@
116116
#define bond_for_each_slave(bond, pos) \
117117
list_for_each_entry(pos, &(bond)->slave_list, list)
118118

119+
/* Caller must have rcu_read_lock */
120+
#define bond_for_each_slave_rcu(bond, pos) \
121+
list_for_each_entry_rcu(pos, &(bond)->slave_list, list)
122+
119123
/**
120124
* bond_for_each_slave_reverse - iterate in reverse from a given position
121125
* @bond: the bond holding this list

0 commit comments

Comments
 (0)