|
@@ -861,7 +861,8 @@ static int tso_fragment(struct sock *sk, struct sk_buff *skb, unsigned int len,
|
|
u16 flags;
|
|
u16 flags;
|
|
|
|
|
|
/* All of a TSO frame must be composed of paged data. */
|
|
/* All of a TSO frame must be composed of paged data. */
|
|
- BUG_ON(skb->len != skb->data_len);
|
|
|
|
|
|
+ if (skb->len != skb->data_len)
|
|
|
|
+ return tcp_fragment(sk, skb, len, mss_now);
|
|
|
|
|
|
buff = sk_stream_alloc_pskb(sk, 0, 0, GFP_ATOMIC);
|
|
buff = sk_stream_alloc_pskb(sk, 0, 0, GFP_ATOMIC);
|
|
if (unlikely(buff == NULL))
|
|
if (unlikely(buff == NULL))
|
|
@@ -974,6 +975,8 @@ static int tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle)
|
|
|
|
|
|
sent_pkts = 0;
|
|
sent_pkts = 0;
|
|
while ((skb = sk->sk_send_head)) {
|
|
while ((skb = sk->sk_send_head)) {
|
|
|
|
+ unsigned int limit;
|
|
|
|
+
|
|
tso_segs = tcp_init_tso_segs(sk, skb, mss_now);
|
|
tso_segs = tcp_init_tso_segs(sk, skb, mss_now);
|
|
BUG_ON(!tso_segs);
|
|
BUG_ON(!tso_segs);
|
|
|
|
|
|
@@ -994,9 +997,10 @@ static int tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle)
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ limit = mss_now;
|
|
if (tso_segs > 1) {
|
|
if (tso_segs > 1) {
|
|
- u32 limit = tcp_window_allows(tp, skb,
|
|
|
|
- mss_now, cwnd_quota);
|
|
|
|
|
|
+ limit = tcp_window_allows(tp, skb,
|
|
|
|
+ mss_now, cwnd_quota);
|
|
|
|
|
|
if (skb->len < limit) {
|
|
if (skb->len < limit) {
|
|
unsigned int trim = skb->len % mss_now;
|
|
unsigned int trim = skb->len % mss_now;
|
|
@@ -1004,15 +1008,12 @@ static int tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle)
|
|
if (trim)
|
|
if (trim)
|
|
limit = skb->len - trim;
|
|
limit = skb->len - trim;
|
|
}
|
|
}
|
|
- if (skb->len > limit) {
|
|
|
|
- if (tso_fragment(sk, skb, limit, mss_now))
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- } else if (unlikely(skb->len > mss_now)) {
|
|
|
|
- if (unlikely(tcp_fragment(sk, skb, mss_now, mss_now)))
|
|
|
|
- break;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if (skb->len > limit &&
|
|
|
|
+ unlikely(tso_fragment(sk, skb, limit, mss_now)))
|
|
|
|
+ break;
|
|
|
|
+
|
|
TCP_SKB_CB(skb)->when = tcp_time_stamp;
|
|
TCP_SKB_CB(skb)->when = tcp_time_stamp;
|
|
|
|
|
|
if (unlikely(tcp_transmit_skb(sk, skb_clone(skb, GFP_ATOMIC))))
|
|
if (unlikely(tcp_transmit_skb(sk, skb_clone(skb, GFP_ATOMIC))))
|
|
@@ -1064,11 +1065,14 @@ void tcp_push_one(struct sock *sk, unsigned int mss_now)
|
|
cwnd_quota = tcp_snd_test(sk, skb, mss_now, TCP_NAGLE_PUSH);
|
|
cwnd_quota = tcp_snd_test(sk, skb, mss_now, TCP_NAGLE_PUSH);
|
|
|
|
|
|
if (likely(cwnd_quota)) {
|
|
if (likely(cwnd_quota)) {
|
|
|
|
+ unsigned int limit;
|
|
|
|
+
|
|
BUG_ON(!tso_segs);
|
|
BUG_ON(!tso_segs);
|
|
|
|
|
|
|
|
+ limit = mss_now;
|
|
if (tso_segs > 1) {
|
|
if (tso_segs > 1) {
|
|
- u32 limit = tcp_window_allows(tp, skb,
|
|
|
|
- mss_now, cwnd_quota);
|
|
|
|
|
|
+ limit = tcp_window_allows(tp, skb,
|
|
|
|
+ mss_now, cwnd_quota);
|
|
|
|
|
|
if (skb->len < limit) {
|
|
if (skb->len < limit) {
|
|
unsigned int trim = skb->len % mss_now;
|
|
unsigned int trim = skb->len % mss_now;
|
|
@@ -1076,15 +1080,12 @@ void tcp_push_one(struct sock *sk, unsigned int mss_now)
|
|
if (trim)
|
|
if (trim)
|
|
limit = skb->len - trim;
|
|
limit = skb->len - trim;
|
|
}
|
|
}
|
|
- if (skb->len > limit) {
|
|
|
|
- if (unlikely(tso_fragment(sk, skb, limit, mss_now)))
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
- } else if (unlikely(skb->len > mss_now)) {
|
|
|
|
- if (unlikely(tcp_fragment(sk, skb, mss_now, mss_now)))
|
|
|
|
- return;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if (skb->len > limit &&
|
|
|
|
+ unlikely(tso_fragment(sk, skb, limit, mss_now)))
|
|
|
|
+ return;
|
|
|
|
+
|
|
/* Send it out now. */
|
|
/* Send it out now. */
|
|
TCP_SKB_CB(skb)->when = tcp_time_stamp;
|
|
TCP_SKB_CB(skb)->when = tcp_time_stamp;
|
|
|
|
|