Commit f335c143 authored by Herbert Xu's avatar Herbert Xu Committed by David S. Miller

[TCP]: Handle real partial-ACKs of TSO frames correctly.

Actually, I think we've caught your crash now.  If that code path
is triggering at all, then it'll trigger with TSO packets too.  If
we get a truly partial ack on a TSO packet, then tcp_tso_acked will
not trim it off.  So we will fall through to this last-ditch trim
call, which doesn't update packets_out.

There are two solutions to this problem.  I've taken the simpler
approach for now.  We simply trim off the partial bits in tcp_tso_acked
and live with the fact that the packet counters may differ from
what's on the netwrok by one.

Later on we can 'fix' this by remembering where the original TSO
packet started from, perhaps in skb->h or somewhere.  Dave, is this
worth it?
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 7515caf1
...@@ -2369,25 +2369,19 @@ static int tcp_tso_acked(struct sock *sk, struct sk_buff *skb, ...@@ -2369,25 +2369,19 @@ static int tcp_tso_acked(struct sock *sk, struct sk_buff *skb,
{ {
struct tcp_opt *tp = tcp_sk(sk); struct tcp_opt *tp = tcp_sk(sk);
struct tcp_skb_cb *scb = TCP_SKB_CB(skb); struct tcp_skb_cb *scb = TCP_SKB_CB(skb);
__u32 mss = tcp_skb_mss(skb); __u32 seq = tp->snd_una;
__u32 snd_una = tp->snd_una; __u32 packets_acked;
__u32 orig_seq, seq;
__u32 packets_acked = 0;
int acked = 0; int acked = 0;
/* If we get here, the whole TSO packet has not been /* If we get here, the whole TSO packet has not been
* acked. * acked.
*/ */
BUG_ON(!after(scb->end_seq, snd_una)); BUG_ON(!after(scb->end_seq, seq));
seq = orig_seq = scb->seq; packets_acked = tcp_skb_pcount(skb);
while (!after(seq + mss, snd_una)) { if (tcp_trim_head(sk, skb, seq - scb->seq))
packets_acked++;
seq += mss;
}
if (tcp_trim_head(sk, skb, (seq - orig_seq)))
return 0; return 0;
packets_acked -= tcp_skb_pcount(skb);
if (packets_acked) { if (packets_acked) {
__u8 sacked = scb->sacked; __u8 sacked = scb->sacked;
......
...@@ -588,7 +588,7 @@ int tcp_trim_head(struct sock *sk, struct sk_buff *skb, u32 len) ...@@ -588,7 +588,7 @@ int tcp_trim_head(struct sock *sk, struct sk_buff *skb, u32 len)
/* Any change of skb->len requires recalculation of tso /* Any change of skb->len requires recalculation of tso
* factor and mss. * factor and mss.
*/ */
if (tcp_skb_mss(skb)) if (tcp_skb_pcount(skb) > 1)
tcp_set_skb_tso_segs(skb, tcp_skb_mss(skb)); tcp_set_skb_tso_segs(skb, tcp_skb_mss(skb));
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment