aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/tcp_input.c
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2012-05-02 05:58:29 -0400
committerDavid S. Miller <davem@davemloft.net>2012-05-02 21:11:11 -0400
commitb081f85c2977b1cbb6e635d53d9512f1ef985972 (patch)
tree3b41dfe3ee282c175907e8bcf9614385115fa2e6 /net/ipv4/tcp_input.c
parent923dd347b8904c24bcac89bf038ed4da87f8aa90 (diff)
net: implement tcp coalescing in tcp_queue_rcv()
Extend tcp coalescing implementing it from tcp_queue_rcv(), the main receiver function when application is not blocked in recvmsg(). Function tcp_queue_rcv() is moved a bit to allow its call from tcp_data_queue() This gives good results especially if GRO could not kick, and if skb head is a fragment. Signed-off-by: Eric Dumazet <edumazet@google.com> Cc: Alexander Duyck <alexander.h.duyck@intel.com> Cc: Neal Cardwell <ncardwell@google.com> Cc: Tom Herbert <therbert@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/tcp_input.c')
-rw-r--r--net/ipv4/tcp_input.c40
1 files changed, 21 insertions, 19 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index a8829370f712..2f696ef13dcd 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -4739,6 +4739,22 @@ end:
4739 skb_set_owner_r(skb, sk); 4739 skb_set_owner_r(skb, sk);
4740} 4740}
4741 4741
4742int tcp_queue_rcv(struct sock *sk, struct sk_buff *skb, int hdrlen,
4743 bool *fragstolen)
4744{
4745 int eaten;
4746 struct sk_buff *tail = skb_peek_tail(&sk->sk_receive_queue);
4747
4748 __skb_pull(skb, hdrlen);
4749 eaten = (tail &&
4750 tcp_try_coalesce(sk, tail, skb, fragstolen)) ? 1 : 0;
4751 tcp_sk(sk)->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
4752 if (!eaten) {
4753 __skb_queue_tail(&sk->sk_receive_queue, skb);
4754 skb_set_owner_r(skb, sk);
4755 }
4756 return eaten;
4757}
4742 4758
4743static void tcp_data_queue(struct sock *sk, struct sk_buff *skb) 4759static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
4744{ 4760{
@@ -4785,20 +4801,12 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
4785 } 4801 }
4786 4802
4787 if (eaten <= 0) { 4803 if (eaten <= 0) {
4788 struct sk_buff *tail;
4789queue_and_out: 4804queue_and_out:
4790 if (eaten < 0 && 4805 if (eaten < 0 &&
4791 tcp_try_rmem_schedule(sk, skb->truesize)) 4806 tcp_try_rmem_schedule(sk, skb->truesize))
4792 goto drop; 4807 goto drop;
4793 4808
4794 tail = skb_peek_tail(&sk->sk_receive_queue); 4809 eaten = tcp_queue_rcv(sk, skb, 0, &fragstolen);
4795 eaten = (tail &&
4796 tcp_try_coalesce(sk, tail, skb,
4797 &fragstolen)) ? 1 : 0;
4798 if (eaten <= 0) {
4799 skb_set_owner_r(skb, sk);
4800 __skb_queue_tail(&sk->sk_receive_queue, skb);
4801 }
4802 } 4810 }
4803 tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq; 4811 tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
4804 if (skb->len) 4812 if (skb->len)
@@ -5493,14 +5501,6 @@ discard:
5493 return 0; 5501 return 0;
5494} 5502}
5495 5503
5496void tcp_queue_rcv(struct sock *sk, struct sk_buff *skb, int hdrlen)
5497{
5498 __skb_pull(skb, hdrlen);
5499 __skb_queue_tail(&sk->sk_receive_queue, skb);
5500 skb_set_owner_r(skb, sk);
5501 tcp_sk(sk)->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
5502}
5503
5504/* 5504/*
5505 * TCP receive function for the ESTABLISHED state. 5505 * TCP receive function for the ESTABLISHED state.
5506 * 5506 *
@@ -5609,6 +5609,7 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
5609 } else { 5609 } else {
5610 int eaten = 0; 5610 int eaten = 0;
5611 int copied_early = 0; 5611 int copied_early = 0;
5612 bool fragstolen = false;
5612 5613
5613 if (tp->copied_seq == tp->rcv_nxt && 5614 if (tp->copied_seq == tp->rcv_nxt &&
5614 len - tcp_header_len <= tp->ucopy.len) { 5615 len - tcp_header_len <= tp->ucopy.len) {
@@ -5666,7 +5667,8 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
5666 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPHPHITS); 5667 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPHPHITS);
5667 5668
5668 /* Bulk data transfer: receiver */ 5669 /* Bulk data transfer: receiver */
5669 tcp_queue_rcv(sk, skb, tcp_header_len); 5670 eaten = tcp_queue_rcv(sk, skb, tcp_header_len,
5671 &fragstolen);
5670 } 5672 }
5671 5673
5672 tcp_event_data_recv(sk, skb); 5674 tcp_event_data_recv(sk, skb);
@@ -5688,7 +5690,7 @@ no_ack:
5688 else 5690 else
5689#endif 5691#endif
5690 if (eaten) 5692 if (eaten)
5691 __kfree_skb(skb); 5693 kfree_skb_partial(skb, fragstolen);
5692 else 5694 else
5693 sk->sk_data_ready(sk, 0); 5695 sk->sk_data_ready(sk, 0);
5694 return 0; 5696 return 0;