aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@ghostprotocols.net>2005-08-09 23:09:46 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2005-08-29 18:42:18 -0400
commite48c414ee61f4ac8d5cff2973e66a7cbc8a93aa5 (patch)
treec4656efe48b75adf5742514c3e4286007f20bdca
parent8feaf0c0a5488b3d898a9c207eb6678f44ba3f26 (diff)
[INET]: Generalise the TCP sock ID lookup routines
And also some TIME_WAIT functions. [acme@toy net-2.6.14]$ grep built-in /tmp/before.size /tmp/after.size /tmp/before.size: 282955 13122 9312 305389 4a8ed net/ipv4/built-in.o /tmp/after.size: 281566 13122 9312 304000 4a380 net/ipv4/built-in.o [acme@toy net-2.6.14]$ I kept them still inlined, will uninline at some point to see what would be the performance difference. Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/inet_hashtables.h77
-rw-r--r--include/net/inet_timewait_sock.h9
-rw-r--r--include/net/sock.h12
-rw-r--r--net/ipv4/Makefile1
-rw-r--r--net/ipv4/inet_hashtables.c2
-rw-r--r--net/ipv4/inet_timewait_sock.c83
-rw-r--r--net/ipv4/tcp_diag.c8
-rw-r--r--net/ipv4/tcp_ipv4.c83
-rw-r--r--net/ipv4/tcp_minisocks.c78
9 files changed, 188 insertions, 165 deletions
diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h
index c38c637e0734..b5c0d64ea741 100644
--- a/include/net/inet_hashtables.h
+++ b/include/net/inet_hashtables.h
@@ -30,6 +30,7 @@
30#include <net/tcp_states.h> 30#include <net/tcp_states.h>
31 31
32#include <asm/atomic.h> 32#include <asm/atomic.h>
33#include <asm/byteorder.h>
33 34
34/* This is for all connections with a full identity, no wildcards. 35/* This is for all connections with a full identity, no wildcards.
35 * New scheme, half the table is for TIME_WAIT, the other half is 36 * New scheme, half the table is for TIME_WAIT, the other half is
@@ -285,13 +286,13 @@ extern struct sock *__inet_lookup_listener(const struct hlist_head *head,
285 const int dif); 286 const int dif);
286 287
287/* Optimize the common listener case. */ 288/* Optimize the common listener case. */
288static inline struct sock *inet_lookup_listener(struct inet_hashinfo *hashinfo, 289static inline struct sock *
289 const u32 daddr, 290 inet_lookup_listener(struct inet_hashinfo *hashinfo,
290 const unsigned short hnum, 291 const u32 daddr,
291 const int dif) 292 const unsigned short hnum, const int dif)
292{ 293{
293 struct sock *sk = NULL; 294 struct sock *sk = NULL;
294 struct hlist_head *head; 295 const struct hlist_head *head;
295 296
296 read_lock(&hashinfo->lhash_lock); 297 read_lock(&hashinfo->lhash_lock);
297 head = &hashinfo->listening_hash[inet_lhashfn(hnum)]; 298 head = &hashinfo->listening_hash[inet_lhashfn(hnum)];
@@ -351,4 +352,70 @@ sherry_cache:
351 ((*((__u32 *)&(inet_twsk(__sk)->tw_dport))) == (__ports)) && \ 352 ((*((__u32 *)&(inet_twsk(__sk)->tw_dport))) == (__ports)) && \
352 (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) 353 (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif))))
353#endif /* 64-bit arch */ 354#endif /* 64-bit arch */
355
356/*
357 * Sockets in TCP_CLOSE state are _always_ taken out of the hash, so we need
358 * not check it for lookups anymore, thanks Alexey. -DaveM
359 *
360 * Local BH must be disabled here.
361 */
362static inline struct sock *
363 __inet_lookup_established(struct inet_hashinfo *hashinfo,
364 const u32 saddr, const u16 sport,
365 const u32 daddr, const u16 hnum,
366 const int dif)
367{
368 INET_ADDR_COOKIE(acookie, saddr, daddr)
369 const __u32 ports = INET_COMBINED_PORTS(sport, hnum);
370 struct sock *sk;
371 const struct hlist_node *node;
372 /* Optimize here for direct hit, only listening connections can
373 * have wildcards anyways.
374 */
375 const int hash = inet_ehashfn(daddr, hnum, saddr, sport, hashinfo->ehash_size);
376 struct inet_ehash_bucket *head = &hashinfo->ehash[hash];
377
378 read_lock(&head->lock);
379 sk_for_each(sk, node, &head->chain) {
380 if (INET_MATCH(sk, acookie, saddr, daddr, ports, dif))
381 goto hit; /* You sunk my battleship! */
382 }
383
384 /* Must check for a TIME_WAIT'er before going to listener hash. */
385 sk_for_each(sk, node, &(head + hashinfo->ehash_size)->chain) {
386 if (INET_TW_MATCH(sk, acookie, saddr, daddr, ports, dif))
387 goto hit;
388 }
389 sk = NULL;
390out:
391 read_unlock(&head->lock);
392 return sk;
393hit:
394 sock_hold(sk);
395 goto out;
396}
397
398static inline struct sock *__inet_lookup(struct inet_hashinfo *hashinfo,
399 const u32 saddr, const u16 sport,
400 const u32 daddr, const u16 hnum,
401 const int dif)
402{
403 struct sock *sk = __inet_lookup_established(hashinfo, saddr, sport, daddr,
404 hnum, dif);
405 return sk ? : inet_lookup_listener(hashinfo, daddr, hnum, dif);
406}
407
408static inline struct sock *inet_lookup(struct inet_hashinfo *hashinfo,
409 const u32 saddr, const u16 sport,
410 const u32 daddr, const u16 dport,
411 const int dif)
412{
413 struct sock *sk;
414
415 local_bh_disable();
416 sk = __inet_lookup(hashinfo, saddr, sport, daddr, ntohs(dport), dif);
417 local_bh_enable();
418
419 return sk;
420}
354#endif /* _INET_HASHTABLES_H */ 421#endif /* _INET_HASHTABLES_H */
diff --git a/include/net/inet_timewait_sock.h b/include/net/inet_timewait_sock.h
index ce117048f2fd..020f28058fd4 100644
--- a/include/net/inet_timewait_sock.h
+++ b/include/net/inet_timewait_sock.h
@@ -17,6 +17,7 @@
17 17
18#include <linux/config.h> 18#include <linux/config.h>
19 19
20#include <linux/ip.h>
20#include <linux/list.h> 21#include <linux/list.h>
21#include <linux/types.h> 22#include <linux/types.h>
22 23
@@ -32,6 +33,7 @@
32#endif 33#endif
33 34
34struct inet_bind_bucket; 35struct inet_bind_bucket;
36struct inet_hashinfo;
35 37
36/* 38/*
37 * This is a TIME_WAIT sock. It works around the memory consumption 39 * This is a TIME_WAIT sock. It works around the memory consumption
@@ -139,4 +141,11 @@ static inline void inet_twsk_put(struct inet_timewait_sock *tw)
139 kmem_cache_free(tw->tw_prot->twsk_slab, tw); 141 kmem_cache_free(tw->tw_prot->twsk_slab, tw);
140 } 142 }
141} 143}
144
145extern void __inet_twsk_kill(struct inet_timewait_sock *tw,
146 struct inet_hashinfo *hashinfo);
147
148extern void __inet_twsk_hashdance(struct inet_timewait_sock *tw,
149 struct sock *sk,
150 struct inet_hashinfo *hashinfo);
142#endif /* _INET_TIMEWAIT_SOCK_ */ 151#endif /* _INET_TIMEWAIT_SOCK_ */
diff --git a/include/net/sock.h b/include/net/sock.h
index c902c57bf2b7..bdae0a5eadf5 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -255,28 +255,28 @@ struct sock {
255/* 255/*
256 * Hashed lists helper routines 256 * Hashed lists helper routines
257 */ 257 */
258static inline struct sock *__sk_head(struct hlist_head *head) 258static inline struct sock *__sk_head(const struct hlist_head *head)
259{ 259{
260 return hlist_entry(head->first, struct sock, sk_node); 260 return hlist_entry(head->first, struct sock, sk_node);
261} 261}
262 262
263static inline struct sock *sk_head(struct hlist_head *head) 263static inline struct sock *sk_head(const struct hlist_head *head)
264{ 264{
265 return hlist_empty(head) ? NULL : __sk_head(head); 265 return hlist_empty(head) ? NULL : __sk_head(head);
266} 266}
267 267
268static inline struct sock *sk_next(struct sock *sk) 268static inline struct sock *sk_next(const struct sock *sk)
269{ 269{
270 return sk->sk_node.next ? 270 return sk->sk_node.next ?
271 hlist_entry(sk->sk_node.next, struct sock, sk_node) : NULL; 271 hlist_entry(sk->sk_node.next, struct sock, sk_node) : NULL;
272} 272}
273 273
274static inline int sk_unhashed(struct sock *sk) 274static inline int sk_unhashed(const struct sock *sk)
275{ 275{
276 return hlist_unhashed(&sk->sk_node); 276 return hlist_unhashed(&sk->sk_node);
277} 277}
278 278
279static inline int sk_hashed(struct sock *sk) 279static inline int sk_hashed(const struct sock *sk)
280{ 280{
281 return sk->sk_node.pprev != NULL; 281 return sk->sk_node.pprev != NULL;
282} 282}
@@ -494,7 +494,7 @@ extern int sk_wait_data(struct sock *sk, long *timeo);
494struct request_sock_ops; 494struct request_sock_ops;
495 495
496/* Here is the right place to enable sock refcounting debugging */ 496/* Here is the right place to enable sock refcounting debugging */
497#define SOCK_REFCNT_DEBUG 497//#define SOCK_REFCNT_DEBUG
498 498
499/* Networking protocol blocks we attach to sockets. 499/* Networking protocol blocks we attach to sockets.
500 * socket layer -> transport layer interface 500 * socket layer -> transport layer interface
diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile
index 2d8d30e83eb0..6650d18e400f 100644
--- a/net/ipv4/Makefile
+++ b/net/ipv4/Makefile
@@ -5,6 +5,7 @@
5obj-y := route.o inetpeer.o protocol.o \ 5obj-y := route.o inetpeer.o protocol.o \
6 ip_input.o ip_fragment.o ip_forward.o ip_options.o \ 6 ip_input.o ip_fragment.o ip_forward.o ip_options.o \
7 ip_output.o ip_sockglue.o inet_hashtables.o \ 7 ip_output.o ip_sockglue.o inet_hashtables.o \
8 inet_timewait_sock.o \
8 tcp.o tcp_input.o tcp_output.o tcp_timer.o tcp_ipv4.o \ 9 tcp.o tcp_input.o tcp_output.o tcp_timer.o tcp_ipv4.o \
9 tcp_minisocks.o tcp_cong.o \ 10 tcp_minisocks.o tcp_cong.o \
10 datagram.o raw.o udp.o arp.o icmp.o devinet.o af_inet.o igmp.o \ 11 datagram.o raw.o udp.o arp.o icmp.o devinet.o af_inet.o igmp.o \
diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c
index 88fcba05b7d6..d94e962958a4 100644
--- a/net/ipv4/inet_hashtables.c
+++ b/net/ipv4/inet_hashtables.c
@@ -162,3 +162,5 @@ struct sock *__inet_lookup_listener(const struct hlist_head *head, const u32 dad
162 } 162 }
163 return result; 163 return result;
164} 164}
165
166EXPORT_SYMBOL_GPL(__inet_lookup_listener);
diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c
new file mode 100644
index 000000000000..d38d160faeb7
--- /dev/null
+++ b/net/ipv4/inet_timewait_sock.c
@@ -0,0 +1,83 @@
1/*
2 * INET An implementation of the TCP/IP protocol suite for the LINUX
3 * operating system. INET is implemented using the BSD Socket
4 * interface as the means of communication with the user level.
5 *
6 * Generic TIME_WAIT sockets functions
7 *
8 * From code orinally in TCP
9 */
10
11#include <linux/config.h>
12
13#include <net/inet_hashtables.h>
14#include <net/inet_timewait_sock.h>
15
16/* Must be called with locally disabled BHs. */
17void __inet_twsk_kill(struct inet_timewait_sock *tw, struct inet_hashinfo *hashinfo)
18{
19 struct inet_bind_hashbucket *bhead;
20 struct inet_bind_bucket *tb;
21 /* Unlink from established hashes. */
22 struct inet_ehash_bucket *ehead = &hashinfo->ehash[tw->tw_hashent];
23
24 write_lock(&ehead->lock);
25 if (hlist_unhashed(&tw->tw_node)) {
26 write_unlock(&ehead->lock);
27 return;
28 }
29 __hlist_del(&tw->tw_node);
30 sk_node_init(&tw->tw_node);
31 write_unlock(&ehead->lock);
32
33 /* Disassociate with bind bucket. */
34 bhead = &hashinfo->bhash[inet_bhashfn(tw->tw_num, hashinfo->bhash_size)];
35 spin_lock(&bhead->lock);
36 tb = tw->tw_tb;
37 __hlist_del(&tw->tw_bind_node);
38 tw->tw_tb = NULL;
39 inet_bind_bucket_destroy(hashinfo->bind_bucket_cachep, tb);
40 spin_unlock(&bhead->lock);
41#ifdef SOCK_REFCNT_DEBUG
42 if (atomic_read(&tw->tw_refcnt) != 1) {
43 printk(KERN_DEBUG "%s timewait_sock %p refcnt=%d\n",
44 tw->tw_prot->name, tw, atomic_read(&tw->tw_refcnt));
45 }
46#endif
47 inet_twsk_put(tw);
48}
49
50/*
51 * Enter the time wait state. This is called with locally disabled BH.
52 * Essentially we whip up a timewait bucket, copy the relevant info into it
53 * from the SK, and mess with hash chains and list linkage.
54 */
55void __inet_twsk_hashdance(struct inet_timewait_sock *tw, struct sock *sk,
56 struct inet_hashinfo *hashinfo)
57{
58 const struct inet_sock *inet = inet_sk(sk);
59 struct inet_ehash_bucket *ehead = &hashinfo->ehash[sk->sk_hashent];
60 struct inet_bind_hashbucket *bhead;
61 /* Step 1: Put TW into bind hash. Original socket stays there too.
62 Note, that any socket with inet->num != 0 MUST be bound in
63 binding cache, even if it is closed.
64 */
65 bhead = &hashinfo->bhash[inet_bhashfn(inet->num, hashinfo->bhash_size)];
66 spin_lock(&bhead->lock);
67 tw->tw_tb = inet->bind_hash;
68 BUG_TRAP(inet->bind_hash);
69 inet_twsk_add_bind_node(tw, &tw->tw_tb->owners);
70 spin_unlock(&bhead->lock);
71
72 write_lock(&ehead->lock);
73
74 /* Step 2: Remove SK from established hash. */
75 if (__sk_del_node_init(sk))
76 sock_prot_dec_use(sk->sk_prot);
77
78 /* Step 3: Hash TW into TIMEWAIT half of established hash table. */
79 inet_twsk_add_node(tw, &(ehead + hashinfo->ehash_size)->chain);
80 atomic_inc(&tw->tw_refcnt);
81
82 write_unlock(&ehead->lock);
83}
diff --git a/net/ipv4/tcp_diag.c b/net/ipv4/tcp_diag.c
index 6f2d6f2276b9..60c6a797cc50 100644
--- a/net/ipv4/tcp_diag.c
+++ b/net/ipv4/tcp_diag.c
@@ -174,8 +174,6 @@ nlmsg_failure:
174 return -1; 174 return -1;
175} 175}
176 176
177extern struct sock *tcp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport,
178 int dif);
179#ifdef CONFIG_IP_TCPDIAG_IPV6 177#ifdef CONFIG_IP_TCPDIAG_IPV6
180extern struct sock *tcp_v6_lookup(struct in6_addr *saddr, u16 sport, 178extern struct sock *tcp_v6_lookup(struct in6_addr *saddr, u16 sport,
181 struct in6_addr *daddr, u16 dport, 179 struct in6_addr *daddr, u16 dport,
@@ -197,9 +195,9 @@ static int tcpdiag_get_exact(struct sk_buff *in_skb, const struct nlmsghdr *nlh)
197 struct sk_buff *rep; 195 struct sk_buff *rep;
198 196
199 if (req->tcpdiag_family == AF_INET) { 197 if (req->tcpdiag_family == AF_INET) {
200 sk = tcp_v4_lookup(req->id.tcpdiag_dst[0], req->id.tcpdiag_dport, 198 sk = inet_lookup(&tcp_hashinfo, req->id.tcpdiag_dst[0],
201 req->id.tcpdiag_src[0], req->id.tcpdiag_sport, 199 req->id.tcpdiag_dport, req->id.tcpdiag_src[0],
202 req->id.tcpdiag_if); 200 req->id.tcpdiag_sport, req->id.tcpdiag_if);
203 } 201 }
204#ifdef CONFIG_IP_TCPDIAG_IPV6 202#ifdef CONFIG_IP_TCPDIAG_IPV6
205 else if (req->tcpdiag_family == AF_INET6) { 203 else if (req->tcpdiag_family == AF_INET6) {
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index ce423e48ebe0..e7e91e60ac74 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -238,71 +238,6 @@ void tcp_unhash(struct sock *sk)
238 inet_unhash(&tcp_hashinfo, sk); 238 inet_unhash(&tcp_hashinfo, sk);
239} 239}
240 240
241/* Sockets in TCP_CLOSE state are _always_ taken out of the hash, so
242 * we need not check it for TCP lookups anymore, thanks Alexey. -DaveM
243 *
244 * Local BH must be disabled here.
245 */
246
247static inline struct sock *__tcp_v4_lookup_established(const u32 saddr,
248 const u16 sport,
249 const u32 daddr,
250 const u16 hnum,
251 const int dif)
252{
253 struct inet_ehash_bucket *head;
254 INET_ADDR_COOKIE(acookie, saddr, daddr)
255 const __u32 ports = INET_COMBINED_PORTS(sport, hnum);
256 struct sock *sk;
257 const struct hlist_node *node;
258 /* Optimize here for direct hit, only listening connections can
259 * have wildcards anyways.
260 */
261 const int hash = inet_ehashfn(daddr, hnum, saddr, sport, tcp_hashinfo.ehash_size);
262 head = &tcp_hashinfo.ehash[hash];
263 read_lock(&head->lock);
264 sk_for_each(sk, node, &head->chain) {
265 if (INET_MATCH(sk, acookie, saddr, daddr, ports, dif))
266 goto hit; /* You sunk my battleship! */
267 }
268
269 /* Must check for a TIME_WAIT'er before going to listener hash. */
270 sk_for_each(sk, node, &(head + tcp_hashinfo.ehash_size)->chain) {
271 if (INET_TW_MATCH(sk, acookie, saddr, daddr, ports, dif))
272 goto hit;
273 }
274 sk = NULL;
275out:
276 read_unlock(&head->lock);
277 return sk;
278hit:
279 sock_hold(sk);
280 goto out;
281}
282
283static inline struct sock *__tcp_v4_lookup(u32 saddr, u16 sport,
284 u32 daddr, u16 hnum, int dif)
285{
286 struct sock *sk = __tcp_v4_lookup_established(saddr, sport,
287 daddr, hnum, dif);
288
289 return sk ? : inet_lookup_listener(&tcp_hashinfo, daddr, hnum, dif);
290}
291
292inline struct sock *tcp_v4_lookup(u32 saddr, u16 sport, u32 daddr,
293 u16 dport, int dif)
294{
295 struct sock *sk;
296
297 local_bh_disable();
298 sk = __tcp_v4_lookup(saddr, sport, daddr, ntohs(dport), dif);
299 local_bh_enable();
300
301 return sk;
302}
303
304EXPORT_SYMBOL_GPL(tcp_v4_lookup);
305
306static inline __u32 tcp_v4_init_sequence(struct sock *sk, struct sk_buff *skb) 241static inline __u32 tcp_v4_init_sequence(struct sock *sk, struct sk_buff *skb)
307{ 242{
308 return secure_tcp_sequence_number(skb->nh.iph->daddr, 243 return secure_tcp_sequence_number(skb->nh.iph->daddr,
@@ -751,8 +686,8 @@ void tcp_v4_err(struct sk_buff *skb, u32 info)
751 return; 686 return;
752 } 687 }
753 688
754 sk = tcp_v4_lookup(iph->daddr, th->dest, iph->saddr, 689 sk = inet_lookup(&tcp_hashinfo, iph->daddr, th->dest, iph->saddr,
755 th->source, tcp_v4_iif(skb)); 690 th->source, tcp_v4_iif(skb));
756 if (!sk) { 691 if (!sk) {
757 ICMP_INC_STATS_BH(ICMP_MIB_INERRORS); 692 ICMP_INC_STATS_BH(ICMP_MIB_INERRORS);
758 return; 693 return;
@@ -1359,11 +1294,9 @@ static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb)
1359 if (req) 1294 if (req)
1360 return tcp_check_req(sk, skb, req, prev); 1295 return tcp_check_req(sk, skb, req, prev);
1361 1296
1362 nsk = __tcp_v4_lookup_established(skb->nh.iph->saddr, 1297 nsk = __inet_lookup_established(&tcp_hashinfo, skb->nh.iph->saddr,
1363 th->source, 1298 th->source, skb->nh.iph->daddr,
1364 skb->nh.iph->daddr, 1299 ntohs(th->dest), tcp_v4_iif(skb));
1365 ntohs(th->dest),
1366 tcp_v4_iif(skb));
1367 1300
1368 if (nsk) { 1301 if (nsk) {
1369 if (nsk->sk_state != TCP_TIME_WAIT) { 1302 if (nsk->sk_state != TCP_TIME_WAIT) {
@@ -1505,9 +1438,9 @@ int tcp_v4_rcv(struct sk_buff *skb)
1505 TCP_SKB_CB(skb)->flags = skb->nh.iph->tos; 1438 TCP_SKB_CB(skb)->flags = skb->nh.iph->tos;
1506 TCP_SKB_CB(skb)->sacked = 0; 1439 TCP_SKB_CB(skb)->sacked = 0;
1507 1440
1508 sk = __tcp_v4_lookup(skb->nh.iph->saddr, th->source, 1441 sk = __inet_lookup(&tcp_hashinfo, skb->nh.iph->saddr, th->source,
1509 skb->nh.iph->daddr, ntohs(th->dest), 1442 skb->nh.iph->daddr, ntohs(th->dest),
1510 tcp_v4_iif(skb)); 1443 tcp_v4_iif(skb));
1511 1444
1512 if (!sk) 1445 if (!sk)
1513 goto no_tcp_socket; 1446 goto no_tcp_socket;
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index 5b5a49335fbb..4112f7a6d108 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -56,42 +56,6 @@ static __inline__ int tcp_in_window(u32 seq, u32 end_seq, u32 s_win, u32 e_win)
56 56
57int tcp_tw_count; 57int tcp_tw_count;
58 58
59
60/* Must be called with locally disabled BHs. */
61static void tcp_timewait_kill(struct inet_timewait_sock *tw)
62{
63 struct inet_bind_hashbucket *bhead;
64 struct inet_bind_bucket *tb;
65 /* Unlink from established hashes. */
66 struct inet_ehash_bucket *ehead = &tcp_hashinfo.ehash[tw->tw_hashent];
67
68 write_lock(&ehead->lock);
69 if (hlist_unhashed(&tw->tw_node)) {
70 write_unlock(&ehead->lock);
71 return;
72 }
73 __hlist_del(&tw->tw_node);
74 sk_node_init(&tw->tw_node);
75 write_unlock(&ehead->lock);
76
77 /* Disassociate with bind bucket. */
78 bhead = &tcp_hashinfo.bhash[inet_bhashfn(tw->tw_num, tcp_hashinfo.bhash_size)];
79 spin_lock(&bhead->lock);
80 tb = tw->tw_tb;
81 __hlist_del(&tw->tw_bind_node);
82 tw->tw_tb = NULL;
83 inet_bind_bucket_destroy(tcp_hashinfo.bind_bucket_cachep, tb);
84 spin_unlock(&bhead->lock);
85
86#ifdef SOCK_REFCNT_DEBUG
87 if (atomic_read(&tw->tw_refcnt) != 1) {
88 printk(KERN_DEBUG "%s timewait_sock %p refcnt=%d\n",
89 tw->tw_prot->name, tw, atomic_read(&tw->tw_refcnt));
90 }
91#endif
92 inet_twsk_put(tw);
93}
94
95/* 59/*
96 * * Main purpose of TIME-WAIT state is to close connection gracefully, 60 * * Main purpose of TIME-WAIT state is to close connection gracefully,
97 * when one of ends sits in LAST-ACK or CLOSING retransmitting FIN 61 * when one of ends sits in LAST-ACK or CLOSING retransmitting FIN
@@ -290,40 +254,6 @@ kill:
290 return TCP_TW_SUCCESS; 254 return TCP_TW_SUCCESS;
291} 255}
292 256
293/* Enter the time wait state. This is called with locally disabled BH.
294 * Essentially we whip up a timewait bucket, copy the
295 * relevant info into it from the SK, and mess with hash chains
296 * and list linkage.
297 */
298static void __tcp_tw_hashdance(struct sock *sk, struct inet_timewait_sock *tw)
299{
300 const struct inet_sock *inet = inet_sk(sk);
301 struct inet_ehash_bucket *ehead = &tcp_hashinfo.ehash[sk->sk_hashent];
302 struct inet_bind_hashbucket *bhead;
303 /* Step 1: Put TW into bind hash. Original socket stays there too.
304 Note, that any socket with inet->num != 0 MUST be bound in
305 binding cache, even if it is closed.
306 */
307 bhead = &tcp_hashinfo.bhash[inet_bhashfn(inet->num, tcp_hashinfo.bhash_size)];
308 spin_lock(&bhead->lock);
309 tw->tw_tb = inet->bind_hash;
310 BUG_TRAP(inet->bind_hash);
311 inet_twsk_add_bind_node(tw, &tw->tw_tb->owners);
312 spin_unlock(&bhead->lock);
313
314 write_lock(&ehead->lock);
315
316 /* Step 2: Remove SK from established hash. */
317 if (__sk_del_node_init(sk))
318 sock_prot_dec_use(sk->sk_prot);
319
320 /* Step 3: Hash TW into TIMEWAIT half of established hash table. */
321 inet_twsk_add_node(tw, &(ehead + tcp_hashinfo.ehash_size)->chain);
322 atomic_inc(&tw->tw_refcnt);
323
324 write_unlock(&ehead->lock);
325}
326
327/* 257/*
328 * Move a socket to time-wait or dead fin-wait-2 state. 258 * Move a socket to time-wait or dead fin-wait-2 state.
329 */ 259 */
@@ -381,7 +311,7 @@ void tcp_time_wait(struct sock *sk, int state, int timeo)
381 tw->tw_ipv6only = 0; 311 tw->tw_ipv6only = 0;
382#endif 312#endif
383 /* Linkage updates. */ 313 /* Linkage updates. */
384 __tcp_tw_hashdance(sk, tw); 314 __inet_twsk_hashdance(tw, sk, &tcp_hashinfo);
385 315
386 /* Get the TIME_WAIT timeout firing. */ 316 /* Get the TIME_WAIT timeout firing. */
387 if (timeo < rto) 317 if (timeo < rto)
@@ -448,7 +378,7 @@ rescan:
448 inet_twsk_for_each_inmate(tw, node, &tcp_tw_death_row[slot]) { 378 inet_twsk_for_each_inmate(tw, node, &tcp_tw_death_row[slot]) {
449 __inet_twsk_del_dead_node(tw); 379 __inet_twsk_del_dead_node(tw);
450 spin_unlock(&tw_death_lock); 380 spin_unlock(&tw_death_lock);
451 tcp_timewait_kill(tw); 381 __inet_twsk_kill(tw, &tcp_hashinfo);
452 inet_twsk_put(tw); 382 inet_twsk_put(tw);
453 killed++; 383 killed++;
454 spin_lock(&tw_death_lock); 384 spin_lock(&tw_death_lock);
@@ -544,7 +474,7 @@ void tcp_tw_deschedule(struct inet_timewait_sock *tw)
544 del_timer(&tcp_tw_timer); 474 del_timer(&tcp_tw_timer);
545 } 475 }
546 spin_unlock(&tw_death_lock); 476 spin_unlock(&tw_death_lock);
547 tcp_timewait_kill(tw); 477 __inet_twsk_kill(tw, &tcp_hashinfo);
548} 478}
549 479
550/* Short-time timewait calendar */ 480/* Short-time timewait calendar */
@@ -653,7 +583,7 @@ void tcp_twcal_tick(unsigned long dummy)
653 inet_twsk_for_each_inmate_safe(tw, node, safe, 583 inet_twsk_for_each_inmate_safe(tw, node, safe,
654 &tcp_twcal_row[slot]) { 584 &tcp_twcal_row[slot]) {
655 __inet_twsk_del_dead_node(tw); 585 __inet_twsk_del_dead_node(tw);
656 tcp_timewait_kill(tw); 586 __inet_twsk_kill(tw, &tcp_hashinfo);
657 inet_twsk_put(tw); 587 inet_twsk_put(tw);
658 killed++; 588 killed++;
659 } 589 }