diff options
author | Eric Dumazet <dada1@cosmosbay.com> | 2008-11-23 20:22:55 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-11-23 20:22:55 -0500 |
commit | c25eb3bfb97294d0543a81230fbc237046b4b84c (patch) | |
tree | 6c9deabfb12f4d31f280cfcfe7e7580a2089931c /net/ipv4/tcp_ipv4.c | |
parent | 8c862c23e2563e6aedfc6c4aa6827cadb83f2414 (diff) |
net: Convert TCP/DCCP listening hash tables to use RCU
This is the last step to be able to perform full RCU lookups
in __inet_lookup() : After established/timewait tables, we
add RCU lookups to listening hash table.
The only trick here is that a socket of a given type (TCP ipv4,
TCP ipv6, ...) can now flight between two different tables
(established and listening) during a RCU grace period, so we
must use different 'nulls' end-of-chain values for two tables.
We define a large value :
#define LISTENING_NULLS_BASE (1U << 29)
So that slots in listening table are guaranteed to have different
end-of-chain values than slots in established table. A reader can
still detect it finished its lookup in the right chain.
Signed-off-by: Eric Dumazet <dada1@cosmosbay.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/tcp_ipv4.c')
-rw-r--r-- | net/ipv4/tcp_ipv4.c | 8 |
1 files changed, 4 insertions, 4 deletions
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index a81caa1be0cf..cab2458f86fd 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c | |||
@@ -1868,7 +1868,7 @@ static inline struct inet_timewait_sock *tw_next(struct inet_timewait_sock *tw) | |||
1868 | static void *listening_get_next(struct seq_file *seq, void *cur) | 1868 | static void *listening_get_next(struct seq_file *seq, void *cur) |
1869 | { | 1869 | { |
1870 | struct inet_connection_sock *icsk; | 1870 | struct inet_connection_sock *icsk; |
1871 | struct hlist_node *node; | 1871 | struct hlist_nulls_node *node; |
1872 | struct sock *sk = cur; | 1872 | struct sock *sk = cur; |
1873 | struct inet_listen_hashbucket *ilb; | 1873 | struct inet_listen_hashbucket *ilb; |
1874 | struct tcp_iter_state *st = seq->private; | 1874 | struct tcp_iter_state *st = seq->private; |
@@ -1878,7 +1878,7 @@ static void *listening_get_next(struct seq_file *seq, void *cur) | |||
1878 | st->bucket = 0; | 1878 | st->bucket = 0; |
1879 | ilb = &tcp_hashinfo.listening_hash[0]; | 1879 | ilb = &tcp_hashinfo.listening_hash[0]; |
1880 | spin_lock_bh(&ilb->lock); | 1880 | spin_lock_bh(&ilb->lock); |
1881 | sk = sk_head(&ilb->head); | 1881 | sk = sk_nulls_head(&ilb->head); |
1882 | goto get_sk; | 1882 | goto get_sk; |
1883 | } | 1883 | } |
1884 | ilb = &tcp_hashinfo.listening_hash[st->bucket]; | 1884 | ilb = &tcp_hashinfo.listening_hash[st->bucket]; |
@@ -1914,7 +1914,7 @@ get_req: | |||
1914 | sk = sk_next(sk); | 1914 | sk = sk_next(sk); |
1915 | } | 1915 | } |
1916 | get_sk: | 1916 | get_sk: |
1917 | sk_for_each_from(sk, node) { | 1917 | sk_nulls_for_each_from(sk, node) { |
1918 | if (sk->sk_family == st->family && net_eq(sock_net(sk), net)) { | 1918 | if (sk->sk_family == st->family && net_eq(sock_net(sk), net)) { |
1919 | cur = sk; | 1919 | cur = sk; |
1920 | goto out; | 1920 | goto out; |
@@ -1935,7 +1935,7 @@ start_req: | |||
1935 | if (++st->bucket < INET_LHTABLE_SIZE) { | 1935 | if (++st->bucket < INET_LHTABLE_SIZE) { |
1936 | ilb = &tcp_hashinfo.listening_hash[st->bucket]; | 1936 | ilb = &tcp_hashinfo.listening_hash[st->bucket]; |
1937 | spin_lock_bh(&ilb->lock); | 1937 | spin_lock_bh(&ilb->lock); |
1938 | sk = sk_head(&ilb->head); | 1938 | sk = sk_nulls_head(&ilb->head); |
1939 | goto get_sk; | 1939 | goto get_sk; |
1940 | } | 1940 | } |
1941 | cur = NULL; | 1941 | cur = NULL; |