net-timestamp: Make the clone operation stand-alone from phy timestamping

The phy timestamping takes a different path than the regular timestamping
does in that it will create a clone first so that the packets needing to be
timestamped can be placed in a queue, or the context block could be used.

In order to support these use cases I am pulling the core of the code out
so it can be used in other drivers beyond just phy devices.

In addition I have added a destructor named sock_efree which is meant to
provide a simple way for dropping the reference to skb exceptions that
aren't part of either the receive or send windows for the socket, and I
have removed some duplication in spots where this destructor could be used
in place of sock_edemux.

Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Alexander Duyck 2014-09-04 13:31:35 -04:00 committed by David S. Miller
parent 37846ef018
commit 62bccb8cdb
6 changed files with 40 additions and 21 deletions

View File

@ -1148,7 +1148,7 @@ static void dp83640_remove(struct phy_device *phydev)
kfree_skb(skb); kfree_skb(skb);
while ((skb = skb_dequeue(&dp83640->tx_queue)) != NULL) while ((skb = skb_dequeue(&dp83640->tx_queue)) != NULL)
skb_complete_tx_timestamp(skb, NULL); kfree_skb(skb);
clock = dp83640_clock_get(dp83640->clock); clock = dp83640_clock_get(dp83640->clock);
@ -1405,7 +1405,7 @@ static void dp83640_txtstamp(struct phy_device *phydev,
case HWTSTAMP_TX_ONESTEP_SYNC: case HWTSTAMP_TX_ONESTEP_SYNC:
if (is_sync(skb, type)) { if (is_sync(skb, type)) {
skb_complete_tx_timestamp(skb, NULL); kfree_skb(skb);
return; return;
} }
/* fall through */ /* fall through */
@ -1416,7 +1416,7 @@ static void dp83640_txtstamp(struct phy_device *phydev,
case HWTSTAMP_TX_OFF: case HWTSTAMP_TX_OFF:
default: default:
skb_complete_tx_timestamp(skb, NULL); kfree_skb(skb);
break; break;
} }
} }

View File

@ -2690,6 +2690,8 @@ static inline ktime_t net_invalid_timestamp(void)
return ktime_set(0, 0); return ktime_set(0, 0);
} }
struct sk_buff *skb_clone_sk(struct sk_buff *skb);
#ifdef CONFIG_NETWORK_PHY_TIMESTAMPING #ifdef CONFIG_NETWORK_PHY_TIMESTAMPING
void skb_clone_tx_timestamp(struct sk_buff *skb); void skb_clone_tx_timestamp(struct sk_buff *skb);

View File

@ -1574,6 +1574,7 @@ struct sk_buff *sock_wmalloc(struct sock *sk, unsigned long size, int force,
void sock_wfree(struct sk_buff *skb); void sock_wfree(struct sk_buff *skb);
void skb_orphan_partial(struct sk_buff *skb); void skb_orphan_partial(struct sk_buff *skb);
void sock_rfree(struct sk_buff *skb); void sock_rfree(struct sk_buff *skb);
void sock_efree(struct sk_buff *skb);
void sock_edemux(struct sk_buff *skb); void sock_edemux(struct sk_buff *skb);
int sock_setsockopt(struct socket *sock, int level, int op, int sock_setsockopt(struct socket *sock, int level, int op,

View File

@ -3511,6 +3511,27 @@ struct sk_buff *sock_dequeue_err_skb(struct sock *sk)
} }
EXPORT_SYMBOL(sock_dequeue_err_skb); EXPORT_SYMBOL(sock_dequeue_err_skb);
struct sk_buff *skb_clone_sk(struct sk_buff *skb)
{
struct sock *sk = skb->sk;
struct sk_buff *clone;
if (!sk || !atomic_inc_not_zero(&sk->sk_refcnt))
return NULL;
clone = skb_clone(skb, GFP_ATOMIC);
if (!clone) {
sock_put(sk);
return NULL;
}
clone->sk = sk;
clone->destructor = sock_efree;
return clone;
}
EXPORT_SYMBOL(skb_clone_sk);
static void __skb_complete_tx_timestamp(struct sk_buff *skb, static void __skb_complete_tx_timestamp(struct sk_buff *skb,
struct sock *sk, struct sock *sk,
int tstype) int tstype)
@ -3540,14 +3561,11 @@ void skb_complete_tx_timestamp(struct sk_buff *skb,
{ {
struct sock *sk = skb->sk; struct sock *sk = skb->sk;
skb->sk = NULL; /* take a reference to prevent skb_orphan() from freeing the socket */
sock_hold(sk);
if (hwtstamps) {
*skb_hwtstamps(skb) = *hwtstamps; *skb_hwtstamps(skb) = *hwtstamps;
__skb_complete_tx_timestamp(skb, sk, SCM_TSTAMP_SND); __skb_complete_tx_timestamp(skb, sk, SCM_TSTAMP_SND);
} else {
kfree_skb(skb);
}
sock_put(sk); sock_put(sk);
} }

View File

@ -1637,6 +1637,12 @@ void sock_rfree(struct sk_buff *skb)
} }
EXPORT_SYMBOL(sock_rfree); EXPORT_SYMBOL(sock_rfree);
void sock_efree(struct sk_buff *skb)
{
sock_put(skb->sk);
}
EXPORT_SYMBOL(sock_efree);
void sock_edemux(struct sk_buff *skb) void sock_edemux(struct sk_buff *skb)
{ {
struct sock *sk = skb->sk; struct sock *sk = skb->sk;

View File

@ -36,10 +36,9 @@ void skb_clone_tx_timestamp(struct sk_buff *skb)
{ {
struct phy_device *phydev; struct phy_device *phydev;
struct sk_buff *clone; struct sk_buff *clone;
struct sock *sk = skb->sk;
unsigned int type; unsigned int type;
if (!sk) if (!skb->sk)
return; return;
type = classify(skb); type = classify(skb);
@ -48,16 +47,9 @@ void skb_clone_tx_timestamp(struct sk_buff *skb)
phydev = skb->dev->phydev; phydev = skb->dev->phydev;
if (likely(phydev->drv->txtstamp)) { if (likely(phydev->drv->txtstamp)) {
if (!atomic_inc_not_zero(&sk->sk_refcnt)) clone = skb_clone_sk(skb);
if (!clone)
return; return;
clone = skb_clone(skb, GFP_ATOMIC);
if (!clone) {
sock_put(sk);
return;
}
clone->sk = sk;
phydev->drv->txtstamp(phydev, clone, type); phydev->drv->txtstamp(phydev, clone, type);
} }
} }