diff options
author | Eric Dumazet <dada1@cosmosbay.com> | 2008-10-29 04:41:45 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-10-29 04:41:45 -0400 |
commit | 645ca708f936b2fbeb79e52d7823e3eb2c0905f8 (patch) | |
tree | b384696994ee3cb04759a7bfffc29a48e4bf40f6 /net/ipv6/udplite.c | |
parent | b189db5d299c6824780af5590564ff608adb3dea (diff) |
udp: introduce struct udp_table and multiple spinlocks
UDP sockets are hashed in a 128 slots hash table.
This hash table is protected by *one* rwlock.
This rwlock is readlocked each time an incoming UDP message is handled.
This rwlock is writelocked each time a socket must be inserted in
hash table (bind time), or deleted from this table (close time)
This is not scalable on SMP machines :
1) Even in read mode, lock() and unlock() are atomic operations and
must dirty a contended cache line, shared by all cpus.
2) A writer might be starved if many readers are 'in flight'. This can
happen on a machine with some NIC receiving many UDP messages. User
process can be delayed a long time at socket creation/dismantle time.
This patch prepares RCU migration, by introducing 'struct udp_table
and struct udp_hslot', and using one spinlock per chain, to reduce
contention on central rwlock.
Introducing one spinlock per chain reduces latencies, for port
randomization on heavily loaded UDP servers. This also speedup
bindings to specific ports.
udp_lib_unhash() was uninlined, becoming to big.
Some cleanups were done to ease review of following patch
(RCUification of UDP Unicast lookups)
Signed-off-by: Eric Dumazet <dada1@cosmosbay.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/udplite.c')
-rw-r--r-- | net/ipv6/udplite.c | 8 |
1 files changed, 4 insertions, 4 deletions
diff --git a/net/ipv6/udplite.c b/net/ipv6/udplite.c index 3cd1a1ac3d6c..f1e892a99e05 100644 --- a/net/ipv6/udplite.c +++ b/net/ipv6/udplite.c | |||
@@ -15,14 +15,14 @@ | |||
15 | 15 | ||
16 | static int udplitev6_rcv(struct sk_buff *skb) | 16 | static int udplitev6_rcv(struct sk_buff *skb) |
17 | { | 17 | { |
18 | return __udp6_lib_rcv(skb, udplite_hash, IPPROTO_UDPLITE); | 18 | return __udp6_lib_rcv(skb, &udplite_table, IPPROTO_UDPLITE); |
19 | } | 19 | } |
20 | 20 | ||
21 | static void udplitev6_err(struct sk_buff *skb, | 21 | static void udplitev6_err(struct sk_buff *skb, |
22 | struct inet6_skb_parm *opt, | 22 | struct inet6_skb_parm *opt, |
23 | int type, int code, int offset, __be32 info) | 23 | int type, int code, int offset, __be32 info) |
24 | { | 24 | { |
25 | __udp6_lib_err(skb, opt, type, code, offset, info, udplite_hash); | 25 | __udp6_lib_err(skb, opt, type, code, offset, info, &udplite_table); |
26 | } | 26 | } |
27 | 27 | ||
28 | static struct inet6_protocol udplitev6_protocol = { | 28 | static struct inet6_protocol udplitev6_protocol = { |
@@ -49,7 +49,7 @@ struct proto udplitev6_prot = { | |||
49 | .unhash = udp_lib_unhash, | 49 | .unhash = udp_lib_unhash, |
50 | .get_port = udp_v6_get_port, | 50 | .get_port = udp_v6_get_port, |
51 | .obj_size = sizeof(struct udp6_sock), | 51 | .obj_size = sizeof(struct udp6_sock), |
52 | .h.udp_hash = udplite_hash, | 52 | .h.udp_table = &udplite_table, |
53 | #ifdef CONFIG_COMPAT | 53 | #ifdef CONFIG_COMPAT |
54 | .compat_setsockopt = compat_udpv6_setsockopt, | 54 | .compat_setsockopt = compat_udpv6_setsockopt, |
55 | .compat_getsockopt = compat_udpv6_getsockopt, | 55 | .compat_getsockopt = compat_udpv6_getsockopt, |
@@ -95,7 +95,7 @@ void udplitev6_exit(void) | |||
95 | static struct udp_seq_afinfo udplite6_seq_afinfo = { | 95 | static struct udp_seq_afinfo udplite6_seq_afinfo = { |
96 | .name = "udplite6", | 96 | .name = "udplite6", |
97 | .family = AF_INET6, | 97 | .family = AF_INET6, |
98 | .hashtable = udplite_hash, | 98 | .udp_table = &udplite_table, |
99 | .seq_fops = { | 99 | .seq_fops = { |
100 | .owner = THIS_MODULE, | 100 | .owner = THIS_MODULE, |
101 | }, | 101 | }, |