diff options
author | Ilpo Järvinen <ilpo.jarvinen@helsinki.fi> | 2009-04-01 23:18:20 +0000 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-04-02 16:31:45 -0700 |
commit | 9eb9362e569062e2f841b7a023e5fcde10ed63b4 (patch) | |
tree | 06dc2aa031ca9cd604ece8a9fd5c5bc8502b2257 /net | |
parent | 797108d134a91afca9fa59c572336b279bc66afb (diff) | |
download | linux-9eb9362e569062e2f841b7a023e5fcde10ed63b4.tar.gz linux-9eb9362e569062e2f841b7a023e5fcde10ed63b4.tar.bz2 linux-9eb9362e569062e2f841b7a023e5fcde10ed63b4.zip |
tcp: miscounts due to tcp_fragment pcount reset
It seems that trivial reset of pcount to one was not sufficient
in tcp_retransmit_skb. Multiple counters experience a positive
miscount when skb's pcount gets lowered without the necessary
adjustments (depending on skb's sacked bits which exactly), at
worst a packets_out miscount can crash at RTO if the write queue
is empty!
Triggering this requires mss change, so bidir tcp or mtu probe or
like.
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi>
Reported-by: Markus Trippelsdorf <markus@trippelsdorf.de>
Tested-by: Uwe Bugla <uwe.bugla@gmx.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv4/tcp_output.c | 7 |
1 files changed, 6 insertions, 1 deletions
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index f1db89bb3aa7..53300fa2359f 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -1893,7 +1893,12 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb) if (tcp_fragment(sk, skb, cur_mss, cur_mss)) return -ENOMEM; /* We'll try again later. */ } else { - tcp_init_tso_segs(sk, skb, cur_mss); + int oldpcount = tcp_skb_pcount(skb); + + if (unlikely(oldpcount > 1)) { + tcp_init_tso_segs(sk, skb, cur_mss); + tcp_adjust_pcount(sk, skb, oldpcount - tcp_skb_pcount(skb)); + } } tcp_retrans_try_collapse(sk, skb, cur_mss); |