summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2013-10-15 22:54:30 +0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-11-04 16:23:40 +0400
commit11db1e4cee071defc371d0fc7f1740024fbe5b06 (patch)
tree3f31e7f8abf5be8eee3c2bd2de3306d1b41c233a /include
parent3cebd7931a6f3007c3eb53942934772cc3b6ee08 (diff)
downloadlinux-11db1e4cee071defc371d0fc7f1740024fbe5b06.tar.xz
tcp: must unclone packets before mangling them
[ Upstream commit c52e2421f7368fd36cbe330d2cf41b10452e39a9 ] TCP stack should make sure it owns skbs before mangling them. We had various crashes using bnx2x, and it turned out gso_size was cleared right before bnx2x driver was populating TC descriptor of the _previous_ packet send. TCP stack can sometime retransmit packets that are still in Qdisc. Of course we could make bnx2x driver more robust (using ACCESS_ONCE(shinfo->gso_size) for example), but the bug is TCP stack. We have identified two points where skb_unclone() was needed. This patch adds a WARN_ON_ONCE() to warn us if we missed another fix of this kind. Kudos to Neal for finding the root cause of this bug. Its visible using small MSS. Signed-off-by: Eric Dumazet <edumazet@google.com> Signed-off-by: Neal Cardwell <ncardwell@google.com> Cc: Yuchung Cheng <ycheng@google.com> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'include')
-rw-r--r--include/linux/skbuff.h10
1 files changed, 10 insertions, 0 deletions
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index dc4d49a0c07d..daabf24655af 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -760,6 +760,16 @@ static inline int skb_cloned(const struct sk_buff *skb)
(atomic_read(&skb_shinfo(skb)->dataref) & SKB_DATAREF_MASK) != 1;
}
+static inline int skb_unclone(struct sk_buff *skb, gfp_t pri)
+{
+ might_sleep_if(pri & __GFP_WAIT);
+
+ if (skb_cloned(skb))
+ return pskb_expand_head(skb, 0, 0, pri);
+
+ return 0;
+}
+
/**
* skb_header_cloned - is the header a clone
* @skb: buffer to check