Merge branch 'timestamping'

Alexander Duyck says:

====================
This change makes it so that the core path for the phy timestamping logic
is shared between skb_tx_tstamp and skb_complete_tx_timestamp.  In addition
it provides a means of using the same skb clone type path in non phy
timestamping drivers.

The main motivation for this is to enable non-phy drivers to be able to
manipulate tx timestamp skbs for such things as putting them in lists or
setting aside buffer in the context block.

v2: Incorporated suggested changes from Willem de Bruijn and Eric Dumazet
     dropped uneeded comment
     restored order of hwtstamp vs swtstamp
     added destructor for skb
    Dropped usage of skb_complete_tx_timestamp as a kfree_skb w/ destructor

v3: Updated destructor handling and dealt with socket reference counting issues

v4: Split out combining destructors into a separate patch
====================
This commit is contained in:
David S. Miller 2014-09-05 17:43:54 -07:00
commit 2c048e6462
7 changed files with 80 additions and 67 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,7 +1574,12 @@ 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);
#ifdef CONFIG_INET
void sock_edemux(struct sk_buff *skb); void sock_edemux(struct sk_buff *skb);
#else
#define sock_edemux(skb) sock_efree(skb)
#endif
int sock_setsockopt(struct socket *sock, int level, int op, int sock_setsockopt(struct socket *sock, int level, int op,
char __user *optval, unsigned int optlen); char __user *optval, unsigned int optlen);

View File

@ -3511,32 +3511,33 @@ struct sk_buff *sock_dequeue_err_skb(struct sock *sk)
} }
EXPORT_SYMBOL(sock_dequeue_err_skb); EXPORT_SYMBOL(sock_dequeue_err_skb);
void __skb_tstamp_tx(struct sk_buff *orig_skb, struct sk_buff *skb_clone_sk(struct sk_buff *skb)
struct skb_shared_hwtstamps *hwtstamps,
struct sock *sk, int tstype)
{ {
struct sock_exterr_skb *serr; struct sock *sk = skb->sk;
struct sk_buff *skb; struct sk_buff *clone;
int err;
if (!sk) if (!sk || !atomic_inc_not_zero(&sk->sk_refcnt))
return; return NULL;
if (hwtstamps) { clone = skb_clone(skb, GFP_ATOMIC);
*skb_hwtstamps(orig_skb) = if (!clone) {
*hwtstamps; sock_put(sk);
} else { return NULL;
/*
* no hardware time stamps available,
* so keep the shared tx_flags and only
* store software time stamp
*/
orig_skb->tstamp = ktime_get_real();
} }
skb = skb_clone(orig_skb, GFP_ATOMIC); clone->sk = sk;
if (!skb) clone->destructor = sock_efree;
return;
return clone;
}
EXPORT_SYMBOL(skb_clone_sk);
static void __skb_complete_tx_timestamp(struct sk_buff *skb,
struct sock *sk,
int tstype)
{
struct sock_exterr_skb *serr;
int err;
serr = SKB_EXT_ERR(skb); serr = SKB_EXT_ERR(skb);
memset(serr, 0, sizeof(*serr)); memset(serr, 0, sizeof(*serr));
@ -3554,6 +3555,42 @@ void __skb_tstamp_tx(struct sk_buff *orig_skb,
if (err) if (err)
kfree_skb(skb); kfree_skb(skb);
} }
void skb_complete_tx_timestamp(struct sk_buff *skb,
struct skb_shared_hwtstamps *hwtstamps)
{
struct sock *sk = skb->sk;
/* take a reference to prevent skb_orphan() from freeing the socket */
sock_hold(sk);
*skb_hwtstamps(skb) = *hwtstamps;
__skb_complete_tx_timestamp(skb, sk, SCM_TSTAMP_SND);
sock_put(sk);
}
EXPORT_SYMBOL_GPL(skb_complete_tx_timestamp);
void __skb_tstamp_tx(struct sk_buff *orig_skb,
struct skb_shared_hwtstamps *hwtstamps,
struct sock *sk, int tstype)
{
struct sk_buff *skb;
if (!sk)
return;
if (hwtstamps)
*skb_hwtstamps(orig_skb) = *hwtstamps;
else
orig_skb->tstamp = ktime_get_real();
skb = skb_clone(orig_skb, GFP_ATOMIC);
if (!skb)
return;
__skb_complete_tx_timestamp(skb, sk, tstype);
}
EXPORT_SYMBOL_GPL(__skb_tstamp_tx); EXPORT_SYMBOL_GPL(__skb_tstamp_tx);
void skb_tstamp_tx(struct sk_buff *orig_skb, void skb_tstamp_tx(struct sk_buff *orig_skb,

View File

@ -1637,18 +1637,24 @@ 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);
#ifdef CONFIG_INET
void sock_edemux(struct sk_buff *skb) void sock_edemux(struct sk_buff *skb)
{ {
struct sock *sk = skb->sk; struct sock *sk = skb->sk;
#ifdef CONFIG_INET
if (sk->sk_state == TCP_TIME_WAIT) if (sk->sk_state == TCP_TIME_WAIT)
inet_twsk_put(inet_twsk(sk)); inet_twsk_put(inet_twsk(sk));
else else
#endif
sock_put(sk); sock_put(sk);
} }
EXPORT_SYMBOL(sock_edemux); EXPORT_SYMBOL(sock_edemux);
#endif
kuid_t sock_i_uid(struct sock *sk) kuid_t sock_i_uid(struct sock *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,50 +47,14 @@ 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);
} }
} }
EXPORT_SYMBOL_GPL(skb_clone_tx_timestamp); EXPORT_SYMBOL_GPL(skb_clone_tx_timestamp);
void skb_complete_tx_timestamp(struct sk_buff *skb,
struct skb_shared_hwtstamps *hwtstamps)
{
struct sock *sk = skb->sk;
struct sock_exterr_skb *serr;
int err;
if (!hwtstamps) {
sock_put(sk);
kfree_skb(skb);
return;
}
*skb_hwtstamps(skb) = *hwtstamps;
serr = SKB_EXT_ERR(skb);
memset(serr, 0, sizeof(*serr));
serr->ee.ee_errno = ENOMSG;
serr->ee.ee_origin = SO_EE_ORIGIN_TIMESTAMPING;
skb->sk = NULL;
err = sock_queue_err_skb(sk, skb);
sock_put(sk);
if (err)
kfree_skb(skb);
}
EXPORT_SYMBOL_GPL(skb_complete_tx_timestamp);
bool skb_defer_rx_timestamp(struct sk_buff *skb) bool skb_defer_rx_timestamp(struct sk_buff *skb)
{ {
struct phy_device *phydev; struct phy_device *phydev;

View File

@ -1972,7 +1972,7 @@ void udp_v4_early_demux(struct sk_buff *skb)
return; return;
skb->sk = sk; skb->sk = sk;
skb->destructor = sock_edemux; skb->destructor = sock_efree;
dst = sk->sk_rx_dst; dst = sk->sk_rx_dst;
if (dst) if (dst)