diff options
Diffstat (limited to 'net/ipv4/tcp.c')
| -rw-r--r-- | net/ipv4/tcp.c | 38 | 
1 files changed, 28 insertions, 10 deletions
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 9d2118e5fbc7..541f26a67ba2 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -426,6 +426,17 @@ void tcp_init_sock(struct sock *sk)  }  EXPORT_SYMBOL(tcp_init_sock); +static void tcp_tx_timestamp(struct sock *sk, struct sk_buff *skb) +{ +	if (sk->sk_tsflags) { +		struct skb_shared_info *shinfo = skb_shinfo(skb); + +		sock_tx_timestamp(sk, &shinfo->tx_flags); +		if (shinfo->tx_flags & SKBTX_ANY_TSTAMP) +			shinfo->tskey = TCP_SKB_CB(skb)->seq + skb->len - 1; +	} +} +  /*   *	Wait for a TCP event.   * @@ -523,7 +534,7 @@ unsigned int tcp_poll(struct file *file, struct socket *sock, poll_table *wait)  	}  	/* This barrier is coupled with smp_wmb() in tcp_reset() */  	smp_rmb(); -	if (sk->sk_err) +	if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))  		mask |= POLLERR;  	return mask; @@ -959,8 +970,10 @@ new_segment:  		copied += copy;  		offset += copy; -		if (!(size -= copy)) +		if (!(size -= copy)) { +			tcp_tx_timestamp(sk, skb);  			goto out; +		}  		if (skb->len < size_goal || (flags & MSG_OOB))  			continue; @@ -1175,13 +1188,6 @@ new_segment:  					goto wait_for_memory;  				/* -				 * All packets are restored as if they have -				 * already been sent. -				 */ -				if (tp->repair) -					TCP_SKB_CB(skb)->when = tcp_time_stamp; - -				/*  				 * Check whether we can use HW checksum.  				 */  				if (sk->sk_route_caps & NETIF_F_ALL_CSUM) @@ -1190,6 +1196,13 @@ new_segment:  				skb_entail(sk, skb);  				copy = size_goal;  				max = size_goal; + +				/* All packets are restored as if they have +				 * already been sent. skb_mstamp isn't set to +				 * avoid wrong rtt estimation. +				 */ +				if (tp->repair) +					TCP_SKB_CB(skb)->sacked |= TCPCB_REPAIRED;  			}  			/* Try to append data to the end of skb. */ @@ -1252,8 +1265,10 @@ new_segment:  			from += copy;  			copied += copy; -			if ((seglen -= copy) == 0 && iovlen == 0) +			if ((seglen -= copy) == 0 && iovlen == 0) { +				tcp_tx_timestamp(sk, skb);  				goto out; +			}  			if (skb->len < max || (flags & MSG_OOB) || unlikely(tp->repair))  				continue; @@ -1617,6 +1632,9 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,  	struct sk_buff *skb;  	u32 urg_hole = 0; +	if (unlikely(flags & MSG_ERRQUEUE)) +		return ip_recv_error(sk, msg, len, addr_len); +  	if (sk_can_busy_loop(sk) && skb_queue_empty(&sk->sk_receive_queue) &&  	    (sk->sk_state == TCP_ESTABLISHED))  		sk_busy_loop(sk, nonblock);  |