net-timestamp: Make the clone operation stand-alone from phy timestamping
authorAlexander Duyck <alexander.h.duyck@intel.com>
Thu, 4 Sep 2014 17:31:35 +0000 (13:31 -0400)
committerDavid S. Miller <davem@davemloft.net>
Sat, 6 Sep 2014 00:43:45 +0000 (17:43 -0700)
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>
drivers/net/phy/dp83640.c
include/linux/skbuff.h
include/net/sock.h
net/core/skbuff.c
net/core/sock.c
net/core/timestamping.c

index d5991ac..87648b3 100644 (file)
@@ -1148,7 +1148,7 @@ static void dp83640_remove(struct phy_device *phydev)
                kfree_skb(skb);
 
        while ((skb = skb_dequeue(&dp83640->tx_queue)) != NULL)
-               skb_complete_tx_timestamp(skb, NULL);
+               kfree_skb(skb);
 
        clock = dp83640_clock_get(dp83640->clock);
 
@@ -1405,7 +1405,7 @@ static void dp83640_txtstamp(struct phy_device *phydev,
 
        case HWTSTAMP_TX_ONESTEP_SYNC:
                if (is_sync(skb, type)) {
-                       skb_complete_tx_timestamp(skb, NULL);
+                       kfree_skb(skb);
                        return;
                }
                /* fall through */
@@ -1416,7 +1416,7 @@ static void dp83640_txtstamp(struct phy_device *phydev,
 
        case HWTSTAMP_TX_OFF:
        default:
-               skb_complete_tx_timestamp(skb, NULL);
+               kfree_skb(skb);
                break;
        }
 }
index 02529fc..1cf0cfa 100644 (file)
@@ -2690,6 +2690,8 @@ static inline ktime_t net_invalid_timestamp(void)
        return ktime_set(0, 0);
 }
 
+struct sk_buff *skb_clone_sk(struct sk_buff *skb);
+
 #ifdef CONFIG_NETWORK_PHY_TIMESTAMPING
 
 void skb_clone_tx_timestamp(struct sk_buff *skb);
index 3fde613..e02be37 100644 (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 skb_orphan_partial(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);
 
 int sock_setsockopt(struct socket *sock, int level, int op,
index 697e696..a936a40 100644 (file)
@@ -3511,6 +3511,27 @@ struct sk_buff *sock_dequeue_err_skb(struct sock *sk)
 }
 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,
                                        struct sock *sk,
                                        int tstype)
@@ -3540,14 +3561,11 @@ void skb_complete_tx_timestamp(struct sk_buff *skb,
 {
        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_complete_tx_timestamp(skb, sk, SCM_TSTAMP_SND);
-       } else {
-               kfree_skb(skb);
-       }
+       *skb_hwtstamps(skb) = *hwtstamps;
+       __skb_complete_tx_timestamp(skb, sk, SCM_TSTAMP_SND);
 
        sock_put(sk);
 }
index f1a638e..d04005c 100644 (file)
@@ -1637,6 +1637,12 @@ void sock_rfree(struct sk_buff *skb)
 }
 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)
 {
        struct sock *sk = skb->sk;
index f48a59f..43d3dd6 100644 (file)
@@ -36,10 +36,9 @@ void skb_clone_tx_timestamp(struct sk_buff *skb)
 {
        struct phy_device *phydev;
        struct sk_buff *clone;
-       struct sock *sk = skb->sk;
        unsigned int type;
 
-       if (!sk)
+       if (!skb->sk)
                return;
 
        type = classify(skb);
@@ -48,16 +47,9 @@ void skb_clone_tx_timestamp(struct sk_buff *skb)
 
        phydev = skb->dev->phydev;
        if (likely(phydev->drv->txtstamp)) {
-               if (!atomic_inc_not_zero(&sk->sk_refcnt))
+               clone = skb_clone_sk(skb);
+               if (!clone)
                        return;
-
-               clone = skb_clone(skb, GFP_ATOMIC);
-               if (!clone) {
-                       sock_put(sk);
-                       return;
-               }
-
-               clone->sk = sk;
                phydev->drv->txtstamp(phydev, clone, type);
        }
 }