Revert "net: remove skb_orphan_try()"
This reverts commit 73a3346556281fd56f39f0a9475249e5039d8807.
The change in question doesn't seem to apply to us, but conflicts with an
attempted cherry-pick of 6e3e939f3, so let's just take it out.
Change-Id: If48a800e4428a7687bea1227b4e9fcc576141f35
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 4b42eb7..70fd1e2 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -213,8 +213,11 @@
/* device driver is going to provide hardware time stamp */
SKBTX_IN_PROGRESS = 1 << 2,
+ /* ensure the originating sk reference is available on driver level */
+ SKBTX_DRV_NEEDS_SK_REF = 1 << 3,
+
/* device driver supports TX zero-copy buffers */
- SKBTX_DEV_ZEROCOPY = 1 << 3,
+ SKBTX_DEV_ZEROCOPY = 1 << 4,
};
/*
diff --git a/net/can/raw.c b/net/can/raw.c
index 46cca3a..cde1b4a 100644
--- a/net/can/raw.c
+++ b/net/can/raw.c
@@ -681,6 +681,9 @@
if (err < 0)
goto free_skb;
+ /* to be able to check the received tx sock reference in raw_rcv() */
+ skb_shinfo(skb)->tx_flags |= SKBTX_DRV_NEEDS_SK_REF;
+
skb->dev = dev;
skb->sk = sk;
diff --git a/net/core/dev.c b/net/core/dev.c
index 35ac2f6..31ca1a6 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2079,6 +2079,25 @@
return 0;
}
+/*
+ * Try to orphan skb early, right before transmission by the device.
+ * We cannot orphan skb if tx timestamp is requested or the sk-reference
+ * is needed on driver level for other reasons, e.g. see net/can/raw.c
+ */
+static inline void skb_orphan_try(struct sk_buff *skb)
+{
+ struct sock *sk = skb->sk;
+
+ if (sk && !skb_shinfo(skb)->tx_flags) {
+ /* skb_tx_hash() wont be able to get sk.
+ * We copy sk_hash into skb->rxhash
+ */
+ if (!skb->rxhash)
+ skb->rxhash = sk->sk_hash;
+ skb_orphan(skb);
+ }
+}
+
static bool can_checksum_protocol(unsigned long features, __be16 protocol)
{
return ((features & NETIF_F_GEN_CSUM) ||
@@ -2163,6 +2182,8 @@
if (!list_empty(&ptype_all))
dev_queue_xmit_nit(skb, dev);
+ skb_orphan_try(skb);
+
features = netif_skb_features(skb);
if (vlan_tx_tag_present(skb) &&
@@ -2272,7 +2293,7 @@
if (skb->sk && skb->sk->sk_hash)
hash = skb->sk->sk_hash;
else
- hash = (__force u16) skb->protocol;
+ hash = (__force u16) skb->protocol ^ skb->rxhash;
hash = jhash_1word(hash, hashrnd);
return (u16) (((u64) hash * qcount) >> 32) + qoffset;
diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c
index cf98d62..274d150 100644
--- a/net/iucv/af_iucv.c
+++ b/net/iucv/af_iucv.c
@@ -380,6 +380,7 @@
skb_trim(skb, skb->dev->mtu);
}
skb->protocol = ETH_P_AF_IUCV;
+ skb_shinfo(skb)->tx_flags |= SKBTX_DRV_NEEDS_SK_REF;
nskb = skb_clone(skb, GFP_ATOMIC);
if (!nskb)
return -ENOMEM;