net: Introduce skb_orphan_try()
Transmitted skb might be attached to a socket and a destructor, for memory accounting purposes. Traditionally, this destructor is called at tx completion time, when skb is freed. When tx completion is performed by another cpu than the sender, this forces some cache lines to change ownership. XPS was an attempt to give tx completion to initial cpu. David idea is to call destructor right before giving skb to device (call to ndo_start_xmit()). Because device queues are usually small, orphaning skb before tx completion is not a big deal. Some drivers already do this, we could do it in upper level. There is one known exception to this early orphaning, called tx timestamping. It needs to keep a reference to socket until device can give a hardware or software timestamp. This patch adds a skb_orphan_try() helper, to centralize all exceptions to early orphaning in one spot, and use it in dev_hard_start_xmit(). "tbench 16" results on a Nehalem machine (2 X5570 @ 2.93GHz) before: Throughput 4428.9 MB/sec 16 procs after: Throughput 4448.14 MB/sec 16 procs UDP should get even better results, its destructor being more complex, since SOCK_USE_WRITE_QUEUE is not set (four atomic ops instead of one) Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
9958da0501
commit
fc6055a5ba
@ -1880,6 +1880,17 @@ static int dev_gso_segment(struct sk_buff *skb)
|
||||
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,
|
||||
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)
|
||||
skb_dst_drop(skb);
|
||||
|
||||
skb_orphan_try(skb);
|
||||
rc = ops->ndo_start_xmit(skb, dev);
|
||||
if (rc == NETDEV_TX_OK)
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1938,6 +1936,7 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
|
||||
if (dev->priv_flags & IFF_XMIT_DST_RELEASE)
|
||||
skb_dst_drop(nskb);
|
||||
|
||||
skb_orphan_try(nskb);
|
||||
rc = ops->ndo_start_xmit(nskb, dev);
|
||||
if (unlikely(rc != NETDEV_TX_OK)) {
|
||||
if (rc & ~NETDEV_TX_MASK)
|
||||
|
Loading…
Reference in New Issue
Block a user