diff options
Diffstat (limited to 'net/ipv4/inet_timewait_sock.c')
| -rw-r--r-- | net/ipv4/inet_timewait_sock.c | 48 |
1 files changed, 26 insertions, 22 deletions
diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c index 1c5fd38f8824..8554d0ea1719 100644 --- a/net/ipv4/inet_timewait_sock.c +++ b/net/ipv4/inet_timewait_sock.c | |||
| @@ -20,16 +20,16 @@ static void __inet_twsk_kill(struct inet_timewait_sock *tw, | |||
| 20 | struct inet_bind_hashbucket *bhead; | 20 | struct inet_bind_hashbucket *bhead; |
| 21 | struct inet_bind_bucket *tb; | 21 | struct inet_bind_bucket *tb; |
| 22 | /* Unlink from established hashes. */ | 22 | /* Unlink from established hashes. */ |
| 23 | rwlock_t *lock = inet_ehash_lockp(hashinfo, tw->tw_hash); | 23 | spinlock_t *lock = inet_ehash_lockp(hashinfo, tw->tw_hash); |
| 24 | 24 | ||
| 25 | write_lock(lock); | 25 | spin_lock(lock); |
| 26 | if (hlist_unhashed(&tw->tw_node)) { | 26 | if (hlist_nulls_unhashed(&tw->tw_node)) { |
| 27 | write_unlock(lock); | 27 | spin_unlock(lock); |
| 28 | return; | 28 | return; |
| 29 | } | 29 | } |
| 30 | __hlist_del(&tw->tw_node); | 30 | hlist_nulls_del_rcu(&tw->tw_node); |
| 31 | sk_node_init(&tw->tw_node); | 31 | sk_nulls_node_init(&tw->tw_node); |
| 32 | write_unlock(lock); | 32 | spin_unlock(lock); |
| 33 | 33 | ||
| 34 | /* Disassociate with bind bucket. */ | 34 | /* Disassociate with bind bucket. */ |
| 35 | bhead = &hashinfo->bhash[inet_bhashfn(twsk_net(tw), tw->tw_num, | 35 | bhead = &hashinfo->bhash[inet_bhashfn(twsk_net(tw), tw->tw_num, |
| @@ -76,7 +76,7 @@ void __inet_twsk_hashdance(struct inet_timewait_sock *tw, struct sock *sk, | |||
| 76 | const struct inet_sock *inet = inet_sk(sk); | 76 | const struct inet_sock *inet = inet_sk(sk); |
| 77 | const struct inet_connection_sock *icsk = inet_csk(sk); | 77 | const struct inet_connection_sock *icsk = inet_csk(sk); |
| 78 | struct inet_ehash_bucket *ehead = inet_ehash_bucket(hashinfo, sk->sk_hash); | 78 | struct inet_ehash_bucket *ehead = inet_ehash_bucket(hashinfo, sk->sk_hash); |
| 79 | rwlock_t *lock = inet_ehash_lockp(hashinfo, sk->sk_hash); | 79 | spinlock_t *lock = inet_ehash_lockp(hashinfo, sk->sk_hash); |
| 80 | struct inet_bind_hashbucket *bhead; | 80 | struct inet_bind_hashbucket *bhead; |
| 81 | /* Step 1: Put TW into bind hash. Original socket stays there too. | 81 | /* Step 1: Put TW into bind hash. Original socket stays there too. |
| 82 | Note, that any socket with inet->num != 0 MUST be bound in | 82 | Note, that any socket with inet->num != 0 MUST be bound in |
| @@ -90,17 +90,21 @@ void __inet_twsk_hashdance(struct inet_timewait_sock *tw, struct sock *sk, | |||
| 90 | inet_twsk_add_bind_node(tw, &tw->tw_tb->owners); | 90 | inet_twsk_add_bind_node(tw, &tw->tw_tb->owners); |
| 91 | spin_unlock(&bhead->lock); | 91 | spin_unlock(&bhead->lock); |
| 92 | 92 | ||
| 93 | write_lock(lock); | 93 | spin_lock(lock); |
| 94 | 94 | ||
| 95 | /* Step 2: Remove SK from established hash. */ | 95 | /* |
| 96 | if (__sk_del_node_init(sk)) | 96 | * Step 2: Hash TW into TIMEWAIT chain. |
| 97 | sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); | 97 | * Should be done before removing sk from established chain |
| 98 | 98 | * because readers are lockless and search established first. | |
| 99 | /* Step 3: Hash TW into TIMEWAIT chain. */ | 99 | */ |
| 100 | inet_twsk_add_node(tw, &ehead->twchain); | ||
| 101 | atomic_inc(&tw->tw_refcnt); | 100 | atomic_inc(&tw->tw_refcnt); |
| 101 | inet_twsk_add_node_rcu(tw, &ehead->twchain); | ||
| 102 | 102 | ||
| 103 | write_unlock(lock); | 103 | /* Step 3: Remove SK from established hash. */ |
| 104 | if (__sk_nulls_del_node_init_rcu(sk)) | ||
| 105 | sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); | ||
| 106 | |||
| 107 | spin_unlock(lock); | ||
| 104 | } | 108 | } |
| 105 | 109 | ||
| 106 | EXPORT_SYMBOL_GPL(__inet_twsk_hashdance); | 110 | EXPORT_SYMBOL_GPL(__inet_twsk_hashdance); |
| @@ -416,17 +420,17 @@ void inet_twsk_purge(struct net *net, struct inet_hashinfo *hashinfo, | |||
| 416 | { | 420 | { |
| 417 | struct inet_timewait_sock *tw; | 421 | struct inet_timewait_sock *tw; |
| 418 | struct sock *sk; | 422 | struct sock *sk; |
| 419 | struct hlist_node *node; | 423 | struct hlist_nulls_node *node; |
| 420 | int h; | 424 | int h; |
| 421 | 425 | ||
| 422 | local_bh_disable(); | 426 | local_bh_disable(); |
| 423 | for (h = 0; h < (hashinfo->ehash_size); h++) { | 427 | for (h = 0; h < (hashinfo->ehash_size); h++) { |
| 424 | struct inet_ehash_bucket *head = | 428 | struct inet_ehash_bucket *head = |
| 425 | inet_ehash_bucket(hashinfo, h); | 429 | inet_ehash_bucket(hashinfo, h); |
| 426 | rwlock_t *lock = inet_ehash_lockp(hashinfo, h); | 430 | spinlock_t *lock = inet_ehash_lockp(hashinfo, h); |
| 427 | restart: | 431 | restart: |
| 428 | write_lock(lock); | 432 | spin_lock(lock); |
| 429 | sk_for_each(sk, node, &head->twchain) { | 433 | sk_nulls_for_each(sk, node, &head->twchain) { |
| 430 | 434 | ||
| 431 | tw = inet_twsk(sk); | 435 | tw = inet_twsk(sk); |
| 432 | if (!net_eq(twsk_net(tw), net) || | 436 | if (!net_eq(twsk_net(tw), net) || |
| @@ -434,13 +438,13 @@ restart: | |||
| 434 | continue; | 438 | continue; |
| 435 | 439 | ||
| 436 | atomic_inc(&tw->tw_refcnt); | 440 | atomic_inc(&tw->tw_refcnt); |
| 437 | write_unlock(lock); | 441 | spin_unlock(lock); |
| 438 | inet_twsk_deschedule(tw, twdr); | 442 | inet_twsk_deschedule(tw, twdr); |
| 439 | inet_twsk_put(tw); | 443 | inet_twsk_put(tw); |
| 440 | 444 | ||
| 441 | goto restart; | 445 | goto restart; |
| 442 | } | 446 | } |
| 443 | write_unlock(lock); | 447 | spin_unlock(lock); |
| 444 | } | 448 | } |
| 445 | local_bh_enable(); | 449 | local_bh_enable(); |
| 446 | } | 450 | } |
