From: Jonathan Lemon <b...@fb.com>

skb_zcopy() flag indicates whether the skb has a zerocopy ubuf.
netgpu does not use ubufs, so skb_zdata() indicates whether the
skb is carrying zero copy data, and should be left alone, while
skb_zcopy() indicates whether there is an attached ubuf.

Signed-off-by: Jonathan Lemon <jonathan.le...@gmail.com>
---
 include/linux/skbuff.h | 24 +++++++++++++++++++++++-
 net/core/skbuff.c      | 17 ++++++++++++++++-
 2 files changed, 39 insertions(+), 2 deletions(-)

diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 006e10fcc7d9..017c20792c23 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -443,8 +443,12 @@ enum {
 
        /* generate software time stamp when entering packet scheduling */
        SKBTX_SCHED_TSTAMP = 1 << 6,
+
+       /* fragments are accessed only via DMA */
+       SKBTX_DEV_NETDMA = 1 << 7,
 };
 
+#define SKBTX_ZERODATA_FRAG    (SKBTX_DEV_ZEROCOPY | SKBTX_DEV_NETDMA)
 #define SKBTX_ZEROCOPY_FRAG    (SKBTX_DEV_ZEROCOPY | SKBTX_SHARED_FRAG)
 #define SKBTX_ANY_SW_TSTAMP    (SKBTX_SW_TSTAMP    | \
                                 SKBTX_SCHED_TSTAMP)
@@ -1420,6 +1424,24 @@ static inline struct skb_shared_hwtstamps 
*skb_hwtstamps(struct sk_buff *skb)
        return &skb_shinfo(skb)->hwtstamps;
 }
 
+static inline bool skb_netdma(struct sk_buff *skb)
+{
+       return skb && skb_shinfo(skb)->tx_flags & SKBTX_DEV_NETDMA;
+}
+
+static inline bool skb_zdata(struct sk_buff *skb)
+{
+       return skb && skb_shinfo(skb)->tx_flags & SKBTX_ZERODATA_FRAG;
+}
+
+static inline void skb_netdma_set(struct sk_buff *skb, void *arg)
+{
+       if (skb && arg) {
+               skb_shinfo(skb)->tx_flags |= SKBTX_DEV_NETDMA;
+               skb_shinfo(skb)->destructor_arg = arg;
+       }
+}
+
 static inline struct ubuf_info *skb_zcopy(struct sk_buff *skb)
 {
        bool is_zcopy = skb && skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY;
@@ -3264,7 +3286,7 @@ static inline int skb_add_data(struct sk_buff *skb,
 static inline bool skb_can_coalesce(struct sk_buff *skb, int i,
                                    const struct page *page, int off)
 {
-       if (skb_zcopy(skb))
+       if (skb_zdata(skb))
                return false;
        if (i) {
                const skb_frag_t *frag = &skb_shinfo(skb)->frags[i - 1];
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 2a391042be53..1422b99b7090 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -69,6 +69,7 @@
 #include <net/xfrm.h>
 #include <net/mpls.h>
 #include <net/mptcp.h>
+#include <net/netgpu.h>
 
 #include <linux/uaccess.h>
 #include <trace/events/skb.h>
@@ -1300,6 +1301,8 @@ int skb_zerocopy_iter_stream(struct sock *sk, struct 
sk_buff *skb,
        }
 
        skb_zcopy_set(skb, uarg, NULL);
+       skb_netdma_set(skb, sk->sk_user_data);
+
        return skb->len - orig_len;
 }
 EXPORT_SYMBOL_GPL(skb_zerocopy_iter_stream);
@@ -1307,6 +1310,16 @@ EXPORT_SYMBOL_GPL(skb_zerocopy_iter_stream);
 static int skb_zerocopy_clone(struct sk_buff *nskb, struct sk_buff *orig,
                              gfp_t gfp_mask)
 {
+       if (skb_netdma(orig)) {
+               if (skb_netdma(nskb)) {
+                       WARN_ONCE(1, "zc clone, dst skb is set\n");
+                       if (skb_uarg(nskb) != skb_uarg(orig))
+                               return -EIO;
+               }
+               skb_netdma_set(nskb, skb_shinfo(orig)->destructor_arg);
+               return 0;
+       }
+
        if (skb_zcopy(orig)) {
                if (skb_zcopy(nskb)) {
                        /* !gfp_mask callers are verified to !skb_zcopy(nskb) */
@@ -2055,6 +2068,8 @@ void *__pskb_pull_tail(struct sk_buff *skb, int delta)
         */
        int i, k, eat = (skb->tail + delta) - skb->end;
 
+       BUG_ON(skb_netdma(skb));
+
        if (eat > 0 || skb_cloned(skb)) {
                if (pskb_expand_head(skb, 0, eat > 0 ? eat + 128 : 0,
                                     GFP_ATOMIC))
@@ -3305,7 +3320,7 @@ int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, 
int shiftlen)
 
        if (skb_headlen(skb))
                return 0;
-       if (skb_zcopy(tgt) || skb_zcopy(skb))
+       if (skb_zdata(tgt) || skb_zdata(skb))
                return 0;
 
        todo = shiftlen;
-- 
2.24.1

Reply via email to