diff options
-rw-r--r-- | include/net/tcp.h | 1 | ||||
-rw-r--r-- | net/ipv4/tcp.c | 12 | ||||
-rw-r--r-- | net/ipv4/tcp_output.c | 2 |
3 files changed, 14 insertions, 1 deletions
diff --git a/include/net/tcp.h b/include/net/tcp.h index 4475aaf0af57..5bba80fbd1d9 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h | |||
@@ -370,6 +370,7 @@ extern int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
370 | extern int tcp_sendpage(struct sock *sk, struct page *page, int offset, | 370 | extern int tcp_sendpage(struct sock *sk, struct page *page, int offset, |
371 | size_t size, int flags); | 371 | size_t size, int flags); |
372 | extern void tcp_release_cb(struct sock *sk); | 372 | extern void tcp_release_cb(struct sock *sk); |
373 | extern void tcp_wfree(struct sk_buff *skb); | ||
373 | extern void tcp_write_timer_handler(struct sock *sk); | 374 | extern void tcp_write_timer_handler(struct sock *sk); |
374 | extern void tcp_delack_timer_handler(struct sock *sk); | 375 | extern void tcp_delack_timer_handler(struct sock *sk); |
375 | extern int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg); | 376 | extern int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg); |
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index a96f7b586277..963bda18486f 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c | |||
@@ -2885,6 +2885,7 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb, | |||
2885 | __be32 delta; | 2885 | __be32 delta; |
2886 | unsigned int oldlen; | 2886 | unsigned int oldlen; |
2887 | unsigned int mss; | 2887 | unsigned int mss; |
2888 | struct sk_buff *gso_skb = skb; | ||
2888 | 2889 | ||
2889 | if (!pskb_may_pull(skb, sizeof(*th))) | 2890 | if (!pskb_may_pull(skb, sizeof(*th))) |
2890 | goto out; | 2891 | goto out; |
@@ -2953,6 +2954,17 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb, | |||
2953 | th->cwr = 0; | 2954 | th->cwr = 0; |
2954 | } while (skb->next); | 2955 | } while (skb->next); |
2955 | 2956 | ||
2957 | /* Following permits TCP Small Queues to work well with GSO : | ||
2958 | * The callback to TCP stack will be called at the time last frag | ||
2959 | * is freed at TX completion, and not right now when gso_skb | ||
2960 | * is freed by GSO engine | ||
2961 | */ | ||
2962 | if (gso_skb->destructor == tcp_wfree) { | ||
2963 | swap(gso_skb->sk, skb->sk); | ||
2964 | swap(gso_skb->destructor, skb->destructor); | ||
2965 | swap(gso_skb->truesize, skb->truesize); | ||
2966 | } | ||
2967 | |||
2956 | delta = htonl(oldlen + (skb->tail - skb->transport_header) + | 2968 | delta = htonl(oldlen + (skb->tail - skb->transport_header) + |
2957 | skb->data_len); | 2969 | skb->data_len); |
2958 | th->check = ~csum_fold((__force __wsum)((__force u32)th->check + | 2970 | th->check = ~csum_fold((__force __wsum)((__force u32)th->check + |
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index af354c98fdb5..d12694353540 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c | |||
@@ -787,7 +787,7 @@ void __init tcp_tasklet_init(void) | |||
787 | * We cant xmit new skbs from this context, as we might already | 787 | * We cant xmit new skbs from this context, as we might already |
788 | * hold qdisc lock. | 788 | * hold qdisc lock. |
789 | */ | 789 | */ |
790 | static void tcp_wfree(struct sk_buff *skb) | 790 | void tcp_wfree(struct sk_buff *skb) |
791 | { | 791 | { |
792 | struct sock *sk = skb->sk; | 792 | struct sock *sk = skb->sk; |
793 | struct tcp_sock *tp = tcp_sk(sk); | 793 | struct tcp_sock *tp = tcp_sk(sk); |