forked from mirrors/linux
		
	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: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									1e75701175
								
							
						
					
					
						commit
						ec94c2696f
					
				
					 4 changed files with 23 additions and 22 deletions
				
			
		| 
						 | 
				
			
			@ -93,8 +93,8 @@ struct inet_timewait_sock *inet_twsk_alloc(const struct sock *sk,
 | 
			
		|||
					   struct inet_timewait_death_row *dr,
 | 
			
		||||
					   const int state);
 | 
			
		||||
 | 
			
		||||
void __inet_twsk_hashdance(struct inet_timewait_sock *tw, struct sock *sk,
 | 
			
		||||
			   struct inet_hashinfo *hashinfo);
 | 
			
		||||
void inet_twsk_hashdance(struct inet_timewait_sock *tw, struct sock *sk,
 | 
			
		||||
			 struct inet_hashinfo *hashinfo);
 | 
			
		||||
 | 
			
		||||
void __inet_twsk_schedule(struct inet_timewait_sock *tw, int timeo,
 | 
			
		||||
			  bool rearm);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -63,9 +63,10 @@ void dccp_time_wait(struct sock *sk, int state, int timeo)
 | 
			
		|||
		 */
 | 
			
		||||
		local_bh_disable();
 | 
			
		||||
		inet_twsk_schedule(tw, timeo);
 | 
			
		||||
		/* Linkage updates. */
 | 
			
		||||
		__inet_twsk_hashdance(tw, sk, &dccp_hashinfo);
 | 
			
		||||
		inet_twsk_put(tw);
 | 
			
		||||
		/* Linkage updates.
 | 
			
		||||
		 * Note that access to tw after this point is illegal.
 | 
			
		||||
		 */
 | 
			
		||||
		inet_twsk_hashdance(tw, sk, &dccp_hashinfo);
 | 
			
		||||
		local_bh_enable();
 | 
			
		||||
	} else {
 | 
			
		||||
		/* 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,
 | 
			
		|||
 * Essentially we whip up a timewait bucket, copy the relevant info into it
 | 
			
		||||
 * 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)
 | 
			
		||||
{
 | 
			
		||||
	const struct inet_sock *inet = inet_sk(sk);
 | 
			
		||||
| 
						 | 
				
			
			@ -119,18 +119,6 @@ void __inet_twsk_hashdance(struct inet_timewait_sock *tw, struct sock *sk,
 | 
			
		|||
 | 
			
		||||
	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);
 | 
			
		||||
 | 
			
		||||
	/* Step 3: Remove SK from hash chain */
 | 
			
		||||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
 | 
			
		||||
	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)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -316,9 +316,10 @@ void tcp_time_wait(struct sock *sk, int state, int timeo)
 | 
			
		|||
		 */
 | 
			
		||||
		local_bh_disable();
 | 
			
		||||
		inet_twsk_schedule(tw, timeo);
 | 
			
		||||
		/* Linkage updates. */
 | 
			
		||||
		__inet_twsk_hashdance(tw, sk, &tcp_hashinfo);
 | 
			
		||||
		inet_twsk_put(tw);
 | 
			
		||||
		/* Linkage updates.
 | 
			
		||||
		 * Note that access to tw after this point is illegal.
 | 
			
		||||
		 */
 | 
			
		||||
		inet_twsk_hashdance(tw, sk, &tcp_hashinfo);
 | 
			
		||||
		local_bh_enable();
 | 
			
		||||
	} else {
 | 
			
		||||
		/* Sorry, if we're out of memory, just CLOSE this
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue