aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/tcp_ipv4.c
diff options
context:
space:
mode:
authorEric Dumazet <dada1@cosmosbay.com>2008-11-20 03:40:07 -0500
committerDavid S. Miller <davem@davemloft.net>2008-11-20 03:40:07 -0500
commit5caea4ea7088e80ac5410d04660346094608b909 (patch)
treefad95133683c002d24ff5de7fb756dad806b41ed /net/ipv4/tcp_ipv4.c
parentd8b83c57a7e497cba9b5cb156e63176323035785 (diff)
net: listening_hash get a spinlock per bucket
This patch prepares RCU migration of listening_hash table for TCP/DCCP protocols. listening_hash table being small (32 slots per protocol), we add a spinlock for each slot, instead of a single rwlock for whole table. This should reduce hold time of readers, and writers concurrency. 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.c24
1 files changed, 12 insertions, 12 deletions
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 5559fea61e87..330b08a12274 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -97,11 +97,7 @@ struct tcp_md5sig_key *tcp_v4_md5_do_lookup(struct sock *sk, __be32 addr)
97} 97}
98#endif 98#endif
99 99
100struct inet_hashinfo __cacheline_aligned tcp_hashinfo = { 100struct inet_hashinfo tcp_hashinfo;
101 .lhash_lock = __RW_LOCK_UNLOCKED(tcp_hashinfo.lhash_lock),
102 .lhash_users = ATOMIC_INIT(0),
103 .lhash_wait = __WAIT_QUEUE_HEAD_INITIALIZER(tcp_hashinfo.lhash_wait),
104};
105 101
106static inline __u32 tcp_v4_init_sequence(struct sk_buff *skb) 102static inline __u32 tcp_v4_init_sequence(struct sk_buff *skb)
107{ 103{
@@ -1874,15 +1870,18 @@ static void *listening_get_next(struct seq_file *seq, void *cur)
1874 struct inet_connection_sock *icsk; 1870 struct inet_connection_sock *icsk;
1875 struct hlist_node *node; 1871 struct hlist_node *node;
1876 struct sock *sk = cur; 1872 struct sock *sk = cur;
1873 struct inet_listen_hashbucket *ilb;
1877 struct tcp_iter_state *st = seq->private; 1874 struct tcp_iter_state *st = seq->private;
1878 struct net *net = seq_file_net(seq); 1875 struct net *net = seq_file_net(seq);
1879 1876
1880 if (!sk) { 1877 if (!sk) {
1881 st->bucket = 0; 1878 st->bucket = 0;
1882 sk = sk_head(&tcp_hashinfo.listening_hash[0]); 1879 ilb = &tcp_hashinfo.listening_hash[0];
1880 spin_lock_bh(&ilb->lock);
1881 sk = sk_head(&ilb->head);
1883 goto get_sk; 1882 goto get_sk;
1884 } 1883 }
1885 1884 ilb = &tcp_hashinfo.listening_hash[st->bucket];
1886 ++st->num; 1885 ++st->num;
1887 1886
1888 if (st->state == TCP_SEQ_STATE_OPENREQ) { 1887 if (st->state == TCP_SEQ_STATE_OPENREQ) {
@@ -1932,8 +1931,11 @@ start_req:
1932 } 1931 }
1933 read_unlock_bh(&icsk->icsk_accept_queue.syn_wait_lock); 1932 read_unlock_bh(&icsk->icsk_accept_queue.syn_wait_lock);
1934 } 1933 }
1934 spin_unlock_bh(&ilb->lock);
1935 if (++st->bucket < INET_LHTABLE_SIZE) { 1935 if (++st->bucket < INET_LHTABLE_SIZE) {
1936 sk = sk_head(&tcp_hashinfo.listening_hash[st->bucket]); 1936 ilb = &tcp_hashinfo.listening_hash[st->bucket];
1937 spin_lock_bh(&ilb->lock);
1938 sk = sk_head(&ilb->head);
1937 goto get_sk; 1939 goto get_sk;
1938 } 1940 }
1939 cur = NULL; 1941 cur = NULL;
@@ -2066,12 +2068,10 @@ static void *tcp_get_idx(struct seq_file *seq, loff_t pos)
2066 void *rc; 2068 void *rc;
2067 struct tcp_iter_state *st = seq->private; 2069 struct tcp_iter_state *st = seq->private;
2068 2070
2069 inet_listen_lock(&tcp_hashinfo);
2070 st->state = TCP_SEQ_STATE_LISTENING; 2071 st->state = TCP_SEQ_STATE_LISTENING;
2071 rc = listening_get_idx(seq, &pos); 2072 rc = listening_get_idx(seq, &pos);
2072 2073
2073 if (!rc) { 2074 if (!rc) {
2074 inet_listen_unlock(&tcp_hashinfo);
2075 st->state = TCP_SEQ_STATE_ESTABLISHED; 2075 st->state = TCP_SEQ_STATE_ESTABLISHED;
2076 rc = established_get_idx(seq, pos); 2076 rc = established_get_idx(seq, pos);
2077 } 2077 }
@@ -2103,7 +2103,6 @@ static void *tcp_seq_next(struct seq_file *seq, void *v, loff_t *pos)
2103 case TCP_SEQ_STATE_LISTENING: 2103 case TCP_SEQ_STATE_LISTENING:
2104 rc = listening_get_next(seq, v); 2104 rc = listening_get_next(seq, v);
2105 if (!rc) { 2105 if (!rc) {
2106 inet_listen_unlock(&tcp_hashinfo);
2107 st->state = TCP_SEQ_STATE_ESTABLISHED; 2106 st->state = TCP_SEQ_STATE_ESTABLISHED;
2108 rc = established_get_first(seq); 2107 rc = established_get_first(seq);
2109 } 2108 }
@@ -2130,7 +2129,7 @@ static void tcp_seq_stop(struct seq_file *seq, void *v)
2130 } 2129 }
2131 case TCP_SEQ_STATE_LISTENING: 2130 case TCP_SEQ_STATE_LISTENING:
2132 if (v != SEQ_START_TOKEN) 2131 if (v != SEQ_START_TOKEN)
2133 inet_listen_unlock(&tcp_hashinfo); 2132 spin_unlock_bh(&tcp_hashinfo.listening_hash[st->bucket].lock);
2134 break; 2133 break;
2135 case TCP_SEQ_STATE_TIME_WAIT: 2134 case TCP_SEQ_STATE_TIME_WAIT:
2136 case TCP_SEQ_STATE_ESTABLISHED: 2135 case TCP_SEQ_STATE_ESTABLISHED:
@@ -2405,6 +2404,7 @@ static struct pernet_operations __net_initdata tcp_sk_ops = {
2405 2404
2406void __init tcp_v4_init(void) 2405void __init tcp_v4_init(void)
2407{ 2406{
2407 inet_hashinfo_init(&tcp_hashinfo);
2408 if (register_pernet_device(&tcp_sk_ops)) 2408 if (register_pernet_device(&tcp_sk_ops))
2409 panic("Failed to create the TCP control socket.\n"); 2409 panic("Failed to create the TCP control socket.\n");
2410} 2410}