aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/inet6_hashtables.c
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2013-10-03 03:22:02 -0400
committerDavid S. Miller <davem@davemloft.net>2013-10-08 23:19:24 -0400
commit05dbc7b59481ca891bbcfe6799a562d48159fbf7 (patch)
treef398ddbc5d2a72b3c3b7b16aed8a34b153491341 /net/ipv6/inet6_hashtables.c
parent53af53ae83fe960ceb9ef74cac7915e9088f4266 (diff)
tcp/dccp: remove twchain
TCP listener refactoring, part 3 : Our goal is to hash SYN_RECV sockets into main ehash for fast lookup, and parallel SYN processing. Current inet_ehash_bucket contains two chains, one for ESTABLISH (and friend states) sockets, another for TIME_WAIT sockets only. As the hash table is sized to get at most one socket per bucket, it makes little sense to have separate twchain, as it makes the lookup slightly more complicated, and doubles hash table memory usage. If we make sure all socket types have the lookup keys at the same offsets, we can use a generic and faster lookup. It turns out TIME_WAIT and ESTABLISHED sockets already have common lookup fields for IPv4. [ INET_TW_MATCH() is no longer needed ] I'll provide a follow-up to factorize IPv6 lookup as well, to remove INET6_TW_MATCH() This way, SYN_RECV pseudo sockets will be supported the same. A new sock_gen_put() helper is added, doing either a sock_put() or inet_twsk_put() [ and will support SYN_RECV later ]. Note this helper should only be called in real slow path, when rcu lookup found a socket that was moved to another identity (freed/reused immediately), but could eventually be used in other contexts, like sock_edemux() Before patch : dmesg | grep "TCP established" TCP established hash table entries: 524288 (order: 11, 8388608 bytes) After patch : TCP established hash table entries: 524288 (order: 10, 4194304 bytes) Signed-off-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/inet6_hashtables.c')
-rw-r--r--net/ipv6/inet6_hashtables.c75
1 files changed, 31 insertions, 44 deletions
diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c
index 066640e0ba8e..46440777e1c5 100644
--- a/net/ipv6/inet6_hashtables.c
+++ b/net/ipv6/inet6_hashtables.c
@@ -89,43 +89,36 @@ begin:
89 sk_nulls_for_each_rcu(sk, node, &head->chain) { 89 sk_nulls_for_each_rcu(sk, node, &head->chain) {
90 if (sk->sk_hash != hash) 90 if (sk->sk_hash != hash)
91 continue; 91 continue;
92 if (likely(INET6_MATCH(sk, net, saddr, daddr, ports, dif))) { 92 if (sk->sk_state == TCP_TIME_WAIT) {
93 if (unlikely(!atomic_inc_not_zero(&sk->sk_refcnt))) 93 if (!INET6_TW_MATCH(sk, net, saddr, daddr, ports, dif))
94 goto begintw; 94 continue;
95 } else {
96 if (!INET6_MATCH(sk, net, saddr, daddr, ports, dif))
97 continue;
98 }
99 if (unlikely(!atomic_inc_not_zero(&sk->sk_refcnt)))
100 goto out;
101
102 if (sk->sk_state == TCP_TIME_WAIT) {
103 if (unlikely(!INET6_TW_MATCH(sk, net, saddr, daddr,
104 ports, dif))) {
105 sock_gen_put(sk);
106 goto begin;
107 }
108 } else {
95 if (unlikely(!INET6_MATCH(sk, net, saddr, daddr, 109 if (unlikely(!INET6_MATCH(sk, net, saddr, daddr,
96 ports, dif))) { 110 ports, dif))) {
97 sock_put(sk); 111 sock_put(sk);
98 goto begin; 112 goto begin;
99 } 113 }
100 goto out; 114 goto found;
101 } 115 }
102 } 116 }
103 if (get_nulls_value(node) != slot) 117 if (get_nulls_value(node) != slot)
104 goto begin; 118 goto begin;
105
106begintw:
107 /* Must check for a TIME_WAIT'er before going to listener hash. */
108 sk_nulls_for_each_rcu(sk, node, &head->twchain) {
109 if (sk->sk_hash != hash)
110 continue;
111 if (likely(INET6_TW_MATCH(sk, net, saddr, daddr,
112 ports, dif))) {
113 if (unlikely(!atomic_inc_not_zero(&sk->sk_refcnt))) {
114 sk = NULL;
115 goto out;
116 }
117 if (unlikely(!INET6_TW_MATCH(sk, net, saddr, daddr,
118 ports, dif))) {
119 inet_twsk_put(inet_twsk(sk));
120 goto begintw;
121 }
122 goto out;
123 }
124 }
125 if (get_nulls_value(node) != slot)
126 goto begintw;
127 sk = NULL;
128out: 119out:
120 sk = NULL;
121found:
129 rcu_read_unlock(); 122 rcu_read_unlock();
130 return sk; 123 return sk;
131} 124}
@@ -248,31 +241,25 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row,
248 spinlock_t *lock = inet_ehash_lockp(hinfo, hash); 241 spinlock_t *lock = inet_ehash_lockp(hinfo, hash);
249 struct sock *sk2; 242 struct sock *sk2;
250 const struct hlist_nulls_node *node; 243 const struct hlist_nulls_node *node;
251 struct inet_timewait_sock *tw; 244 struct inet_timewait_sock *tw = NULL;
252 int twrefcnt = 0; 245 int twrefcnt = 0;
253 246
254 spin_lock(lock); 247 spin_lock(lock);
255 248
256 /* Check TIME-WAIT sockets first. */ 249 sk_nulls_for_each(sk2, node, &head->chain) {
257 sk_nulls_for_each(sk2, node, &head->twchain) {
258 if (sk2->sk_hash != hash) 250 if (sk2->sk_hash != hash)
259 continue; 251 continue;
260 252
261 if (likely(INET6_TW_MATCH(sk2, net, saddr, daddr, 253 if (sk2->sk_state == TCP_TIME_WAIT) {
262 ports, dif))) { 254 if (likely(INET6_TW_MATCH(sk2, net, saddr, daddr,
263 tw = inet_twsk(sk2); 255 ports, dif))) {
264 if (twsk_unique(sk, sk2, twp)) 256 tw = inet_twsk(sk2);
265 goto unique; 257 if (twsk_unique(sk, sk2, twp))
266 else 258 goto unique;
267 goto not_unique; 259 else
260 goto not_unique;
261 }
268 } 262 }
269 }
270 tw = NULL;
271
272 /* And established part... */
273 sk_nulls_for_each(sk2, node, &head->chain) {
274 if (sk2->sk_hash != hash)
275 continue;
276 if (likely(INET6_MATCH(sk2, net, saddr, daddr, ports, dif))) 263 if (likely(INET6_MATCH(sk2, net, saddr, daddr, ports, dif)))
277 goto not_unique; 264 goto not_unique;
278 } 265 }