From: Herbert Xu <[EMAIL PROTECTED]> Date: Mon, 22 Aug 2005 13:04:31 +1000
> > + > > + fack_count += pcount; > > > > in_sack = !after(start_seq, TCP_SKB_CB(skb)->seq) && > > !before(end_seq, TCP_SKB_CB(skb)->end_seq); > > Maybe I'm missing something subtle here :) But it seems to me that > your patch will end up only processing the second half of the result > of tcp_fragment and skip the first bit. Thinking about this some more... why would I need to use anyting other than "SKB"? SKB is where the front part of the split data is placed, and skb->next contains the subsequent data. So just using "skb" should be fine. We also don't need to jump back to the top of the loop because the first test: /* The retransmission queue is always in order, so * we can short-circuit the walk early. */ if (!before(TCP_SKB_CB(skb)->seq, end_seq)) break; is by definition not going to pass. The patch below should address the rest of your concerns. A further simplification seems possible, in that all of the tp->*_out modifications can be keyed upon the "skb_ever_sent" arg to tcp_fragment(). diff --git a/include/net/tcp.h b/include/net/tcp.h --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -855,7 +855,7 @@ extern int tcp_retransmit_skb(struct soc extern void tcp_xmit_retransmit_queue(struct sock *); extern void tcp_simple_retransmit(struct sock *); extern int tcp_trim_head(struct sock *, struct sk_buff *, u32); -extern int tcp_fragment(struct sock *, struct sk_buff *, u32, unsigned int); +extern int tcp_fragment(struct sock *, struct sk_buff *, u32, unsigned int, int); extern void tcp_send_probe0(struct sock *); extern void tcp_send_partial(struct sock *); diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -978,7 +978,7 @@ tcp_sacktag_write_queue(struct sock *sk, else pkt_len = (end_seq - TCP_SKB_CB(skb)->seq); - if (tcp_fragment(sk, skb, pkt_len, pkt_len)) + if (tcp_fragment(sk, skb, pkt_len, pkt_len, 1)) break; pcount = tcp_skb_pcount(skb); } diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -427,11 +427,11 @@ static void tcp_set_skb_tso_segs(struct * packet to the list. This won't be called frequently, I hope. * Remember, these are still headerless SKBs at this point. */ -int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, unsigned int mss_now) +int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, unsigned int mss_now, int skb_ever_sent) { struct tcp_sock *tp = tcp_sk(sk); struct sk_buff *buff; - int nsize; + int nsize, old_factor; u16 flags; nsize = skb_headlen(skb) - len; @@ -489,6 +489,8 @@ int tcp_fragment(struct sock *sk, struct tp->left_out -= tcp_skb_pcount(skb); } + old_factor = tcp_skb_pcount(skb); + /* Fix up tso_factor for both original and new SKB. */ tcp_set_skb_tso_segs(sk, skb, mss_now); tcp_set_skb_tso_segs(sk, buff, mss_now); @@ -503,6 +505,17 @@ int tcp_fragment(struct sock *sk, struct tp->left_out += tcp_skb_pcount(buff); } + if (skb_ever_sent) { + int diff = old_factor - tcp_skb_pcount(skb) - + tcp_skb_pcount(buff); + tp->packets_out -= diff; + if (diff > 0) { + tp->fackets_out -= diff; + if ((int)tp->fackets_out < 0) + tp->fackets_out = 0; + } + } + /* Link BUFF into the send queue. */ skb_header_release(buff); __skb_append(skb, buff); @@ -862,7 +875,7 @@ static int tso_fragment(struct sock *sk, /* All of a TSO frame must be composed of paged data. */ if (skb->len != skb->data_len) - return tcp_fragment(sk, skb, len, mss_now); + return tcp_fragment(sk, skb, len, mss_now, 0); buff = sk_stream_alloc_pskb(sk, 0, 0, GFP_ATOMIC); if (unlikely(buff == NULL)) @@ -1360,22 +1373,8 @@ int tcp_retransmit_skb(struct sock *sk, return -EAGAIN; if (skb->len > cur_mss) { - int old_factor = tcp_skb_pcount(skb); - int diff; - - if (tcp_fragment(sk, skb, cur_mss, cur_mss)) + if (tcp_fragment(sk, skb, cur_mss, cur_mss, 1)) return -ENOMEM; /* We'll try again later. */ - - /* New SKB created, account for it. */ - diff = old_factor - tcp_skb_pcount(skb) - - tcp_skb_pcount(skb->next); - tp->packets_out -= diff; - - if (diff > 0) { - tp->fackets_out -= diff; - if ((int)tp->fackets_out < 0) - tp->fackets_out = 0; - } } /* Collapse two adjacent packets if worthwhile and we can. */ @@ -1972,7 +1971,7 @@ int tcp_write_wakeup(struct sock *sk) skb->len > mss) { seg_size = min(seg_size, mss); TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_PSH; - if (tcp_fragment(sk, skb, seg_size, mss)) + if (tcp_fragment(sk, skb, seg_size, mss, 0)) return -1; } else if (!tcp_skb_pcount(skb)) tcp_set_skb_tso_segs(sk, skb, mss); - To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html