diff options
author | Eric Dumazet <edumazet@google.com> | 2016-05-03 00:49:25 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-05-04 12:44:36 -0400 |
commit | d4011239f46ac6e407af61e3f74d1e3874fc9394 (patch) | |
tree | 5091043fd26ab8871104ba087894d9842a399d10 /net/ipv4/tcp.c | |
parent | cba653210056cf47cc1969f831f05ddfb99ee2bd (diff) |
tcp: guarantee forward progress in tcp_sendmsg()
Under high rx pressure, it is possible tcp_sendmsg() never has a
chance to allocate an skb and loop forever as sk_flush_backlog()
would always return true.
Fix this by calling sk_flush_backlog() only if one skb had been
allocated and filled before last backlog check.
Fixes: d41a69f1d390 ("tcp: make tcp_sendmsg() aware of socket backlog")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Acked-by: Soheil Hassas Yeganeh <soheil@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/tcp.c')
-rw-r--r-- | net/ipv4/tcp.c | 7 |
1 files changed, 5 insertions, 2 deletions
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index b945c2b046c5..5c7ed147449c 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c | |||
@@ -1084,6 +1084,7 @@ int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) | |||
1084 | struct sockcm_cookie sockc; | 1084 | struct sockcm_cookie sockc; |
1085 | int flags, err, copied = 0; | 1085 | int flags, err, copied = 0; |
1086 | int mss_now = 0, size_goal, copied_syn = 0; | 1086 | int mss_now = 0, size_goal, copied_syn = 0; |
1087 | bool process_backlog = false; | ||
1087 | bool sg; | 1088 | bool sg; |
1088 | long timeo; | 1089 | long timeo; |
1089 | 1090 | ||
@@ -1167,9 +1168,10 @@ new_segment: | |||
1167 | if (!sk_stream_memory_free(sk)) | 1168 | if (!sk_stream_memory_free(sk)) |
1168 | goto wait_for_sndbuf; | 1169 | goto wait_for_sndbuf; |
1169 | 1170 | ||
1170 | if (sk_flush_backlog(sk)) | 1171 | if (process_backlog && sk_flush_backlog(sk)) { |
1172 | process_backlog = false; | ||
1171 | goto restart; | 1173 | goto restart; |
1172 | 1174 | } | |
1173 | skb = sk_stream_alloc_skb(sk, | 1175 | skb = sk_stream_alloc_skb(sk, |
1174 | select_size(sk, sg), | 1176 | select_size(sk, sg), |
1175 | sk->sk_allocation, | 1177 | sk->sk_allocation, |
@@ -1177,6 +1179,7 @@ new_segment: | |||
1177 | if (!skb) | 1179 | if (!skb) |
1178 | goto wait_for_memory; | 1180 | goto wait_for_memory; |
1179 | 1181 | ||
1182 | process_backlog = true; | ||
1180 | /* | 1183 | /* |
1181 | * Check whether we can use HW checksum. | 1184 | * Check whether we can use HW checksum. |
1182 | */ | 1185 | */ |