diff options
Diffstat (limited to 'net/ipv4/tcp_output.c')
| -rw-r--r-- | net/ipv4/tcp_output.c | 34 | 
1 files changed, 30 insertions, 4 deletions
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index e9f985e42405..6818042cd8a9 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -1730,7 +1730,7 @@ u32 tcp_tso_autosize(const struct sock *sk, unsigned int mss_now,  	 */  	segs = max_t(u32, bytes / mss_now, min_tso_segs); -	return min_t(u32, segs, sk->sk_gso_max_segs); +	return segs;  }  EXPORT_SYMBOL(tcp_tso_autosize); @@ -1742,9 +1742,10 @@ static u32 tcp_tso_segs(struct sock *sk, unsigned int mss_now)  	const struct tcp_congestion_ops *ca_ops = inet_csk(sk)->icsk_ca_ops;  	u32 tso_segs = ca_ops->tso_segs_goal ? ca_ops->tso_segs_goal(sk) : 0; -	return tso_segs ? : -		tcp_tso_autosize(sk, mss_now, -				 sock_net(sk)->ipv4.sysctl_tcp_min_tso_segs); +	if (!tso_segs) +		tso_segs = tcp_tso_autosize(sk, mss_now, +				sock_net(sk)->ipv4.sysctl_tcp_min_tso_segs); +	return min_t(u32, tso_segs, sk->sk_gso_max_segs);  }  /* Returns the portion of skb which can be sent right away */ @@ -2027,6 +2028,24 @@ static inline void tcp_mtu_check_reprobe(struct sock *sk)  	}  } +static bool tcp_can_coalesce_send_queue_head(struct sock *sk, int len) +{ +	struct sk_buff *skb, *next; + +	skb = tcp_send_head(sk); +	tcp_for_write_queue_from_safe(skb, next, sk) { +		if (len <= skb->len) +			break; + +		if (unlikely(TCP_SKB_CB(skb)->eor)) +			return false; + +		len -= skb->len; +	} + +	return true; +} +  /* Create a new MTU probe if we are ready.   * MTU probe is regularly attempting to increase the path MTU by   * deliberately sending larger packets.  This discovers routing @@ -2099,6 +2118,9 @@ static int tcp_mtu_probe(struct sock *sk)  			return 0;  	} +	if (!tcp_can_coalesce_send_queue_head(sk, probe_size)) +		return -1; +  	/* We're allowed to probe.  Build it now. */  	nskb = sk_stream_alloc_skb(sk, probe_size, GFP_ATOMIC, false);  	if (!nskb) @@ -2134,6 +2156,10 @@ static int tcp_mtu_probe(struct sock *sk)  			/* We've eaten all the data from this skb.  			 * Throw it away. */  			TCP_SKB_CB(nskb)->tcp_flags |= TCP_SKB_CB(skb)->tcp_flags; +			/* If this is the last SKB we copy and eor is set +			 * we need to propagate it to the new skb. +			 */ +			TCP_SKB_CB(nskb)->eor = TCP_SKB_CB(skb)->eor;  			tcp_unlink_write_queue(skb, sk);  			sk_wmem_free_skb(sk, skb);  		} else {  | 

