On Sat, Oct 23, 2004 at 07:50:40AM +1000, herbert wrote: > > So we don't really know whether it went further or not :) 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. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> 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? Cheers, -- Visit Openswan at http://www.openswan.org/ Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au> Home Page: http://gondor.apana.org.au/~herbert/ PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
===== net/ipv4/tcp_input.c 1.81 vs edited ===== --- 1.81/net/ipv4/tcp_input.c 2004-10-04 07:31:39 +10:00 +++ edited/net/ipv4/tcp_input.c 2004-10-23 09:12:42 +10:00 @@ -2369,25 +2369,19 @@ { 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; --- linux-2.6/net/ipv4/tcp_output.c.orig 2004-10-23 08:44:16.000000000 +1000 +++ linux-2.6/net/ipv4/tcp_output.c 2004-10-23 09:10:13.000000000 +1000 @@ -588,7 +588,7 @@ /* 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;