Discard tcp out-of-order queue if system limit is reached
Subsystems (3)
PATCH 1/1 Discard tcp out-of-order queue if system limit is reached
Hello!
tcp_prune_queue() doesn't prune an out-of-order queue if socket
is under rcvbuf. However even if socket is under rcvbuf but system-wide limit is reached then skb cannot be queued. It can lead to deadlock situation as any skb that fills sequence hole is dropped.
So discard out-of-order queue if system-wide limit is reached.
--- net/ipv4/tcp_input.c | 78 +++++++++++++++++++++++++++++++++---------------- 1 files changed, 52 insertions(+), 26 deletions(-)
net/ipv4/tcp_input.c +52 -26
@@ -3841,8 +3841,28 @@ static void tcp_ofo_queue(struct sock *sk) } } +static int tcp_prune_ofo_queue (struct sock *sk);static int tcp_prune_queue (struct sock *sk); +static inline int tcp_try_rmem_schedule (struct sock *sk,unsigned int size) +{ +if (atomic_read (&sk->sk_rmem_alloc) > sk->sk_rcvbuf || + !sk_rmem_schedule (sk, size)) { + +if (tcp_prune_queue (sk) <0 ) +return -1 ; + +if (!sk_rmem_schedule (sk, size)) { +if (!tcp_prune_ofo_queue (sk)) +return -1 ; + +if (!sk_rmem_schedule (sk, size)) +return -1 ; + } + } +return 0 ; +} +static void tcp_data_queue (struct sock *sk,struct sk_buff *skb) {struct tcphdr *th =tcp_hdr (skb);
@@ -3892,12 +3912,9 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)if (eaten <=0 ) { queue_and_out:if (eaten <0 && - (atomic_read (&sk->sk_rmem_alloc) > sk->sk_rcvbuf || - !sk_rmem_schedule (sk, skb->truesize))) { -if (tcp_prune_queue (sk) <0 || - !sk_rmem_schedule (sk, skb->truesize)) - goto drop; - } +tcp_try_rmem_schedule (sk, skb->truesize)) + goto drop; +skb_set_owner_r (skb, sk);__skb_queue_tail (&sk->sk_receive_queue, skb); }
@@ -3966,12 +3983,8 @@ drop:TCP_ECN_check_ce (tp, skb); -if (atomic_read (&sk->sk_rmem_alloc) > sk->sk_rcvbuf || - !sk_rmem_schedule (sk, skb->truesize)) { -if (tcp_prune_queue (sk) <0 || - !sk_rmem_schedule (sk, skb->truesize)) - goto drop; - } +if (tcp_try_rmem_schedule (sk, skb->truesize)) + goto drop;/* Disable header prediction. */ tp->pred_flags =0 ;
@@ -4198,6 +4211,32 @@ static void tcp_collapse_ofo_queue(struct sock *sk) } } +/* +* Purge the out-of-order queue. +* Return true if queue was pruned. +*/ +static int tcp_prune_ofo_queue (struct sock *sk) +{ +struct tcp_sock *tp =tcp_sk (sk); +int res =0 ; + +if (!skb_queue_empty (&tp->out_of_order_queue)) { +NET_INC_STATS_BH (LINUX_MIB_OFOPRUNED ); +__skb_queue_purge (&tp->out_of_order_queue); + +/* Reset SACK state. A conforming SACK implementation will +* do the same at a timeout based retransmit. When a connection +* is in a sad state like this, we care only about integrity +* of the connection not performance. +*/ +if (tp->rx_opt.sack_ok) +tcp_sack_reset (&tp->rx_opt); +sk_mem_reclaim (sk); + res =1 ; + } +return res; +} +/* Reduce allocated memory if we can, trying to get * the socket within its memory limits again. *
@@ -4231,20 +4270,7 @@ static int tcp_prune_queue(struct sock *sk)/* Collapsing did not help, destructive actions follow. * This must not ever occur. */ -/* First, purge the out_of_order queue. */ -if (!skb_queue_empty (&tp->out_of_order_queue)) { -NET_INC_STATS_BH (LINUX_MIB_OFOPRUNED ); -__skb_queue_purge (&tp->out_of_order_queue); - -/* Reset SACK state. A conforming SACK implementation will -* do the same at a timeout based retransmit. When a connection -* is in a sad state like this, we care only about integrity -* of the connection not performance. -*/ -if (tcp_is_sack (tp)) -tcp_sack_reset (&tp->rx_opt); -sk_mem_reclaim (sk); - } +tcp_prune_ofo_queue (sk);if (atomic_read (&sk->sk_rmem_alloc) <= sk->sk_rcvbuf)return 0 ;
Quoted 7 lines · Vitaliy Gusev
Hello!
tcp_prune_queue()doesn't prune an out-of-order queue if socket
is under rcvbuf. However even if socket is under rcvbuf but system-wide limit is reached then skb cannot be queued. It can lead to deadlock situation as any skb that fills sequence hole is dropped.
So discard out-of-order queue if system-wide limit is reached.
Thanks. At least the description makes much more sense than before now.
-Andi
Quoted 20 lines · On Tue, 15 Apr 2008 18:54:44 +0400 Vitaliy Gusev <[email protected]> wrote:
Hello!
tcp_prune_queue()doesn't prune an out-of-order queue if socket
is under rcvbuf. However even if socket is under rcvbuf but system-wide limit is reached then skb cannot be queued. It can lead to deadlock situation as any skb that fills sequence hole is dropped.
So discard out-of-order queue if system-wide limit is reached.Signed-off-by Vitaliy Gusev <[email protected]>--- net/ipv4/tcp_input.c | 78 +++++++++++++++++++++++++++++++++---------------- 1 files changed, 52 insertions(+), 26 deletions(-)net/ipv4/tcp_input.c +0
-0
net/ipv4/tcp_input.c static void tcp_ofo_queue(struct sock *sk) · line 3847
Quoted 7 lines
net/ipv4/tcp_input.c +2
-0@@ -3841,8 +3841,28 @@ static void tcp_ofo_queue(struct sock *sk) } } +static int tcp_prune_ofo_queue (struct sock *sk);static int tcp_prune_queue (struct sock *sk); +static inline int tcp_try_rmem_schedule (struct sock *sk,unsigned int size)
minor nit, current preferred style is to not use inline for used once functions, the compiler will do it anyway.
David Miller
maintainerFrom: Vitaliy Gusev <[email protected]>
Date: Tue, 15 Apr 2008 18:54:44 +0400
Quoted 7 lines
tcp_prune_queue()doesn't prune an out-of-order queue if socket
is under rcvbuf. However even if socket is under rcvbuf but system-wide limit is reached then skb cannot be queued. It can lead to deadlock situation as any skb that fills sequence hole is dropped.
So discard out-of-order queue if system-wide limit is reached.Signed-off-by Vitaliy Gusev <[email protected]>
I applied your original patch already, so I added the following relative patch.
Please provide relative fixup patches when I say that I've applied your patch already.
Thank you.
commit 56f367bbfd5a7439961499ca6a2f0822d2074d83
Author: Vitaliy Gusev <[email protected]> Date: Tue Apr 15 20:26:34 2008 -0700
[TCP]: Add return value indication to tcp_prune_ofo_queue().
Returns non-zero if tp->out_of_order_queue was seen non-empty. This allows tcp_try_rmem_schedule() to return early.
net/ipv4/tcp_input.c +9 -3
@@ -3841,7 +3841,7 @@ static void tcp_ofo_queue(struct sock *sk) } } -static void tcp_prune_ofo_queue (struct sock *sk); +static int tcp_prune_ofo_queue (struct sock *sk);static int tcp_prune_queue (struct sock *sk);static inline int tcp_try_rmem_schedule (struct sock *sk,unsigned int size)
@@ -3853,7 +3853,9 @@ static inline int tcp_try_rmem_schedule(struct sock *sk, unsigned int size)return -1 ;if (!sk_rmem_schedule (sk, size)) { -tcp_prune_ofo_queue (sk); +if (!tcp_prune_ofo_queue (sk)) +return -1 ; +if (!sk_rmem_schedule (sk, size))return -1 ; }
@@ -4211,10 +4213,12 @@ static void tcp_collapse_ofo_queue(struct sock *sk)/* * Purge the out-of-order queue. +* Return true if queue was pruned. */ -static void tcp_prune_ofo_queue (struct sock *sk) +static int tcp_prune_ofo_queue (struct sock *sk) {struct tcp_sock *tp =tcp_sk (sk); +int res =0 ;if (!skb_queue_empty (&tp->out_of_order_queue)) {NET_INC_STATS_BH (LINUX_MIB_OFOPRUNED );
@@ -4228,7 +4232,9 @@ static void tcp_prune_ofo_queue(struct sock *sk)if (tp->rx_opt.sack_ok)tcp_sack_reset (&tp->rx_opt);sk_mem_reclaim (sk); + res =1 ; } +return res; }/* Reduce allocated memory if we can, trying to get
Quoted 9 lines · David Miller
From: Vitaliy Gusev <[email protected]>
Date: Tue, 15 Apr 2008 18:54:44 +0400Quoted 6 lines
tcp_prune_queue()doesn't prune an out-of-order queue if socket
is under rcvbuf. However even if socket is under rcvbuf but system-wide limit is reached then skb cannot be queued. It can lead to deadlock situation as any skb that fills sequence hole is dropped.
So discard out-of-order queue if system-wide limit is reached.
Quoted 4 lines
Quoted 1 line
Signed-off-by Vitaliy Gusev <[email protected]>I applied your original patch already, so I added the following relative patch.
Could you please at least update the original description to the one from the new patch? That one was somewhat misleading imho.
-Andi
David Miller
maintainerFrom: Andi Kleen <[email protected]>
Date: Wed, 16 Apr 2008 09:01:45 +0200
Quoted 10 lines
Quoted 9 lines · David Miller
From: Vitaliy Gusev <[email protected]>
Date: Tue, 15 Apr 2008 18:54:44 +0400Quoted 6 lines
tcp_prune_queue()doesn't prune an out-of-order queue if socket
is under rcvbuf. However even if socket is under rcvbuf but system-wide limit is reached then skb cannot be queued. It can lead to deadlock situation as any skb that fills sequence hole is dropped.
So discard out-of-order queue if system-wide limit is reached.
Quoted 7 lines
Quoted 4 lines
Quoted 1 line
Signed-off-by Vitaliy Gusev <[email protected]>I applied your original patch already, so I added the following relative patch.
Could you please at least update the original description to the one from the new patch? That one was somewhat misleading imho.
It's already a few changesets deep in my tree and it's already pushed to kernel.org I really don't want to have to respin my tree and break it for all of my downstream tree developers just to make this commit message fixup.
Sorry.