diff options
| author | Herbert Xu <herbert@gondor.apana.org.au> | 2004-10-25 06:57:45 -0700 |
|---|---|---|
| committer | David S. Miller <davem@nuts.davemloft.net> | 2004-10-25 06:57:45 -0700 |
| commit | f335c143218df5b29b9d55211e6a6141ce1b67fd (patch) | |
| tree | 5da2bff36931adb6e2f8ea83d76cb47bdc7804ac | |
| parent | 7515caf10ea7ef7d433d50a213769225f44d8180 (diff) | |
[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: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | net/ipv4/tcp_input.c | 18 | ||||
| -rw-r--r-- | net/ipv4/tcp_output.c | 2 |
2 files changed, 7 insertions, 13 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 559ba0c55da5..e8769f30f0c6 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -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_skb_cb *scb = TCP_SKB_CB(skb); - __u32 mss = tcp_skb_mss(skb); - __u32 snd_una = tp->snd_una; - __u32 orig_seq, seq; - __u32 packets_acked = 0; + __u32 seq = tp->snd_una; + __u32 packets_acked; int acked = 0; /* If we get here, the whole TSO packet has not been * acked. */ - BUG_ON(!after(scb->end_seq, snd_una)); + BUG_ON(!after(scb->end_seq, seq)); - seq = orig_seq = scb->seq; - while (!after(seq + mss, snd_una)) { - packets_acked++; - seq += mss; - } - - if (tcp_trim_head(sk, skb, (seq - orig_seq))) + packets_acked = tcp_skb_pcount(skb); + if (tcp_trim_head(sk, skb, seq - scb->seq)) return 0; + packets_acked -= tcp_skb_pcount(skb); if (packets_acked) { __u8 sacked = scb->sacked; diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index b268b7d65976..0b08a3499b29 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -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 * factor and mss. */ - if (tcp_skb_mss(skb)) + if (tcp_skb_pcount(skb) > 1) tcp_set_skb_tso_segs(skb, tcp_skb_mss(skb)); return 0; |
