diff options
Diffstat (limited to 'net/ipv4/tcp_input.c')
| -rw-r--r-- | net/ipv4/tcp_input.c | 28 | 
1 files changed, 24 insertions, 4 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index fdd88c3803a6..0003d409fec5 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -2478,6 +2478,9 @@ static void tcp_cwnd_reduction(struct sock *sk, const int prior_unsacked,  	int newly_acked_sacked = prior_unsacked -  				 (tp->packets_out - tp->sacked_out); +	if (newly_acked_sacked <= 0 || WARN_ON_ONCE(!tp->prior_cwnd)) +		return; +  	tp->prr_delivered += newly_acked_sacked;  	if (delta < 0) {  		u64 dividend = (u64)tp->snd_ssthresh * tp->prr_delivered + @@ -4481,19 +4484,34 @@ static int __must_check tcp_queue_rcv(struct sock *sk, struct sk_buff *skb, int  int tcp_send_rcvq(struct sock *sk, struct msghdr *msg, size_t size)  {  	struct sk_buff *skb; +	int err = -ENOMEM; +	int data_len = 0;  	bool fragstolen;  	if (size == 0)  		return 0; -	skb = alloc_skb(size, sk->sk_allocation); +	if (size > PAGE_SIZE) { +		int npages = min_t(size_t, size >> PAGE_SHIFT, MAX_SKB_FRAGS); + +		data_len = npages << PAGE_SHIFT; +		size = data_len + (size & ~PAGE_MASK); +	} +	skb = alloc_skb_with_frags(size - data_len, data_len, +				   PAGE_ALLOC_COSTLY_ORDER, +				   &err, sk->sk_allocation);  	if (!skb)  		goto err; +	skb_put(skb, size - data_len); +	skb->data_len = data_len; +	skb->len = size; +  	if (tcp_try_rmem_schedule(sk, skb, skb->truesize))  		goto err_free; -	if (memcpy_from_msg(skb_put(skb, size), msg, size)) +	err = skb_copy_datagram_from_iter(skb, 0, &msg->msg_iter, size); +	if (err)  		goto err_free;  	TCP_SKB_CB(skb)->seq = tcp_sk(sk)->rcv_nxt; @@ -4509,7 +4527,8 @@ int tcp_send_rcvq(struct sock *sk, struct msghdr *msg, size_t size)  err_free:  	kfree_skb(skb);  err: -	return -ENOMEM; +	return err; +  }  static void tcp_data_queue(struct sock *sk, struct sk_buff *skb) @@ -5667,6 +5686,7 @@ discard:  		}  		tp->rcv_nxt = TCP_SKB_CB(skb)->seq + 1; +		tp->copied_seq = tp->rcv_nxt;  		tp->rcv_wup = TCP_SKB_CB(skb)->seq + 1;  		/* RFC1323: The window in SYN & SYN/ACK segments is @@ -6187,7 +6207,7 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,  	tcp_openreq_init(req, &tmp_opt, skb, sk);  	/* Note: tcp_v6_init_req() might override ir_iif for link locals */ -	inet_rsk(req)->ir_iif = sk->sk_bound_dev_if; +	inet_rsk(req)->ir_iif = inet_request_bound_dev_if(sk, skb);  	af_ops->init_req(req, sk, skb);  | 
