Skip to content

Commit e67f88d

Browse files
Eric Dumazetdavem330
Eric Dumazet
authored andcommitted
net: dont hold rtnl mutex during netlink dump callbacks
Four years ago, Patrick made a change to hold rtnl mutex during netlink dump callbacks. I believe it was a wrong move. This slows down concurrent dumps, making good old /proc/net/ files faster than rtnetlink in some situations. This occurred to me because one "ip link show dev ..." was _very_ slow on a workload adding/removing network devices in background. All dump callbacks are able to use RCU locking now, so this patch does roughly a revert of commits : 1c2d670 : [RTNETLINK]: Hold rtnl_mutex during netlink dump callbacks 6313c1e : [RTNETLINK]: Remove unnecessary locking in dump callbacks This let writers fight for rtnl mutex and readers going full speed. It also takes care of phonet : phonet_route_get() is now called from rcu read section. I renamed it to phonet_route_get_rcu() Signed-off-by: Eric Dumazet <[email protected]> Cc: Patrick McHardy <[email protected]> Cc: Remi Denis-Courmont <[email protected]> Acked-by: Stephen Hemminger <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent dcfd9cd commit e67f88d

File tree

8 files changed

+25
-23
lines changed

8 files changed

+25
-23
lines changed

include/net/phonet/pn_dev.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ void phonet_address_notify(int event, struct net_device *dev, u8 addr);
5151
int phonet_route_add(struct net_device *dev, u8 daddr);
5252
int phonet_route_del(struct net_device *dev, u8 daddr);
5353
void rtm_phonet_notify(int event, struct net_device *dev, u8 dst);
54-
struct net_device *phonet_route_get(struct net *net, u8 daddr);
54+
struct net_device *phonet_route_get_rcu(struct net *net, u8 daddr);
5555
struct net_device *phonet_route_output(struct net *net, u8 daddr);
5656

5757
#define PN_NO_ADDR 0xff

net/bridge/br_netlink.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,9 @@ static int br_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
120120
int idx;
121121

