diff options
Diffstat (limited to 'net/ipv4/tcp_input.c')
-rw-r--r-- | net/ipv4/tcp_input.c | 49 |
1 files changed, 26 insertions, 23 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 3e07a64ca44e..d377f4854cb8 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
@@ -2926,13 +2926,14 @@ static void tcp_enter_recovery(struct sock *sk, bool ece_ack) | |||
2926 | * tcp_xmit_retransmit_queue(). | 2926 | * tcp_xmit_retransmit_queue(). |
2927 | */ | 2927 | */ |
2928 | static void tcp_fastretrans_alert(struct sock *sk, int pkts_acked, | 2928 | static void tcp_fastretrans_alert(struct sock *sk, int pkts_acked, |
2929 | int newly_acked_sacked, bool is_dupack, | 2929 | int prior_sacked, bool is_dupack, |
2930 | int flag) | 2930 | int flag) |
2931 | { | 2931 | { |
2932 | struct inet_connection_sock *icsk = inet_csk(sk); | 2932 | struct inet_connection_sock *icsk = inet_csk(sk); |
2933 | struct tcp_sock *tp = tcp_sk(sk); | 2933 | struct tcp_sock *tp = tcp_sk(sk); |
2934 | int do_lost = is_dupack || ((flag & FLAG_DATA_SACKED) && | 2934 | int do_lost = is_dupack || ((flag & FLAG_DATA_SACKED) && |
2935 | (tcp_fackets_out(tp) > tp->reordering)); | 2935 | (tcp_fackets_out(tp) > tp->reordering)); |
2936 | int newly_acked_sacked = 0; | ||
2936 | int fast_rexmit = 0; | 2937 | int fast_rexmit = 0; |
2937 | 2938 | ||
2938 | if (WARN_ON(!tp->packets_out && tp->sacked_out)) | 2939 | if (WARN_ON(!tp->packets_out && tp->sacked_out)) |
@@ -2992,6 +2993,7 @@ static void tcp_fastretrans_alert(struct sock *sk, int pkts_acked, | |||
2992 | tcp_add_reno_sack(sk); | 2993 | tcp_add_reno_sack(sk); |
2993 | } else | 2994 | } else |
2994 | do_lost = tcp_try_undo_partial(sk, pkts_acked); | 2995 | do_lost = tcp_try_undo_partial(sk, pkts_acked); |
2996 | newly_acked_sacked = pkts_acked + tp->sacked_out - prior_sacked; | ||
2995 | break; | 2997 | break; |
2996 | case TCP_CA_Loss: | 2998 | case TCP_CA_Loss: |
2997 | if (flag & FLAG_DATA_ACKED) | 2999 | if (flag & FLAG_DATA_ACKED) |
@@ -3013,6 +3015,7 @@ static void tcp_fastretrans_alert(struct sock *sk, int pkts_acked, | |||
3013 | if (is_dupack) | 3015 | if (is_dupack) |
3014 | tcp_add_reno_sack(sk); | 3016 | tcp_add_reno_sack(sk); |
3015 | } | 3017 | } |
3018 | newly_acked_sacked = pkts_acked + tp->sacked_out - prior_sacked; | ||
3016 | 3019 | ||
3017 | if (icsk->icsk_ca_state <= TCP_CA_Disorder) | 3020 | if (icsk->icsk_ca_state <= TCP_CA_Disorder) |
3018 | tcp_try_undo_dsack(sk); | 3021 | tcp_try_undo_dsack(sk); |
@@ -3590,7 +3593,6 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) | |||
3590 | int prior_packets; | 3593 | int prior_packets; |
3591 | int prior_sacked = tp->sacked_out; | 3594 | int prior_sacked = tp->sacked_out; |
3592 | int pkts_acked = 0; | 3595 | int pkts_acked = 0; |
3593 | int newly_acked_sacked = 0; | ||
3594 | bool frto_cwnd = false; | 3596 | bool frto_cwnd = false; |
3595 | 3597 | ||
3596 | /* If the ack is older than previous acks | 3598 | /* If the ack is older than previous acks |
@@ -3666,8 +3668,6 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) | |||
3666 | flag |= tcp_clean_rtx_queue(sk, prior_fackets, prior_snd_una); | 3668 | flag |= tcp_clean_rtx_queue(sk, prior_fackets, prior_snd_una); |
3667 | 3669 | ||
3668 | pkts_acked = prior_packets - tp->packets_out; | 3670 | pkts_acked = prior_packets - tp->packets_out; |
3669 | newly_acked_sacked = (prior_packets - prior_sacked) - | ||
3670 | (tp->packets_out - tp->sacked_out); | ||
3671 | 3671 | ||
3672 | if (tp->frto_counter) | 3672 | if (tp->frto_counter) |
3673 | frto_cwnd = tcp_process_frto(sk, flag); | 3673 | frto_cwnd = tcp_process_frto(sk, flag); |
@@ -3681,7 +3681,7 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) | |||
3681 | tcp_may_raise_cwnd(sk, flag)) | 3681 | tcp_may_raise_cwnd(sk, flag)) |
3682 | tcp_cong_avoid(sk, ack, prior_in_flight); | 3682 | tcp_cong_avoid(sk, ack, prior_in_flight); |
3683 | is_dupack = !(flag & (FLAG_SND_UNA_ADVANCED | FLAG_NOT_DUP)); | 3683 | is_dupack = !(flag & (FLAG_SND_UNA_ADVANCED | FLAG_NOT_DUP)); |
3684 | tcp_fastretrans_alert(sk, pkts_acked, newly_acked_sacked, | 3684 | tcp_fastretrans_alert(sk, pkts_acked, prior_sacked, |
3685 | is_dupack, flag); | 3685 | is_dupack, flag); |
3686 | } else { | 3686 | } else { |
3687 | if ((flag & FLAG_DATA_ACKED) && !frto_cwnd) | 3687 | if ((flag & FLAG_DATA_ACKED) && !frto_cwnd) |
@@ -3698,7 +3698,7 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) | |||
3698 | no_queue: | 3698 | no_queue: |
3699 | /* If data was DSACKed, see if we can undo a cwnd reduction. */ | 3699 | /* If data was DSACKed, see if we can undo a cwnd reduction. */ |
3700 | if (flag & FLAG_DSACKING_ACK) | 3700 | if (flag & FLAG_DSACKING_ACK) |
3701 | tcp_fastretrans_alert(sk, pkts_acked, newly_acked_sacked, | 3701 | tcp_fastretrans_alert(sk, pkts_acked, prior_sacked, |
3702 | is_dupack, flag); | 3702 | is_dupack, flag); |
3703 | /* If this ack opens up a zero window, clear backoff. It was | 3703 | /* If this ack opens up a zero window, clear backoff. It was |
3704 | * being used to time the probes, and is probably far higher than | 3704 | * being used to time the probes, and is probably far higher than |
@@ -3718,8 +3718,7 @@ old_ack: | |||
3718 | */ | 3718 | */ |
3719 | if (TCP_SKB_CB(skb)->sacked) { | 3719 | if (TCP_SKB_CB(skb)->sacked) { |
3720 | flag |= tcp_sacktag_write_queue(sk, skb, prior_snd_una); | 3720 | flag |= tcp_sacktag_write_queue(sk, skb, prior_snd_una); |
3721 | newly_acked_sacked = tp->sacked_out - prior_sacked; | 3721 | tcp_fastretrans_alert(sk, pkts_acked, prior_sacked, |
3722 | tcp_fastretrans_alert(sk, pkts_acked, newly_acked_sacked, | ||
3723 | is_dupack, flag); | 3722 | is_dupack, flag); |
3724 | } | 3723 | } |
3725 | 3724 | ||
@@ -4351,19 +4350,20 @@ static void tcp_ofo_queue(struct sock *sk) | |||
4351 | static bool tcp_prune_ofo_queue(struct sock *sk); | 4350 | static bool tcp_prune_ofo_queue(struct sock *sk); |
4352 | static int tcp_prune_queue(struct sock *sk); | 4351 | static int tcp_prune_queue(struct sock *sk); |
4353 | 4352 | ||
4354 | static int tcp_try_rmem_schedule(struct sock *sk, unsigned int size) | 4353 | static int tcp_try_rmem_schedule(struct sock *sk, struct sk_buff *skb, |
4354 | unsigned int size) | ||
4355 | { | 4355 | { |
4356 | if (atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf || | 4356 | if (atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf || |
4357 | !sk_rmem_schedule(sk, size)) { | 4357 | !sk_rmem_schedule(sk, skb, size)) { |
4358 | 4358 | ||
4359 | if (tcp_prune_queue(sk) < 0) | 4359 | if (tcp_prune_queue(sk) < 0) |
4360 | return -1; | 4360 | return -1; |
4361 | 4361 | ||
4362 | if (!sk_rmem_schedule(sk, size)) { | 4362 | if (!sk_rmem_schedule(sk, skb, size)) { |
4363 | if (!tcp_prune_ofo_queue(sk)) | 4363 | if (!tcp_prune_ofo_queue(sk)) |
4364 | return -1; | 4364 | return -1; |
4365 | 4365 | ||
4366 | if (!sk_rmem_schedule(sk, size)) | 4366 | if (!sk_rmem_schedule(sk, skb, size)) |
4367 | return -1; | 4367 | return -1; |
4368 | } | 4368 | } |
4369 | } | 4369 | } |
@@ -4418,7 +4418,7 @@ static void tcp_data_queue_ofo(struct sock *sk, struct sk_buff *skb) | |||
4418 | 4418 | ||
4419 | TCP_ECN_check_ce(tp, skb); | 4419 | TCP_ECN_check_ce(tp, skb); |
4420 | 4420 | ||
4421 | if (unlikely(tcp_try_rmem_schedule(sk, skb->truesize))) { | 4421 | if (unlikely(tcp_try_rmem_schedule(sk, skb, skb->truesize))) { |
4422 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPOFODROP); | 4422 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPOFODROP); |
4423 | __kfree_skb(skb); | 4423 | __kfree_skb(skb); |
4424 | return; | 4424 | return; |
@@ -4552,17 +4552,17 @@ static int __must_check tcp_queue_rcv(struct sock *sk, struct sk_buff *skb, int | |||
4552 | 4552 | ||
4553 | int tcp_send_rcvq(struct sock *sk, struct msghdr *msg, size_t size) | 4553 | int tcp_send_rcvq(struct sock *sk, struct msghdr *msg, size_t size) |
4554 | { | 4554 | { |
4555 | struct sk_buff *skb; | 4555 | struct sk_buff *skb = NULL; |
4556 | struct tcphdr *th; | 4556 | struct tcphdr *th; |
4557 | bool fragstolen; | 4557 | bool fragstolen; |
4558 | 4558 | ||
4559 | if (tcp_try_rmem_schedule(sk, size + sizeof(*th))) | ||
4560 | goto err; | ||
4561 | |||
4562 | skb = alloc_skb(size + sizeof(*th), sk->sk_allocation); | 4559 | skb = alloc_skb(size + sizeof(*th), sk->sk_allocation); |
4563 | if (!skb) | 4560 | if (!skb) |
4564 | goto err; | 4561 | goto err; |
4565 | 4562 | ||
4563 | if (tcp_try_rmem_schedule(sk, skb, size + sizeof(*th))) | ||
4564 | goto err_free; | ||
4565 | |||
4566 | th = (struct tcphdr *)skb_put(skb, sizeof(*th)); | 4566 | th = (struct tcphdr *)skb_put(skb, sizeof(*th)); |
4567 | skb_reset_transport_header(skb); | 4567 | skb_reset_transport_header(skb); |
4568 | memset(th, 0, sizeof(*th)); | 4568 | memset(th, 0, sizeof(*th)); |
@@ -4633,7 +4633,7 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb) | |||
4633 | if (eaten <= 0) { | 4633 | if (eaten <= 0) { |
4634 | queue_and_out: | 4634 | queue_and_out: |
4635 | if (eaten < 0 && | 4635 | if (eaten < 0 && |
4636 | tcp_try_rmem_schedule(sk, skb->truesize)) | 4636 | tcp_try_rmem_schedule(sk, skb, skb->truesize)) |
4637 | goto drop; | 4637 | goto drop; |
4638 | 4638 | ||
4639 | eaten = tcp_queue_rcv(sk, skb, 0, &fragstolen); | 4639 | eaten = tcp_queue_rcv(sk, skb, 0, &fragstolen); |
@@ -4661,7 +4661,7 @@ queue_and_out: | |||
4661 | 4661 | ||
4662 | if (eaten > 0) | 4662 | if (eaten > 0) |
4663 | kfree_skb_partial(skb, fragstolen); | 4663 | kfree_skb_partial(skb, fragstolen); |
4664 | else if (!sock_flag(sk, SOCK_DEAD)) | 4664 | if (!sock_flag(sk, SOCK_DEAD)) |
4665 | sk->sk_data_ready(sk, 0); | 4665 | sk->sk_data_ready(sk, 0); |
4666 | return; | 4666 | return; |
4667 | } | 4667 | } |
@@ -5391,6 +5391,8 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb, | |||
5391 | { | 5391 | { |
5392 | struct tcp_sock *tp = tcp_sk(sk); | 5392 | struct tcp_sock *tp = tcp_sk(sk); |
5393 | 5393 | ||
5394 | if (unlikely(sk->sk_rx_dst == NULL)) | ||
5395 | inet_csk(sk)->icsk_af_ops->sk_rx_dst_set(sk, skb); | ||
5394 | /* | 5396 | /* |
5395 | * Header prediction. | 5397 | * Header prediction. |
5396 | * The code loosely follows the one in the famous | 5398 | * The code loosely follows the one in the famous |
@@ -5475,7 +5477,9 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb, | |||
5475 | if (tp->copied_seq == tp->rcv_nxt && | 5477 | if (tp->copied_seq == tp->rcv_nxt && |
5476 | len - tcp_header_len <= tp->ucopy.len) { | 5478 | len - tcp_header_len <= tp->ucopy.len) { |
5477 | #ifdef CONFIG_NET_DMA | 5479 | #ifdef CONFIG_NET_DMA |
5478 | if (tcp_dma_try_early_copy(sk, skb, tcp_header_len)) { | 5480 | if (tp->ucopy.task == current && |
5481 | sock_owned_by_user(sk) && | ||
5482 | tcp_dma_try_early_copy(sk, skb, tcp_header_len)) { | ||
5479 | copied_early = 1; | 5483 | copied_early = 1; |
5480 | eaten = 1; | 5484 | eaten = 1; |
5481 | } | 5485 | } |
@@ -5552,8 +5556,7 @@ no_ack: | |||
5552 | #endif | 5556 | #endif |
5553 | if (eaten) | 5557 | if (eaten) |
5554 | kfree_skb_partial(skb, fragstolen); | 5558 | kfree_skb_partial(skb, fragstolen); |
5555 | else | 5559 | sk->sk_data_ready(sk, 0); |
5556 | sk->sk_data_ready(sk, 0); | ||
5557 | return 0; | 5560 | return 0; |
5558 | } | 5561 | } |
5559 | } | 5562 | } |
@@ -5602,7 +5605,7 @@ void tcp_finish_connect(struct sock *sk, struct sk_buff *skb) | |||
5602 | tcp_set_state(sk, TCP_ESTABLISHED); | 5605 | tcp_set_state(sk, TCP_ESTABLISHED); |
5603 | 5606 | ||
5604 | if (skb != NULL) { | 5607 | if (skb != NULL) { |
5605 | sk->sk_rx_dst = dst_clone(skb_dst(skb)); | 5608 | icsk->icsk_af_ops->sk_rx_dst_set(sk, skb); |
5606 | security_inet_conn_established(sk, skb); | 5609 | security_inet_conn_established(sk, skb); |
5607 | } | 5610 | } |
5608 | 5611 | ||