aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorNeil Horman <nhorman@tuxdriver.com>2006-06-18 01:59:03 -0400
committerDavid S. Miller <davem@davemloft.net>2006-06-18 01:59:03 -0400
commitd5b9f4c083b0e3102f3101545279f623680cb3a0 (patch)
tree86d5f77d14a8ae687e585ec4535ca8038e450ab9 /net
parentd7c2c9e3977e4312d093ac092761798d4d47c9e0 (diff)
[SCTP]: Fix persistent slowdown in sctp when a gap ack consumes rx buffer.
In the event that our entire receive buffer is full with a series of chunks that represent a single gap-ack, and then we accept a chunk (or chunks) that fill in the gap between the ctsn and the first gap, we renege chunks from the end of the buffer, which effectively does nothing but move our gap to the end of our received tsn stream. This does little but move our missing tsns down stream a little, and, if the sender is sending sufficiently large retransmit frames, the result is a perpetual slowdown which can never be recovered from, since the only chunk that can be accepted to allow progress in the tsn stream necessitates that a new gap be created to make room for it. This leads to a constant need for retransmits, and subsequent receiver stalls. The fix I've come up with is to deliver the frame without reneging if we have a full receive buffer and the receiving sockets sk_receive_queue is empty(indicating that the receive buffer is being blocked by a missing tsn). Signed-off-by: Neil Horman <nhorman@tuxdriver.com> Signed-off-by: Sridhar Samudrala <sri@us.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/sctp/sm_statefuns.c10
1 files changed, 9 insertions, 1 deletions
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
index 8bc279219a72..9e58144f4851 100644
--- a/net/sctp/sm_statefuns.c
+++ b/net/sctp/sm_statefuns.c
@@ -5293,10 +5293,18 @@ static int sctp_eat_data(const struct sctp_association *asoc,
5293 * seems a bit troublesome in that frag_point varies based on 5293 * seems a bit troublesome in that frag_point varies based on
5294 * PMTU. In cases, such as loopback, this might be a rather 5294 * PMTU. In cases, such as loopback, this might be a rather
5295 * large spill over. 5295 * large spill over.
5296 * NOTE: If we have a full receive buffer here, we only renege if
5297 * our receiver can still make progress without the tsn being
5298 * received. We do this because in the event that the associations
5299 * receive queue is empty we are filling a leading gap, and since
5300 * reneging moves the gap to the end of the tsn stream, we are likely
5301 * to stall again very shortly. Avoiding the renege when we fill a
5302 * leading gap is a good heuristic for avoiding such steady state
5303 * stalls.
5296 */ 5304 */
5297 if (!asoc->rwnd || asoc->rwnd_over || 5305 if (!asoc->rwnd || asoc->rwnd_over ||
5298 (datalen > asoc->rwnd + asoc->frag_point) || 5306 (datalen > asoc->rwnd + asoc->frag_point) ||
5299 rcvbuf_over) { 5307 (rcvbuf_over && (!skb_queue_len(&sk->sk_receive_queue)))) {
5300 5308
5301 /* If this is the next TSN, consider reneging to make 5309 /* If this is the next TSN, consider reneging to make
5302 * room. Note: Playing nice with a confused sender. A 5310 * room. Note: Playing nice with a confused sender. A