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

Reply via email to