122122
idx = 0;
123-
for_each_netdev(net, dev) {
124-
struct net_bridge_port *port = br_port_get_rtnl(dev);
123+
rcu_read_lock();
124+
for_each_netdev_rcu(net, dev) {
125+
struct net_bridge_port *port = br_port_get_rcu(dev);
125126

126127
/* not a bridge port */
127128
if (!port || idx < cb->args[0])
@@ -135,7 +136,7 @@ static int br_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
135136
skip:
136137
++idx;
137138
}
138-
139+
rcu_read_unlock();
139140
cb->args[0] = idx;
140141

141142
return skb->len;

net/core/fib_rules.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -590,7 +590,8 @@ static int dump_rules(struct sk_buff *skb, struct netlink_callback *cb,
590590
int idx = 0;
591591
struct fib_rule *rule;
592592

593-
list_for_each_entry(rule, &ops->rules_list, list) {
593+
rcu_read_lock();
594+
list_for_each_entry_rcu(rule, &ops->rules_list, list) {
594595
if (idx < cb->args[1])
595596
goto skip;
596597

net/core/rtnetlink.c

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1007,10 +1007,11 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
10071007
s_h = cb->args[0];
10081008
s_idx = cb->args[1];
10091009

1010+
rcu_read_lock();
10101011
for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
10111012
idx = 0;
10121013
head = &net->dev_index_head[h];
1013-
hlist_for_each_entry(dev, node, head, index_hlist) {
1014+
hlist_for_each_entry_rcu(dev, node, head, index_hlist) {
10141015
if (idx < s_idx)
10151016
goto cont;
10161017
if (rtnl_fill_ifinfo(skb, dev, RTM_NEWLINK,
@@ -1023,6 +1024,7 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
10231024
}
10241025
}
10251026
out:
1027+
rcu_read_unlock();
10261028
cb->args[1] = idx;
10271029
cb->args[0] = h;
10281030

@@ -1879,7 +1881,6 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
18791881
int min_len;
18801882
int family;
18811883
int type;
1882-
int err;
18831884

18841885
type = nlh->nlmsg_type;
18851886
if (type > RTM_MAX)
@@ -1906,11 +1907,8 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
19061907
if (dumpit == NULL)
19071908
return -EOPNOTSUPP;
19081909

1909-
__rtnl_unlock();
19101910
rtnl = net->rtnl;
1911-
err = netlink_dump_start(rtnl, skb, nlh, dumpit, NULL);
1912-
rtnl_lock();
1913-
return err;
1911+
return netlink_dump_start(rtnl, skb, nlh, dumpit, NULL);
19141912
}
19151913

19161914
memset(rta_buf, 0, (rtattr_max * sizeof(struct rtattr *)));
@@ -1980,7 +1978,7 @@ static int __net_init rtnetlink_net_init(struct net *net)
19801978
{
19811979
struct sock *sk;
19821980
sk = netlink_kernel_create(net, NETLINK_ROUTE, RTNLGRP_MAX,
1983-
rtnetlink_rcv, &rtnl_mutex, THIS_MODULE);
1981+
rtnetlink_rcv, NULL, THIS_MODULE);
19841982
if (!sk)
19851983
return -ENOMEM;
19861984
net->rtnl = sk;

net/decnet/dn_dev.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -752,7 +752,8 @@ static int dn_nl_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
752752
skip_naddr = cb->args[1];
753753

754754
idx = 0;
755-
for_each_netdev(&init_net, dev) {
755+
rcu_read_lock();
756+
for_each_netdev_rcu(&init_net, dev) {
756757
if (idx < skip_ndevs)
757758
goto cont;
758759
else if (idx > skip_ndevs) {
@@ -761,11 +762,11 @@ static int dn_nl_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
761762
skip_naddr = 0;
762763
}
763764

764-
if ((dn_db = rtnl_dereference(dev->dn_ptr)) == NULL)
765+
if ((dn_db = rcu_dereference(dev->dn_ptr)) == NULL)
765766
goto cont;
766767

767-
for (ifa = rtnl_dereference(dn_db->ifa_list), dn_idx = 0; ifa;
768-
ifa = rtnl_dereference(ifa->ifa_next), dn_idx++) {
768+
for (ifa = rcu_dereference(dn_db->ifa_list), dn_idx = 0; ifa;
769+
ifa = rcu_dereference(ifa->ifa_next), dn_idx++) {
769770
if (dn_idx < skip_naddr)
770771
continue;
771772

@@ -778,6 +779,7 @@ static int dn_nl_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
778779
idx++;
779780
}
780781
done:
782+
rcu_read_unlock();
781783
cb->args[0] = idx;
782784
cb->args[1] = dn_idx;
783785

net/ipv6/ip6_fib.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -394,10 +394,11 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
394394
arg.net = net;
395395
w->args = &arg;
396396

397+
rcu_read_lock();
397398
for (h = s_h; h < FIB6_TABLE_HASHSZ; h++, s_e = 0) {
398399
e = 0;
399400
head = &net->ipv6.fib_table_hash[h];
400-
hlist_for_each_entry(tb, node, head, tb6_hlist) {
401+
hlist_for_each_entry_rcu(tb, node, head, tb6_hlist) {
401402
if (e < s_e)
402403
goto next;
403404
res = fib6_dump_table(tb, skb, cb);
@@ -408,6 +409,7 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
408409
}
409410
}
410411
out:
412+
rcu_read_unlock();
411413
cb->args[1] = e;
412414
cb->args[0] = h;
413415

net/phonet/pn_dev.c

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -426,18 +426,14 @@ int phonet_route_del(struct net_device *dev, u8 daddr)
426426
return 0;
427427
}
428428

429-
struct net_device *phonet_route_get(struct net *net, u8 daddr)
429+
struct net_device *phonet_route_get_rcu(struct net *net, u8 daddr)
430430
{
431431
struct phonet_net *pnn = phonet_pernet(net);
432432
struct phonet_routes *routes = &pnn->routes;
433433
struct net_device *dev;
434434

435-
ASSERT_RTNL(); /* no need to hold the device */
436-
437435
daddr >>= 2;
438-
rcu_read_lock();
439436
dev = rcu_dereference(routes->table[daddr]);
440-
rcu_read_unlock();
441437
return dev;
442438
}
443439

net/phonet/pn_netlink.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,10 +264,11 @@ static int route_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
264264
struct net *net = sock_net(skb->sk);
265265
u8 addr, addr_idx = 0, addr_start_idx = cb->args[0];
266266

267+
rcu_read_lock();
267268
for (addr = 0; addr < 64; addr++) {
268269
struct net_device *dev;
269270

270-
dev = phonet_route_get(net, addr << 2);
271+
dev = phonet_route_get_rcu(net, addr << 2);
271272
if (!dev)
272273
continue;
273274

@@ -279,6 +280,7 @@ static int route_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
279280
}
280281

281282
out:
283+
rcu_read_unlock();
282284
cb->args[0] = addr_idx;
283285
cb->args[1] = 0;
284286

0 commit comments

Comments
 (0)