diff options
Diffstat (limited to 'net/ipv4/tcp_ipv4.c')
| -rw-r--r-- | net/ipv4/tcp_ipv4.c | 60 | 
1 files changed, 31 insertions, 29 deletions
| diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index b710958393e6..fd17f25ff288 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -93,7 +93,9 @@ static int tcp_v4_md5_hash_hdr(char *md5_hash, const struct tcp_md5sig_key *key,  struct inet_hashinfo tcp_hashinfo;  EXPORT_SYMBOL(tcp_hashinfo); -static DEFINE_PER_CPU(struct sock *, ipv4_tcp_sk); +static DEFINE_PER_CPU(struct sock_bh_locked, ipv4_tcp_sk) = { +	.bh_lock = INIT_LOCAL_LOCK(bh_lock), +};  static u32 tcp_v4_init_seq(const struct sk_buff *skb)  { @@ -114,6 +116,7 @@ int tcp_twsk_unique(struct sock *sk, struct sock *sktw, void *twp)  	const struct inet_timewait_sock *tw = inet_twsk(sktw);  	const struct tcp_timewait_sock *tcptw = tcp_twsk(sktw);  	struct tcp_sock *tp = tcp_sk(sk); +	int ts_recent_stamp;  	if (reuse == 2) {  		/* Still does not detect *everything* that goes through @@ -152,10 +155,11 @@ int tcp_twsk_unique(struct sock *sk, struct sock *sktw, void *twp)  	   If TW bucket has been already destroyed we fall back to VJ's scheme  	   and use initial timestamp retrieved from peer table.  	 */ -	if (tcptw->tw_ts_recent_stamp && +	ts_recent_stamp = READ_ONCE(tcptw->tw_ts_recent_stamp); +	if (ts_recent_stamp &&  	    (!twp || (reuse && time_after32(ktime_get_seconds(), -					    tcptw->tw_ts_recent_stamp)))) { -		/* inet_twsk_hashdance() sets sk_refcnt after putting twsk +					    ts_recent_stamp)))) { +		/* inet_twsk_hashdance_schedule() sets sk_refcnt after putting twsk  		 * and releasing the bucket lock.  		 */  		if (unlikely(!refcount_inc_not_zero(&sktw->sk_refcnt))) @@ -178,8 +182,8 @@ int tcp_twsk_unique(struct sock *sk, struct sock *sktw, void *twp)  			if (!seq)  				seq = 1;  			WRITE_ONCE(tp->write_seq, seq); -			tp->rx_opt.ts_recent	   = tcptw->tw_ts_recent; -			tp->rx_opt.ts_recent_stamp = tcptw->tw_ts_recent_stamp; +			tp->rx_opt.ts_recent	   = READ_ONCE(tcptw->tw_ts_recent); +			tp->rx_opt.ts_recent_stamp = ts_recent_stamp;  		}  		return 1; @@ -611,15 +615,10 @@ int tcp_v4_err(struct sk_buff *skb, u32 info)  		ip_icmp_error(sk, skb, err, th->dest, info, (u8 *)th); -		if (!sock_owned_by_user(sk)) { -			WRITE_ONCE(sk->sk_err, err); - -			sk_error_report(sk); - -			tcp_done(sk); -		} else { +		if (!sock_owned_by_user(sk)) +			tcp_done_with_error(sk, err); +		else  			WRITE_ONCE(sk->sk_err_soft, err); -		}  		goto out;  	} @@ -885,7 +884,9 @@ static void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb,  	arg.tos = ip_hdr(skb)->tos;  	arg.uid = sock_net_uid(net, sk && sk_fullsock(sk) ? sk : NULL);  	local_bh_disable(); -	ctl_sk = this_cpu_read(ipv4_tcp_sk); +	local_lock_nested_bh(&ipv4_tcp_sk.bh_lock); +	ctl_sk = this_cpu_read(ipv4_tcp_sk.sock); +  	sock_net_set(ctl_sk, net);  	if (sk) {  		ctl_sk->sk_mark = (sk->sk_state == TCP_TIME_WAIT) ? @@ -910,6 +911,7 @@ static void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb,  	sock_net_set(ctl_sk, &init_net);  	__TCP_INC_STATS(net, TCP_MIB_OUTSEGS);  	__TCP_INC_STATS(net, TCP_MIB_OUTRSTS); +	local_unlock_nested_bh(&ipv4_tcp_sk.bh_lock);  	local_bh_enable();  #ifdef CONFIG_TCP_MD5SIG @@ -1005,7 +1007,8 @@ static void tcp_v4_send_ack(const struct sock *sk,  	arg.tos = tos;  	arg.uid = sock_net_uid(net, sk_fullsock(sk) ? sk : NULL);  	local_bh_disable(); -	ctl_sk = this_cpu_read(ipv4_tcp_sk); +	local_lock_nested_bh(&ipv4_tcp_sk.bh_lock); +	ctl_sk = this_cpu_read(ipv4_tcp_sk.sock);  	sock_net_set(ctl_sk, net);  	ctl_sk->sk_mark = (sk->sk_state == TCP_TIME_WAIT) ?  			   inet_twsk(sk)->tw_mark : READ_ONCE(sk->sk_mark); @@ -1020,6 +1023,7 @@ static void tcp_v4_send_ack(const struct sock *sk,  	sock_net_set(ctl_sk, &init_net);  	__TCP_INC_STATS(net, TCP_MIB_OUTSEGS); +	local_unlock_nested_bh(&ipv4_tcp_sk.bh_lock);  	local_bh_enable();  } @@ -1057,19 +1061,17 @@ static void tcp_v4_timewait_ack(struct sock *sk, struct sk_buff *skb)  #else  	if (0) {  #endif -#ifdef CONFIG_TCP_MD5SIG -	} else if (static_branch_unlikely(&tcp_md5_needed.key)) { +	} else if (static_branch_tcp_md5()) {  		key.md5_key = tcp_twsk_md5_key(tcptw);  		if (key.md5_key)  			key.type = TCP_KEY_MD5; -#endif  	}  	tcp_v4_send_ack(sk, skb,  			tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt,  			tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale,  			tcp_tw_tsval(tcptw), -			tcptw->tw_ts_recent, +			READ_ONCE(tcptw->tw_ts_recent),  			tw->tw_bound_dev_if, &key,  			tw->tw_transparent ? IP_REPLY_ARG_NOSRCCHECK : 0,  			tw->tw_tos, @@ -1131,8 +1133,7 @@ static void tcp_v4_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb,  #else  	if (0) {  #endif -#ifdef CONFIG_TCP_MD5SIG -	} else if (static_branch_unlikely(&tcp_md5_needed.key)) { +	} else if (static_branch_tcp_md5()) {  		const union tcp_md5_addr *addr;  		int l3index; @@ -1141,7 +1142,6 @@ static void tcp_v4_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb,  		key.md5_key = tcp_md5_do_lookup(sk, l3index, addr, AF_INET);  		if (key.md5_key)  			key.type = TCP_KEY_MD5; -#endif  	}  	tcp_v4_send_ack(sk, skb, seq, @@ -1939,7 +1939,7 @@ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)  reset:  	tcp_v4_send_reset(rsk, skb, sk_rst_convert_drop_reason(reason));  discard: -	kfree_skb_reason(skb, reason); +	sk_skb_reason_drop(sk, skb, reason);  	/* Be careful here. If this function gets more complicated and  	 * gcc suffers from register pressure on the x86, sk (in %ebx)  	 * might be destroyed here. This current version compiles correctly, @@ -2049,8 +2049,7 @@ bool tcp_add_backlog(struct sock *sk, struct sk_buff *skb,  	      TCP_SKB_CB(skb)->tcp_flags) & TCPHDR_ACK) ||  	    ((TCP_SKB_CB(tail)->tcp_flags ^  	      TCP_SKB_CB(skb)->tcp_flags) & (TCPHDR_ECE | TCPHDR_CWR)) || -	    !mptcp_skb_can_collapse(tail, skb) || -	    skb_cmp_decrypted(tail, skb) || +	    !tcp_skb_can_collapse_rx(tail, skb) ||  	    thtail->doff != th->doff ||  	    memcmp(thtail + 1, th + 1, hdrlen - sizeof(*th)))  		goto no_coalesce; @@ -2176,8 +2175,8 @@ int tcp_v4_rcv(struct sk_buff *skb)  	int dif = inet_iif(skb);  	const struct iphdr *iph;  	const struct tcphdr *th; +	struct sock *sk = NULL;  	bool refcounted; -	struct sock *sk;  	int ret;  	u32 isn; @@ -2376,7 +2375,7 @@ bad_packet:  discard_it:  	SKB_DR_OR(drop_reason, NOT_SPECIFIED);  	/* Discard frame. */ -	kfree_skb_reason(skb, drop_reason); +	sk_skb_reason_drop(sk, skb, drop_reason);  	return 0;  discard_and_relse: @@ -3506,6 +3505,7 @@ static int __net_init tcp_sk_init(struct net *net)  	net->ipv4.sysctl_tcp_shrink_window = 0;  	net->ipv4.sysctl_tcp_pingpong_thresh = 1; +	net->ipv4.sysctl_tcp_rto_min_us = jiffies_to_usecs(TCP_RTO_MIN);  	return 0;  } @@ -3620,7 +3620,9 @@ void __init tcp_v4_init(void)  		 */  		inet_sk(sk)->pmtudisc = IP_PMTUDISC_DO; -		per_cpu(ipv4_tcp_sk, cpu) = sk; +		sk->sk_clockid = CLOCK_MONOTONIC; + +		per_cpu(ipv4_tcp_sk.sock, cpu) = sk;  	}  	if (register_pernet_subsys(&tcp_sk_ops))  		panic("Failed to create the TCP control socket.\n"); |