diff options
Diffstat (limited to 'net/ipv4/tcp.c')
| -rw-r--r-- | net/ipv4/tcp.c | 55 | 
1 files changed, 26 insertions, 29 deletions
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 970e9a2cca4a..6cdfce6f2867 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -1000,7 +1000,7 @@ new_segment:  	i = skb_shinfo(skb)->nr_frags;  	can_coalesce = skb_can_coalesce(skb, i, page, offset); -	if (!can_coalesce && i >= sysctl_max_skb_frags) { +	if (!can_coalesce && i >= READ_ONCE(sysctl_max_skb_frags)) {  		tcp_mark_push(tp, skb);  		goto new_segment;  	} @@ -1015,7 +1015,7 @@ new_segment:  		skb_frag_size_add(&skb_shinfo(skb)->frags[i - 1], copy);  	} else {  		get_page(page); -		skb_fill_page_desc(skb, i, page, offset, copy); +		skb_fill_page_desc_noacc(skb, i, page, offset, copy);  	}  	if (!(flags & MSG_NO_SHARED_FRAGS)) @@ -1354,7 +1354,7 @@ new_segment:  			if (!skb_can_coalesce(skb, i, pfrag->page,  					      pfrag->offset)) { -				if (i >= sysctl_max_skb_frags) { +				if (i >= READ_ONCE(sysctl_max_skb_frags)) {  					tcp_mark_push(tp, skb);  					goto new_segment;  				} @@ -1567,17 +1567,11 @@ static int tcp_peek_sndq(struct sock *sk, struct msghdr *msg, int len)   * calculation of whether or not we must ACK for the sake of   * a window update.   */ -void tcp_cleanup_rbuf(struct sock *sk, int copied) +static void __tcp_cleanup_rbuf(struct sock *sk, int copied)  {  	struct tcp_sock *tp = tcp_sk(sk);  	bool time_to_ack = false; -	struct sk_buff *skb = skb_peek(&sk->sk_receive_queue); - -	WARN(skb && !before(tp->copied_seq, TCP_SKB_CB(skb)->end_seq), -	     "cleanup rbuf bug: copied %X seq %X rcvnxt %X\n", -	     tp->copied_seq, TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt); -  	if (inet_csk_ack_scheduled(sk)) {  		const struct inet_connection_sock *icsk = inet_csk(sk); @@ -1623,6 +1617,17 @@ void tcp_cleanup_rbuf(struct sock *sk, int copied)  		tcp_send_ack(sk);  } +void tcp_cleanup_rbuf(struct sock *sk, int copied) +{ +	struct sk_buff *skb = skb_peek(&sk->sk_receive_queue); +	struct tcp_sock *tp = tcp_sk(sk); + +	WARN(skb && !before(tp->copied_seq, TCP_SKB_CB(skb)->end_seq), +	     "cleanup rbuf bug: copied %X seq %X rcvnxt %X\n", +	     tp->copied_seq, TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt); +	__tcp_cleanup_rbuf(sk, copied); +} +  static void tcp_eat_recv_skb(struct sock *sk, struct sk_buff *skb)  {  	__skb_unlink(skb, &sk->sk_receive_queue); @@ -1756,34 +1761,26 @@ int tcp_read_skb(struct sock *sk, skb_read_actor_t recv_actor)  	if (sk->sk_state == TCP_LISTEN)  		return -ENOTCONN; -	while ((skb = tcp_recv_skb(sk, seq, &offset)) != NULL) { -		int used; - -		__skb_unlink(skb, &sk->sk_receive_queue); -		used = recv_actor(sk, skb); -		if (used <= 0) { -			if (!copied) -				copied = used; -			break; -		} -		seq += used; -		copied += used; +	skb = tcp_recv_skb(sk, seq, &offset); +	if (!skb) +		return 0; -		if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) { -			consume_skb(skb); +	__skb_unlink(skb, &sk->sk_receive_queue); +	WARN_ON(!skb_set_owner_sk_safe(skb, sk)); +	copied = recv_actor(sk, skb); +	if (copied >= 0) { +		seq += copied; +		if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN)  			++seq; -			break; -		} -		consume_skb(skb); -		break;  	} +	consume_skb(skb);  	WRITE_ONCE(tp->copied_seq, seq);  	tcp_rcv_space_adjust(sk);  	/* Clean up data we have read: This will do ACK frames. */  	if (copied > 0) -		tcp_cleanup_rbuf(sk, copied); +		__tcp_cleanup_rbuf(sk, copied);  	return copied;  }  | 
