virtio-net: pack headroom into ctx for mergeable buffers
authorJason Wang <jasowang@redhat.com>
Wed, 19 Jul 2017 08:54:46 +0000 (16:54 +0800)
committerDavid S. Miller <davem@davemloft.net>
Mon, 24 Jul 2017 20:37:00 +0000 (13:37 -0700)
Pack headroom into ctx - this way when we get a buffer we can figure out
the actual headroom that was allocated for the buffer. Will be helpful
to optimize switching between XDP and non-XDP modes which have different
headroom requirements.

Signed-off-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/virtio_net.c

index 99830167ea2f5b17b2189e5b29547f9cbc9b11b5..3223a36ad9a81649a0552f538623012fd2c4b4bd 100644 (file)
@@ -270,6 +270,23 @@ static void skb_xmit_done(struct virtqueue *vq)
                netif_wake_subqueue(vi->dev, vq2txq(vq));
 }
 
+#define MRG_CTX_HEADER_SHIFT 22
+static void *mergeable_len_to_ctx(unsigned int truesize,
+                                 unsigned int headroom)
+{
+       return (void *)(unsigned long)((headroom << MRG_CTX_HEADER_SHIFT) | truesize);
+}
+
+static unsigned int mergeable_ctx_to_headroom(void *mrg_ctx)
+{
+       return (unsigned long)mrg_ctx >> MRG_CTX_HEADER_SHIFT;
+}
+
+static unsigned int mergeable_ctx_to_truesize(void *mrg_ctx)
+{
+       return (unsigned long)mrg_ctx & ((1 << MRG_CTX_HEADER_SHIFT) - 1);
+}
+
 /* Called from bottom half context */
 static struct sk_buff *page_to_skb(struct virtnet_info *vi,
                                   struct receive_queue *rq,
@@ -639,13 +656,14 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
        }
        rcu_read_unlock();
 
-       if (unlikely(len > (unsigned long)ctx)) {
+       truesize = mergeable_ctx_to_truesize(ctx);
+       if (unlikely(len > truesize)) {
                pr_debug("%s: rx error: len %u exceeds truesize %lu\n",
                         dev->name, len, (unsigned long)ctx);
                dev->stats.rx_length_errors++;
                goto err_skb;
        }
-       truesize = (unsigned long)ctx;
+
        head_skb = page_to_skb(vi, rq, page, offset, len, truesize);
        curr_skb = head_skb;
 
@@ -665,13 +683,14 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
                }
 
                page = virt_to_head_page(buf);
-               if (unlikely(len > (unsigned long)ctx)) {
+
+               truesize = mergeable_ctx_to_truesize(ctx);
+               if (unlikely(len > truesize)) {
                        pr_debug("%s: rx error: len %u exceeds truesize %lu\n",
                                 dev->name, len, (unsigned long)ctx);
                        dev->stats.rx_length_errors++;
                        goto err_skb;
                }
-               truesize = (unsigned long)ctx;
 
                num_skb_frags = skb_shinfo(curr_skb)->nr_frags;
                if (unlikely(num_skb_frags == MAX_SKB_FRAGS)) {
@@ -889,7 +908,7 @@ static int add_recvbuf_mergeable(struct virtnet_info *vi,
 
        buf = (char *)page_address(alloc_frag->page) + alloc_frag->offset;
        buf += headroom; /* advance address leaving hole at front of pkt */
-       ctx = (void *)(unsigned long)len;
+       ctx = mergeable_len_to_ctx(len, headroom);
        get_page(alloc_frag->page);
        alloc_frag->offset += len + headroom;
        hole = alloc_frag->size - alloc_frag->offset;