Commit ec94c269 authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller

tcp/dccp: avoid one atomic operation for timewait hashdance

First, rename __inet_twsk_hashdance() to inet_twsk_hashdance()

Then, remove one inet_twsk_put() by setting tw_refcnt to 3 instead
of 4, but adding a fat warning that we do not have the right to access
tw anymore after inet_twsk_hashdance()
Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 1e757011
...@@ -93,8 +93,8 @@ struct inet_timewait_sock *inet_twsk_alloc(const struct sock *sk, ...@@ -93,8 +93,8 @@ struct inet_timewait_sock *inet_twsk_alloc(const struct sock *sk,
struct inet_timewait_death_row *dr, struct inet_timewait_death_row *dr,
const int state); const int state);
void __inet_twsk_hashdance(struct inet_timewait_sock *tw, struct sock *sk, void inet_twsk_hashdance(struct inet_timewait_sock *tw, struct sock *sk,
struct inet_hashinfo *hashinfo); struct inet_hashinfo *hashinfo);
void __inet_twsk_schedule(struct inet_timewait_sock *tw, int timeo, void __inet_twsk_schedule(struct inet_timewait_sock *tw, int timeo,
bool rearm); bool rearm);
......
...@@ -63,9 +63,10 @@ void dccp_time_wait(struct sock *sk, int state, int timeo) ...@@ -63,9 +63,10 @@ void dccp_time_wait(struct sock *sk, int state, int timeo)
*/ */
local_bh_disable(); local_bh_disable();
inet_twsk_schedule(tw, timeo); inet_twsk_schedule(tw, timeo);
/* Linkage updates. */ /* Linkage updates.
__inet_twsk_hashdance(tw, sk, &dccp_hashinfo); * Note that access to tw after this point is illegal.
inet_twsk_put(tw); */
inet_twsk_hashdance(tw, sk, &dccp_hashinfo);
local_bh_enable(); local_bh_enable();
} else { } else {
/* Sorry, if we're out of memory, just CLOSE this /* Sorry, if we're out of memory, just CLOSE this
......
...@@ -97,7 +97,7 @@ static void inet_twsk_add_bind_node(struct inet_timewait_sock *tw, ...@@ -97,7 +97,7 @@ static void inet_twsk_add_bind_node(struct inet_timewait_sock *tw,
* Essentially we whip up a timewait bucket, copy the relevant info into it * Essentially we whip up a timewait bucket, copy the relevant info into it
* from the SK, and mess with hash chains and list linkage. * from the SK, and mess with hash chains and list linkage.
*/ */
void __inet_twsk_hashdance(struct inet_timewait_sock *tw, struct sock *sk, void inet_twsk_hashdance(struct inet_timewait_sock *tw, struct sock *sk,
struct inet_hashinfo *hashinfo) struct inet_hashinfo *hashinfo)
{ {
const struct inet_sock *inet = inet_sk(sk); const struct inet_sock *inet = inet_sk(sk);
...@@ -119,18 +119,6 @@ void __inet_twsk_hashdance(struct inet_timewait_sock *tw, struct sock *sk, ...@@ -119,18 +119,6 @@ void __inet_twsk_hashdance(struct inet_timewait_sock *tw, struct sock *sk,
spin_lock(lock); spin_lock(lock);
/*
* Step 2: Hash TW into tcp ehash chain.
* Notes :
* - tw_refcnt is set to 4 because :
* - We have one reference from bhash chain.
* - We have one reference from ehash chain.
* - We have one reference from timer.
* - One reference for ourself (our caller will release it).
* We can use atomic_set() because prior spin_lock()/spin_unlock()
* committed into memory all tw fields.
*/
refcount_set(&tw->tw_refcnt, 4);
inet_twsk_add_node_rcu(tw, &ehead->chain); inet_twsk_add_node_rcu(tw, &ehead->chain);
/* Step 3: Remove SK from hash chain */ /* Step 3: Remove SK from hash chain */
...@@ -138,8 +126,19 @@ void __inet_twsk_hashdance(struct inet_timewait_sock *tw, struct sock *sk, ...@@ -138,8 +126,19 @@ void __inet_twsk_hashdance(struct inet_timewait_sock *tw, struct sock *sk,
sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
spin_unlock(lock); spin_unlock(lock);
/* tw_refcnt is set to 3 because we have :
* - one reference for bhash chain.
* - one reference for ehash chain.
* - one reference for timer.
* We can use atomic_set() because prior spin_lock()/spin_unlock()
* committed into memory all tw fields.
* Also note that after this point, we lost our implicit reference
* so we are not allowed to use tw anymore.
*/
refcount_set(&tw->tw_refcnt, 3);
} }
EXPORT_SYMBOL_GPL(__inet_twsk_hashdance); EXPORT_SYMBOL_GPL(inet_twsk_hashdance);
static void tw_timer_handler(struct timer_list *t) static void tw_timer_handler(struct timer_list *t)
{ {
......
...@@ -316,9 +316,10 @@ void tcp_time_wait(struct sock *sk, int state, int timeo) ...@@ -316,9 +316,10 @@ void tcp_time_wait(struct sock *sk, int state, int timeo)
*/ */
local_bh_disable(); local_bh_disable();
inet_twsk_schedule(tw, timeo); inet_twsk_schedule(tw, timeo);
/* Linkage updates. */ /* Linkage updates.
__inet_twsk_hashdance(tw, sk, &tcp_hashinfo); * Note that access to tw after this point is illegal.
inet_twsk_put(tw); */
inet_twsk_hashdance(tw, sk, &tcp_hashinfo);
local_bh_enable(); local_bh_enable();
} else { } else {
/* Sorry, if we're out of memory, just CLOSE this /* Sorry, if we're out of memory, just CLOSE this
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment