summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteve Lin <stlin@nvidia.com>2012-12-04 11:53:47 -0800
committerMandar Padmawar <mpadmawar@nvidia.com>2013-03-06 00:36:33 -0800
commit4b63cd6432841b6db91bfb5a120cfbc974855c6f (patch)
tree2bcd33c878f9f22ea90986b77898b4f1f0305583
parent0aa10b64ccf9ddc506862481b5e3f209f6285866 (diff)
CHROMIUM: tcp: Avoid merging segments on the OOO queue into a cloned SKB
TCP tries to merge socket buffers in the out-of-order queue when they are sequential. This is generally a good thing to save memory and speed up processing, but can lead to problems when it expands a buffer that has previously been cloned. We have encountered a bug with a confused/broken receive queue, that we think might have been caused by this problem, as the smsc95xx driver uses cloned buffers in its receive path. Thanks to edumazet for pointing that out and suggesting this fix. This patch makes sure that this code path only expands socket buffers that have not been cloned and just enqueues them normally in the other case. In upstream kernels starting with 3.5, the affected code has been refactored into tcp_try_coalesce with commit 1402d36, which has later been patched to fix this issue in commit 923dd34. The fix has not been backported into the upstream 3.4 kernel. BUG=chromium-os:35827 TEST=None Signed-off-by: Julius Werner <jwerner@chromium.org> Original-author: Julius Werner Bug 1206597 Bug 1232607 Change-Id: I08fdf47b42d903b5079ad0985edd491b421ac7ca Signed-off-by: Steve Lin <stlin@nvidia.com> Reviewed-on: http://git-master/r/203898 Reviewed-by: Brandon Casey <bcasey@nvidia.com> Reviewed-by: Mark Kuo <mkuo@nvidia.com> GVS: Gerrit_Virtual_Submit
-rw-r--r--net/ipv4/tcp_input.c4
1 files changed, 3 insertions, 1 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 56a9c8d0bef1..6b017383119e 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -4496,7 +4496,9 @@ static void tcp_data_queue_ofo(struct sock *sk, struct sk_buff *skb)
* to avoid future tcp_collapse_ofo_queue(),
* probably the most expensive function in tcp stack.
*/
- if (skb->len <= skb_tailroom(skb1) && !tcp_hdr(skb)->fin) {
+ if (skb->len <= skb_tailroom(skb1) &&
+ !tcp_hdr(skb)->fin &&
+ !skb_cloned(skb1)) {
NET_INC_STATS_BH(sock_net(sk),
LINUX_MIB_TCPRCVCOALESCE);
BUG_ON(skb_copy_bits(skb, 0,