aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/inet_timewait_sock.h3
-rw-r--r--net/ipv4/inet_hashtables.c2
-rw-r--r--net/ipv4/inet_timewait_sock.c29
3 files changed, 26 insertions, 8 deletions
diff --git a/include/net/inet_timewait_sock.h b/include/net/inet_timewait_sock.h
index b801ade2295e..79f67eae8a7e 100644
--- a/include/net/inet_timewait_sock.h
+++ b/include/net/inet_timewait_sock.h
@@ -201,6 +201,9 @@ extern void inet_twsk_put(struct inet_timewait_sock *tw);
201 201
202extern int inet_twsk_unhash(struct inet_timewait_sock *tw); 202extern int inet_twsk_unhash(struct inet_timewait_sock *tw);
203 203
204extern int inet_twsk_bind_unhash(struct inet_timewait_sock *tw,
205 struct inet_hashinfo *hashinfo);
206
204extern struct inet_timewait_sock *inet_twsk_alloc(const struct sock *sk, 207extern struct inet_timewait_sock *inet_twsk_alloc(const struct sock *sk,
205 const int state); 208 const int state);
206 209
diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c
index c4201b7ece38..2b79377b468d 100644
--- a/net/ipv4/inet_hashtables.c
+++ b/net/ipv4/inet_hashtables.c
@@ -502,6 +502,8 @@ ok:
502 inet_sk(sk)->inet_sport = htons(port); 502 inet_sk(sk)->inet_sport = htons(port);
503 twrefcnt += hash(sk, tw); 503 twrefcnt += hash(sk, tw);
504 } 504 }
505 if (tw)
506 twrefcnt += inet_twsk_bind_unhash(tw, hinfo);
505 spin_unlock(&head->lock); 507 spin_unlock(&head->lock);
506 508
507 if (tw) { 509 if (tw) {
diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c
index 0fdf45e4c90c..bf4b1e2a4305 100644
--- a/net/ipv4/inet_timewait_sock.c
+++ b/net/ipv4/inet_timewait_sock.c
@@ -29,12 +29,29 @@ int inet_twsk_unhash(struct inet_timewait_sock *tw)
29 return 1; 29 return 1;
30} 30}
31 31
32/*
33 * unhash a timewait socket from bind hash
34 * lock must be hold by caller
35 */
36int inet_twsk_bind_unhash(struct inet_timewait_sock *tw,
37 struct inet_hashinfo *hashinfo)
38{
39 struct inet_bind_bucket *tb = tw->tw_tb;
40
41 if (!tb)
42 return 0;
43
44 __hlist_del(&tw->tw_bind_node);
45 tw->tw_tb = NULL;
46 inet_bind_bucket_destroy(hashinfo->bind_bucket_cachep, tb);
47 return 1;
48}
49
32/* Must be called with locally disabled BHs. */ 50/* Must be called with locally disabled BHs. */
33static void __inet_twsk_kill(struct inet_timewait_sock *tw, 51static void __inet_twsk_kill(struct inet_timewait_sock *tw,
34 struct inet_hashinfo *hashinfo) 52 struct inet_hashinfo *hashinfo)
35{ 53{
36 struct inet_bind_hashbucket *bhead; 54 struct inet_bind_hashbucket *bhead;
37 struct inet_bind_bucket *tb;
38 int refcnt; 55 int refcnt;
39 /* Unlink from established hashes. */ 56 /* Unlink from established hashes. */
40 spinlock_t *lock = inet_ehash_lockp(hashinfo, tw->tw_hash); 57 spinlock_t *lock = inet_ehash_lockp(hashinfo, tw->tw_hash);
@@ -46,15 +63,11 @@ static void __inet_twsk_kill(struct inet_timewait_sock *tw,
46 /* Disassociate with bind bucket. */ 63 /* Disassociate with bind bucket. */
47 bhead = &hashinfo->bhash[inet_bhashfn(twsk_net(tw), tw->tw_num, 64 bhead = &hashinfo->bhash[inet_bhashfn(twsk_net(tw), tw->tw_num,
48 hashinfo->bhash_size)]; 65 hashinfo->bhash_size)];
66
49 spin_lock(&bhead->lock); 67 spin_lock(&bhead->lock);
50 tb = tw->tw_tb; 68 refcnt += inet_twsk_bind_unhash(tw, hashinfo);
51 if (tb) {
52 __hlist_del(&tw->tw_bind_node);
53 tw->tw_tb = NULL;
54 inet_bind_bucket_destroy(hashinfo->bind_bucket_cachep, tb);
55 refcnt++;
56 }
57 spin_unlock(&bhead->lock); 69 spin_unlock(&bhead->lock);
70
58#ifdef SOCK_REFCNT_DEBUG 71#ifdef SOCK_REFCNT_DEBUG
59 if (atomic_read(&tw->tw_refcnt) != 1) { 72 if (atomic_read(&tw->tw_refcnt) != 1) {
60 printk(KERN_DEBUG "%s timewait_sock %p refcnt=%d\n", 73 printk(KERN_DEBUG "%s timewait_sock %p refcnt=%d\n",