Commit 8dce0aac authored by David S. Miller's avatar David S. Miller

[TCP]: Fix inaccuracies in tso_factor settings.

1) If tcp_{sendmsg,sendpage} tacks on more data to an
   existing SKB, this can make tso_factor inaccurate.
   Invalidate it, which forces it to be recalculated,
   by simply setting it to zero.
2) __tcp_trim_head() changes skb->len thus we need
   to recalculate tso_factor
3) BUG check that tcp_retrans_try_collapse() does not
   try to collapse packets with non-1 tso_factor
4) The Solaris FIN workaround in tcp_retransmit_skb()
   changes packet size, need to fixup tso_factor
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent f755f1fb
...@@ -691,6 +691,7 @@ static ssize_t do_tcp_sendpages(struct sock *sk, struct page **pages, int poffse ...@@ -691,6 +691,7 @@ static ssize_t do_tcp_sendpages(struct sock *sk, struct page **pages, int poffse
skb->ip_summed = CHECKSUM_HW; skb->ip_summed = CHECKSUM_HW;
tp->write_seq += copy; tp->write_seq += copy;
TCP_SKB_CB(skb)->end_seq += copy; TCP_SKB_CB(skb)->end_seq += copy;
TCP_SKB_CB(skb)->tso_factor = 0;
if (!copied) if (!copied)
TCP_SKB_CB(skb)->flags &= ~TCPCB_FLAG_PSH; TCP_SKB_CB(skb)->flags &= ~TCPCB_FLAG_PSH;
...@@ -937,6 +938,7 @@ int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, ...@@ -937,6 +938,7 @@ int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
tp->write_seq += copy; tp->write_seq += copy;
TCP_SKB_CB(skb)->end_seq += copy; TCP_SKB_CB(skb)->end_seq += copy;
TCP_SKB_CB(skb)->tso_factor = 0;
from += copy; from += copy;
copied += copy; copied += copy;
......
...@@ -553,7 +553,7 @@ unsigned char * __pskb_trim_head(struct sk_buff *skb, int len) ...@@ -553,7 +553,7 @@ unsigned char * __pskb_trim_head(struct sk_buff *skb, int len)
return skb->tail; return skb->tail;
} }
static int __tcp_trim_head(struct sock *sk, struct sk_buff *skb, u32 len) static int __tcp_trim_head(struct tcp_opt *tp, struct sk_buff *skb, u32 len)
{ {
if (skb_cloned(skb) && if (skb_cloned(skb) &&
pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
...@@ -567,12 +567,18 @@ static int __tcp_trim_head(struct sock *sk, struct sk_buff *skb, u32 len) ...@@ -567,12 +567,18 @@ static int __tcp_trim_head(struct sock *sk, struct sk_buff *skb, u32 len)
} }
skb->ip_summed = CHECKSUM_HW; skb->ip_summed = CHECKSUM_HW;
/* Any change of skb->len requires recalculation of tso
* factor and mss.
*/
tcp_set_skb_tso_factor(skb, tp->mss_cache_std);
return 0; return 0;
} }
static inline int tcp_trim_head(struct sock *sk, struct sk_buff *skb, u32 len) static inline int tcp_trim_head(struct tcp_opt *tp, struct sk_buff *skb, u32 len)
{ {
int err = __tcp_trim_head(sk, skb, len); int err = __tcp_trim_head(tp, skb, len);
if (!err) if (!err)
TCP_SKB_CB(skb)->seq += len; TCP_SKB_CB(skb)->seq += len;
...@@ -897,6 +903,9 @@ static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *skb, int m ...@@ -897,6 +903,9 @@ static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *skb, int m
((skb_size + next_skb_size) > mss_now)) ((skb_size + next_skb_size) > mss_now))
return; return;
BUG_ON(TCP_SKB_CB(skb)->tso_factor != 1 ||
TCP_SKB_CB(next_skb)->tso_factor != 1);
/* Ok. We will be able to collapse the packet. */ /* Ok. We will be able to collapse the packet. */
__skb_unlink(next_skb, next_skb->list); __skb_unlink(next_skb, next_skb->list);
...@@ -1018,7 +1027,7 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb) ...@@ -1018,7 +1027,7 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
if (skb->len > (data_end_seq - data_seq)) { if (skb->len > (data_end_seq - data_seq)) {
u32 to_trim = skb->len - (data_end_seq - data_seq); u32 to_trim = skb->len - (data_end_seq - data_seq);
if (__tcp_trim_head(sk, skb, to_trim)) if (__tcp_trim_head(tp, skb, to_trim))
return -ENOMEM; return -ENOMEM;
} }
...@@ -1032,7 +1041,7 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb) ...@@ -1032,7 +1041,7 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
tp->mss_cache = tp->mss_cache_std; tp->mss_cache = tp->mss_cache_std;
} }
if (tcp_trim_head(sk, skb, tp->snd_una - TCP_SKB_CB(skb)->seq)) if (tcp_trim_head(tp, skb, tp->snd_una - TCP_SKB_CB(skb)->seq))
return -ENOMEM; return -ENOMEM;
} }
...@@ -1080,6 +1089,7 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb) ...@@ -1080,6 +1089,7 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
tp->snd_una == (TCP_SKB_CB(skb)->end_seq - 1)) { tp->snd_una == (TCP_SKB_CB(skb)->end_seq - 1)) {
if (!pskb_trim(skb, 0)) { if (!pskb_trim(skb, 0)) {
TCP_SKB_CB(skb)->seq = TCP_SKB_CB(skb)->end_seq - 1; TCP_SKB_CB(skb)->seq = TCP_SKB_CB(skb)->end_seq - 1;
TCP_SKB_CB(skb)->tso_factor = 1;
skb->ip_summed = CHECKSUM_NONE; skb->ip_summed = CHECKSUM_NONE;
skb->csum = 0; skb->csum = 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