Commit bf520a21 authored by David S. Miller's avatar David S. Miller Committed by Linus Torvalds

[TCP]: Set PSH bit on all outgoing TSO frames.

Helps with crazy Mac OS-X TCP implementations which delay the
recvmsg() wakeup of the user until push is seen.

Based upon ideas from Alexey Kuznetsov, and a preliminary
patch by Stephen Hemminger.
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 245f9eba
...@@ -408,6 +408,16 @@ static void tcp_queue_skb(struct sock *sk, struct sk_buff *skb) ...@@ -408,6 +408,16 @@ static void tcp_queue_skb(struct sock *sk, struct sk_buff *skb)
sk->sk_send_head = skb; sk->sk_send_head = skb;
} }
static inline void tcp_tso_set_push(struct sk_buff *skb)
{
/* Force push to be on for any TSO frames to workaround
* problems with busted implementations like Mac OS-X that
* hold off socket receive wakeups until push is seen.
*/
if (tcp_skb_pcount(skb) > 1)
TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_PSH;
}
/* Send _single_ skb sitting at the send head. This function requires /* Send _single_ skb sitting at the send head. This function requires
* true push pending frames to setup probe timer etc. * true push pending frames to setup probe timer etc.
*/ */
...@@ -419,6 +429,7 @@ void tcp_push_one(struct sock *sk, unsigned cur_mss) ...@@ -419,6 +429,7 @@ void tcp_push_one(struct sock *sk, unsigned cur_mss)
if (tcp_snd_test(tp, skb, cur_mss, TCP_NAGLE_PUSH)) { if (tcp_snd_test(tp, skb, cur_mss, TCP_NAGLE_PUSH)) {
/* Send it out now. */ /* Send it out now. */
TCP_SKB_CB(skb)->when = tcp_time_stamp; TCP_SKB_CB(skb)->when = tcp_time_stamp;
tcp_tso_set_push(skb);
if (!tcp_transmit_skb(sk, skb_clone(skb, sk->sk_allocation))) { if (!tcp_transmit_skb(sk, skb_clone(skb, sk->sk_allocation))) {
sk->sk_send_head = NULL; sk->sk_send_head = NULL;
tp->snd_nxt = TCP_SKB_CB(skb)->end_seq; tp->snd_nxt = TCP_SKB_CB(skb)->end_seq;
...@@ -755,6 +766,7 @@ int tcp_write_xmit(struct sock *sk, int nonagle) ...@@ -755,6 +766,7 @@ int tcp_write_xmit(struct sock *sk, int nonagle)
} }
TCP_SKB_CB(skb)->when = tcp_time_stamp; TCP_SKB_CB(skb)->when = tcp_time_stamp;
tcp_tso_set_push(skb);
if (tcp_transmit_skb(sk, skb_clone(skb, GFP_ATOMIC))) if (tcp_transmit_skb(sk, skb_clone(skb, GFP_ATOMIC)))
break; break;
...@@ -1096,6 +1108,7 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb) ...@@ -1096,6 +1108,7 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
* is still in somebody's hands, else make a clone. * is still in somebody's hands, else make a clone.
*/ */
TCP_SKB_CB(skb)->when = tcp_time_stamp; TCP_SKB_CB(skb)->when = tcp_time_stamp;
tcp_tso_set_push(skb);
err = tcp_transmit_skb(sk, (skb_cloned(skb) ? err = tcp_transmit_skb(sk, (skb_cloned(skb) ?
pskb_copy(skb, GFP_ATOMIC): pskb_copy(skb, GFP_ATOMIC):
...@@ -1668,6 +1681,7 @@ int tcp_write_wakeup(struct sock *sk) ...@@ -1668,6 +1681,7 @@ int tcp_write_wakeup(struct sock *sk)
TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_PSH; TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_PSH;
TCP_SKB_CB(skb)->when = tcp_time_stamp; TCP_SKB_CB(skb)->when = tcp_time_stamp;
tcp_tso_set_push(skb);
err = tcp_transmit_skb(sk, skb_clone(skb, GFP_ATOMIC)); err = tcp_transmit_skb(sk, skb_clone(skb, GFP_ATOMIC));
if (!err) { if (!err) {
update_send_head(sk, tp, skb); update_send_head(sk, tp, skb);
......
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