|
@@ -1880,6 +1880,17 @@ static int dev_gso_segment(struct sk_buff *skb)
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * Try to orphan skb early, right before transmission by the device.
|
|
|
|
+ * We cannot orphan skb if tx timestamp is requested, since
|
|
|
|
+ * drivers need to call skb_tstamp_tx() to send the timestamp.
|
|
|
|
+ */
|
|
|
|
+static inline void skb_orphan_try(struct sk_buff *skb)
|
|
|
|
+{
|
|
|
|
+ if (!skb_tx(skb)->flags)
|
|
|
|
+ skb_orphan(skb);
|
|
|
|
+}
|
|
|
|
+
|
|
int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
|
|
int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
|
|
struct netdev_queue *txq)
|
|
struct netdev_queue *txq)
|
|
{
|
|
{
|
|
@@ -1904,23 +1915,10 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
|
|
if (dev->priv_flags & IFF_XMIT_DST_RELEASE)
|
|
if (dev->priv_flags & IFF_XMIT_DST_RELEASE)
|
|
skb_dst_drop(skb);
|
|
skb_dst_drop(skb);
|
|
|
|
|
|
|
|
+ skb_orphan_try(skb);
|
|
rc = ops->ndo_start_xmit(skb, dev);
|
|
rc = ops->ndo_start_xmit(skb, dev);
|
|
if (rc == NETDEV_TX_OK)
|
|
if (rc == NETDEV_TX_OK)
|
|
txq_trans_update(txq);
|
|
txq_trans_update(txq);
|
|
- /*
|
|
|
|
- * TODO: if skb_orphan() was called by
|
|
|
|
- * dev->hard_start_xmit() (for example, the unmodified
|
|
|
|
- * igb driver does that; bnx2 doesn't), then
|
|
|
|
- * skb_tx_software_timestamp() will be unable to send
|
|
|
|
- * back the time stamp.
|
|
|
|
- *
|
|
|
|
- * How can this be prevented? Always create another
|
|
|
|
- * reference to the socket before calling
|
|
|
|
- * dev->hard_start_xmit()? Prevent that skb_orphan()
|
|
|
|
- * does anything in dev->hard_start_xmit() by clearing
|
|
|
|
- * the skb destructor before the call and restoring it
|
|
|
|
- * afterwards, then doing the skb_orphan() ourselves?
|
|
|
|
- */
|
|
|
|
return rc;
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1938,6 +1936,7 @@ gso:
|
|
if (dev->priv_flags & IFF_XMIT_DST_RELEASE)
|
|
if (dev->priv_flags & IFF_XMIT_DST_RELEASE)
|
|
skb_dst_drop(nskb);
|
|
skb_dst_drop(nskb);
|
|
|
|
|
|
|
|
+ skb_orphan_try(nskb);
|
|
rc = ops->ndo_start_xmit(nskb, dev);
|
|
rc = ops->ndo_start_xmit(nskb, dev);
|
|
if (unlikely(rc != NETDEV_TX_OK)) {
|
|
if (unlikely(rc != NETDEV_TX_OK)) {
|
|
if (rc & ~NETDEV_TX_MASK)
|
|
if (rc & ~NETDEV_TX_MASK)
|