+++ /dev/null
-From e42e8ccda949937872452f571638200f515090c2 Mon Sep 17 00:00:00 2001
-From: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi>
-Date: Sat, 4 Apr 2009 18:12:41 -0700
-Subject: tcp: Fix various bugs wrt. packet counting during fragmentation.
-
-
-[ Upstream commits: d3d2ae454501a4dec360995649e1b002a2ad90c5,
- 02276f3c962fd408fa9d441251067845f948bfcf,
- 797108d134a91afca9fa59c572336b279bc66afb,
- 9eb9362e569062e2f841b7a023e5fcde10ed63b4 ]
-
---------------------
-tcp: Don't clear hints when tcp_fragmenting
-
-1) We didn't remove any skbs, so no need to handle stale refs.
-
-2) scoreboard_skb_hint is trivial, no timestamps were changed
- so no need to clear that one
-
-3) lost_skb_hint needs tweaking similar to that of
- tcp_sacktag_one().
-
-Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi>
-Signed-off-by: David S. Miller <davem@davemloft.net>
---------------------
-tcp: fix corner case issue in segmentation during rexmitting
-
-If cur_mss grew very recently so that the previously G/TSOed skb
-now fits well into a single segment it would get send up in
-parts unless we calculate # of segments again. This corner-case
-could happen eg. after mtu probe completes or less than
-previously sack blocks are required for the opposite direction.
-
-Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi>
-Signed-off-by: David S. Miller <davem@davemloft.net>
---------------------
-tcp: add helper for counter tweaking due mid-wq change
-
-We need full-scale adjustment to fix a TCP miscount in the next
-patch, so just move it into a helper and call for that from the
-other places.
-
-Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi>
-Signed-off-by: David S. Miller <davem@davemloft.net>
---------------------
-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>
-Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-
----
- include/net/tcp.h | 15 -----------
- net/ipv4/tcp_output.c | 68 ++++++++++++++++++++++++++++++--------------------
- 2 files changed, 41 insertions(+), 42 deletions(-)
-
---- a/include/net/tcp.h
-+++ b/include/net/tcp.h
-@@ -610,21 +610,6 @@ static inline int tcp_skb_mss(const stru
- return skb_shinfo(skb)->gso_size;
- }
-
--static inline void tcp_dec_pcount_approx_int(__u32 *count, const int decr)
--{
-- if (*count) {
-- *count -= decr;
-- if ((int)*count < 0)
-- *count = 0;
-- }
--}
--
--static inline void tcp_dec_pcount_approx(__u32 *count,
-- const struct sk_buff *skb)
--{
-- tcp_dec_pcount_approx_int(count, tcp_skb_pcount(skb));
--}
--
- /* Events passed to congestion control interface */
- enum tcp_ca_event {
- CA_EVENT_TX_START, /* first transmit when no packets in flight */
---- a/net/ipv4/tcp_output.c
-+++ b/net/ipv4/tcp_output.c
-@@ -751,6 +751,36 @@ static void tcp_adjust_fackets_out(struc
- tp->fackets_out -= decr;
- }
-
-+/* Pcount in the middle of the write queue got changed, we need to do various
-+ * tweaks to fix counters
-+ */
-+static void tcp_adjust_pcount(struct sock *sk, struct sk_buff *skb, int decr)
-+{
-+ struct tcp_sock *tp = tcp_sk(sk);
-+
-+ tp->packets_out -= decr;
-+
-+ if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED)
-+ tp->sacked_out -= decr;
-+ if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS)
-+ tp->retrans_out -= decr;
-+ if (TCP_SKB_CB(skb)->sacked & TCPCB_LOST)
-+ tp->lost_out -= decr;
-+
-+ /* Reno case is special. Sigh... */
-+ if (tcp_is_reno(tp) && decr > 0)
-+ tp->sacked_out -= min_t(u32, tp->sacked_out, decr);
-+
-+ tcp_adjust_fackets_out(sk, skb, decr);
-+
-+ if (tp->lost_skb_hint &&
-+ before(TCP_SKB_CB(skb)->seq, TCP_SKB_CB(tp->lost_skb_hint)->seq) &&
-+ (tcp_is_fack(tp) || TCP_SKB_CB(skb)->sacked))
-+ tp->lost_cnt_hint -= decr;
-+
-+ tcp_verify_left_out(tp);
-+}
-+
- /* Function to create two new TCP segments. Shrinks the given segment
- * to the specified size and appends a new segment with the rest of the
- * packet to the list. This won't be called frequently, I hope.
-@@ -767,7 +797,6 @@ int tcp_fragment(struct sock *sk, struct
-
- BUG_ON(len > skb->len);
-
-- tcp_clear_retrans_hints_partial(tp);
- nsize = skb_headlen(skb) - len;
- if (nsize < 0)
- nsize = 0;
-@@ -834,22 +863,8 @@ int tcp_fragment(struct sock *sk, struct
- int diff = old_factor - tcp_skb_pcount(skb) -
- tcp_skb_pcount(buff);
-
-- tp->packets_out -= diff;
--
-- if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED)
-- tp->sacked_out -= diff;
-- if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS)
-- tp->retrans_out -= diff;
--
-- if (TCP_SKB_CB(skb)->sacked & TCPCB_LOST)
-- tp->lost_out -= diff;
--
-- /* Adjust Reno SACK estimate. */
-- if (tcp_is_reno(tp) && diff > 0) {
-- tcp_dec_pcount_approx_int(&tp->sacked_out, diff);
-- tcp_verify_left_out(tp);
-- }
-- tcp_adjust_fackets_out(sk, skb, diff);
-+ if (diff)
-+ tcp_adjust_pcount(sk, skb, diff);
- }
-
- /* Link BUFF into the send queue. */
-@@ -1829,22 +1844,14 @@ static void tcp_retrans_try_collapse(str
- * packet counting does not break.
- */
- TCP_SKB_CB(skb)->sacked |= TCP_SKB_CB(next_skb)->sacked & TCPCB_EVER_RETRANS;
-- if (TCP_SKB_CB(next_skb)->sacked & TCPCB_SACKED_RETRANS)
-- tp->retrans_out -= tcp_skb_pcount(next_skb);
-- if (TCP_SKB_CB(next_skb)->sacked & TCPCB_LOST)
-- tp->lost_out -= tcp_skb_pcount(next_skb);
-- /* Reno case is special. Sigh... */
-- if (tcp_is_reno(tp) && tp->sacked_out)
-- tcp_dec_pcount_approx(&tp->sacked_out, next_skb);
--
-- tcp_adjust_fackets_out(sk, next_skb, tcp_skb_pcount(next_skb));
-- tp->packets_out -= tcp_skb_pcount(next_skb);
-
- /* changed transmit queue under us so clear hints */
- tcp_clear_retrans_hints_partial(tp);
- if (next_skb == tp->retransmit_skb_hint)
- tp->retransmit_skb_hint = skb;
-
-+ tcp_adjust_pcount(sk, next_skb, tcp_skb_pcount(next_skb));
-+
- sk_wmem_free_skb(sk, next_skb);
- }
-
-@@ -1945,6 +1952,13 @@ int tcp_retransmit_skb(struct sock *sk,
- if (skb->len > cur_mss) {
- if (tcp_fragment(sk, skb, cur_mss, cur_mss))
- return -ENOMEM; /* We'll try again later. */
-+ } else {
-+ 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));
-+ }
- }
-
- /* Collapse two adjacent packets if worthwhile and we can. */