From 44f4d5a27ee63ec80d498e0d0673605d5ce1427d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Denis-Courmont?= Date: Tue, 12 Apr 2011 23:27:36 +0000 Subject: Phonet: convert bound sockets hash list to RCU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This gets rid of the last spinlock in the Phonet stack proper. Signed-off-by: RĂ©mi Denis-Courmont Signed-off-by: David S. Miller --- net/phonet/socket.c | 45 +++++++++++++++++++++------------------------ 1 file changed, 21 insertions(+), 24 deletions(-) (limited to 'net/phonet') diff --git a/net/phonet/socket.c b/net/phonet/socket.c index b1adafa..8c5bfce 100644 --- a/net/phonet/socket.c +++ b/net/phonet/socket.c @@ -52,7 +52,7 @@ static int pn_socket_release(struct socket *sock) static struct { struct hlist_head hlist[PN_HASHSIZE]; - spinlock_t lock; + struct mutex lock; } pnsocks; void __init pn_sock_init(void) @@ -61,7 +61,7 @@ void __init pn_sock_init(void) for (i = 0; i < PN_HASHSIZE; i++) INIT_HLIST_HEAD(pnsocks.hlist + i); - spin_lock_init(&pnsocks.lock); + mutex_init(&pnsocks.lock); } static struct hlist_head *pn_hash_list(u16 obj) @@ -82,9 +82,8 @@ struct sock *pn_find_sock_by_sa(struct net *net, const struct sockaddr_pn *spn) u8 res = spn->spn_resource; struct hlist_head *hlist = pn_hash_list(obj); - spin_lock_bh(&pnsocks.lock); - - sk_for_each(sknode, node, hlist) { + rcu_read_lock(); + sk_for_each_rcu(sknode, node, hlist) { struct pn_sock *pn = pn_sk(sknode); BUG_ON(!pn->sobject); /* unbound socket */ @@ -107,8 +106,7 @@ struct sock *pn_find_sock_by_sa(struct net *net, const struct sockaddr_pn *spn) sock_hold(sknode); break; } - - spin_unlock_bh(&pnsocks.lock); + rcu_read_unlock(); return rval; } @@ -119,7 +117,7 @@ void pn_deliver_sock_broadcast(struct net *net, struct sk_buff *skb) struct hlist_head *hlist = pnsocks.hlist; unsigned h; - spin_lock(&pnsocks.lock); + rcu_read_lock(); for (h = 0; h < PN_HASHSIZE; h++) { struct hlist_node *node; struct sock *sknode; @@ -140,25 +138,26 @@ void pn_deliver_sock_broadcast(struct net *net, struct sk_buff *skb) } hlist++; } - spin_unlock(&pnsocks.lock); + rcu_read_unlock(); } void pn_sock_hash(struct sock *sk) { struct hlist_head *hlist = pn_hash_list(pn_sk(sk)->sobject); - spin_lock_bh(&pnsocks.lock); - sk_add_node(sk, hlist); - spin_unlock_bh(&pnsocks.lock); + mutex_lock(&pnsocks.lock); + sk_add_node_rcu(sk, hlist); + mutex_unlock(&pnsocks.lock); } EXPORT_SYMBOL(pn_sock_hash); void pn_sock_unhash(struct sock *sk) { - spin_lock_bh(&pnsocks.lock); - sk_del_node_init(sk); - spin_unlock_bh(&pnsocks.lock); + mutex_lock(&pnsocks.lock); + sk_del_node_init_rcu(sk); + mutex_unlock(&pnsocks.lock); pn_sock_unbind_all_res(sk); + synchronize_rcu(); } EXPORT_SYMBOL(pn_sock_unhash); @@ -548,7 +547,7 @@ static struct sock *pn_sock_get_idx(struct seq_file *seq, loff_t pos) unsigned h; for (h = 0; h < PN_HASHSIZE; h++) { - sk_for_each(sknode, node, hlist) { + sk_for_each_rcu(sknode, node, hlist) { if (!net_eq(net, sock_net(sknode))) continue; if (!pos) @@ -572,9 +571,9 @@ static struct sock *pn_sock_get_next(struct seq_file *seq, struct sock *sk) } static void *pn_sock_seq_start(struct seq_file *seq, loff_t *pos) - __acquires(pnsocks.lock) + __acquires(rcu) { - spin_lock_bh(&pnsocks.lock); + rcu_read_lock(); return *pos ? pn_sock_get_idx(seq, *pos - 1) : SEQ_START_TOKEN; } @@ -591,9 +590,9 @@ static void *pn_sock_seq_next(struct seq_file *seq, void *v, loff_t *pos) } static void pn_sock_seq_stop(struct seq_file *seq, void *v) - __releases(pnsocks.lock) + __releases(rcu) { - spin_unlock_bh(&pnsocks.lock); + rcu_read_unlock(); } static int pn_sock_seq_show(struct seq_file *seq, void *v) @@ -721,13 +720,11 @@ void pn_sock_unbind_all_res(struct sock *sk) } mutex_unlock(&resource_mutex); - if (match == 0) - return; - synchronize_rcu(); while (match > 0) { - sock_put(sk); + __sock_put(sk); match--; } + /* Caller is responsible for RCU sync before final sock_put() */ } #ifdef CONFIG_PROC_FS -- cgit v1.1 From e67f88dd12f610da98ca838822f2c9b4e7c6100e Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 27 Apr 2011 22:56:07 +0000 Subject: 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 : 1c2d670f366 : [RTNETLINK]: Hold rtnl_mutex during netlink dump callbacks 6313c1e0992 : [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 Cc: Patrick McHardy Cc: Remi Denis-Courmont Acked-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/phonet/pn_dev.c | 6 +----- net/phonet/pn_netlink.c | 4 +++- 2 files changed, 4 insertions(+), 6 deletions(-) (limited to 'net/phonet') diff --git a/net/phonet/pn_dev.c b/net/phonet/pn_dev.c index 947038d..47b3452 100644 --- a/net/phonet/pn_dev.c +++ b/net/phonet/pn_dev.c @@ -426,18 +426,14 @@ int phonet_route_del(struct net_device *dev, u8 daddr) return 0; } -struct net_device *phonet_route_get(struct net *net, u8 daddr) +struct net_device *phonet_route_get_rcu(struct net *net, u8 daddr) { struct phonet_net *pnn = phonet_pernet(net); struct phonet_routes *routes = &pnn->routes; struct net_device *dev; - ASSERT_RTNL(); /* no need to hold the device */ - daddr >>= 2; - rcu_read_lock(); dev = rcu_dereference(routes->table[daddr]); - rcu_read_unlock(); return dev; } diff --git a/net/phonet/pn_netlink.c b/net/phonet/pn_netlink.c index 58b3b1f..438accb 100644 --- a/net/phonet/pn_netlink.c +++ b/net/phonet/pn_netlink.c @@ -264,10 +264,11 @@ static int route_dumpit(struct sk_buff *skb, struct netlink_callback *cb) struct net *net = sock_net(skb->sk); u8 addr, addr_idx = 0, addr_start_idx = cb->args[0]; + rcu_read_lock(); for (addr = 0; addr < 64; addr++) { struct net_device *dev; - dev = phonet_route_get(net, addr << 2); + dev = phonet_route_get_rcu(net, addr << 2); if (!dev) continue; @@ -279,6 +280,7 @@ static int route_dumpit(struct sk_buff *skb, struct netlink_callback *cb) } out: + rcu_read_unlock(); cb->args[0] = addr_idx; cb->args[1] = 0; -- cgit v1.1