This reverts commit a4e7ba7027012f009f22a68bcfde670f9298d3a4. leads to crashes with no ACCESS_PLATFORM when sysctl net.core.high_order_alloc_disable=1 Cc: Xuan Zhuo <xuanzhuo@xxxxxxxxxxxxxxxxx> Reported-by: Si-Wei Liu <si-wei.liu@xxxxxxxxxx> Signed-off-by: Michael S. Tsirkin <mst@xxxxxxxxxx> --- drivers/net/virtio_net.c | 198 ++++----------------------------------- 1 file changed, 19 insertions(+), 179 deletions(-) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 15e202dd6964..041c483a06c5 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -498,12 +498,6 @@ struct virtio_net_common_hdr { }; static void virtnet_sq_free_unused_buf(struct virtqueue *vq, void *buf); -static int virtnet_xdp_handler(struct bpf_prog *xdp_prog, struct xdp_buff *xdp, - struct net_device *dev, - unsigned int *xdp_xmit, - struct virtnet_rq_stats *stats); -static void virtnet_receive_done(struct virtnet_info *vi, struct receive_queue *rq, - struct sk_buff *skb, u8 flags); static bool is_xdp_frame(void *ptr) { @@ -1068,124 +1062,6 @@ static void sg_fill_dma(struct scatterlist *sg, dma_addr_t addr, u32 len) sg->length = len; } -static struct xdp_buff *buf_to_xdp(struct virtnet_info *vi, - struct receive_queue *rq, void *buf, u32 len) -{ - struct xdp_buff *xdp; - u32 bufsize; - - xdp = (struct xdp_buff *)buf; - - bufsize = xsk_pool_get_rx_frame_size(rq->xsk_pool) + vi->hdr_len; - - if (unlikely(len > bufsize)) { - pr_debug("%s: rx error: len %u exceeds truesize %u\n", - vi->dev->name, len, bufsize); - DEV_STATS_INC(vi->dev, rx_length_errors); - xsk_buff_free(xdp); - return NULL; - } - - xsk_buff_set_size(xdp, len); - xsk_buff_dma_sync_for_cpu(xdp); - - return xdp; -} - -static struct sk_buff *xsk_construct_skb(struct receive_queue *rq, - struct xdp_buff *xdp) -{ - unsigned int metasize = xdp->data - xdp->data_meta; - struct sk_buff *skb; - unsigned int size; - - size = xdp->data_end - xdp->data_hard_start; - skb = napi_alloc_skb(&rq->napi, size); - if (unlikely(!skb)) { - xsk_buff_free(xdp); - return NULL; - } - - skb_reserve(skb, xdp->data_meta - xdp->data_hard_start); - - size = xdp->data_end - xdp->data_meta; - memcpy(__skb_put(skb, size), xdp->data_meta, size); - - if (metasize) { - __skb_pull(skb, metasize); - skb_metadata_set(skb, metasize); - } - - xsk_buff_free(xdp); - - return skb; -} - -static struct sk_buff *virtnet_receive_xsk_small(struct net_device *dev, struct virtnet_info *vi, - struct receive_queue *rq, struct xdp_buff *xdp, - unsigned int *xdp_xmit, - struct virtnet_rq_stats *stats) -{ - struct bpf_prog *prog; - u32 ret; - - ret = XDP_PASS; - rcu_read_lock(); - prog = rcu_dereference(rq->xdp_prog); - if (prog) - ret = virtnet_xdp_handler(prog, xdp, dev, xdp_xmit, stats); - rcu_read_unlock(); - - switch (ret) { - case XDP_PASS: - return xsk_construct_skb(rq, xdp); - - case XDP_TX: - case XDP_REDIRECT: - return NULL; - - default: - /* drop packet */ - xsk_buff_free(xdp); - u64_stats_inc(&stats->drops); - return NULL; - } -} - -static void virtnet_receive_xsk_buf(struct virtnet_info *vi, struct receive_queue *rq, - void *buf, u32 len, - unsigned int *xdp_xmit, - struct virtnet_rq_stats *stats) -{ - struct net_device *dev = vi->dev; - struct sk_buff *skb = NULL; - struct xdp_buff *xdp; - u8 flags; - - len -= vi->hdr_len; - - u64_stats_add(&stats->bytes, len); - - xdp = buf_to_xdp(vi, rq, buf, len); - if (!xdp) - return; - - if (unlikely(len < ETH_HLEN)) { - pr_debug("%s: short packet %i\n", dev->name, len); - DEV_STATS_INC(dev, rx_length_errors); - xsk_buff_free(xdp); - return; - } - - flags = ((struct virtio_net_common_hdr *)(xdp->data - vi->hdr_len))->hdr.flags; - - if (!vi->mergeable_rx_bufs) - skb = virtnet_receive_xsk_small(dev, vi, rq, xdp, xdp_xmit, stats); - - if (skb) - virtnet_receive_done(vi, rq, skb, flags); -} - static int virtnet_add_recvbuf_xsk(struct virtnet_info *vi, struct receive_queue *rq, struct xsk_buff_pool *pool, gfp_t gfp) { @@ -2516,67 +2392,31 @@ static void refill_work(struct work_struct *work) } } -static int virtnet_receive_xsk_bufs(struct virtnet_info *vi, - struct receive_queue *rq, - int budget, - unsigned int *xdp_xmit, - struct virtnet_rq_stats *stats) -{ - unsigned int len; - int packets = 0; - void *buf; - - while (packets < budget) { - buf = virtqueue_get_buf(rq->vq, &len); - if (!buf) - break; - - virtnet_receive_xsk_buf(vi, rq, buf, len, xdp_xmit, stats); - packets++; - } - - return packets; -} - -static int virtnet_receive_packets(struct virtnet_info *vi, - struct receive_queue *rq, - int budget, - unsigned int *xdp_xmit, - struct virtnet_rq_stats *stats) -{ - unsigned int len; - int packets = 0; - void *buf; - - if (!vi->big_packets || vi->mergeable_rx_bufs) { - void *ctx; - while (packets < budget && - (buf = virtnet_rq_get_buf(rq, &len, &ctx))) { - receive_buf(vi, rq, buf, len, ctx, xdp_xmit, stats); - packets++; - } - } else { - while (packets < budget && - (buf = virtqueue_get_buf(rq->vq, &len)) != NULL) { - receive_buf(vi, rq, buf, len, NULL, xdp_xmit, stats); - packets++; - } - } - - return packets; -} - static int virtnet_receive(struct receive_queue *rq, int budget, unsigned int *xdp_xmit) { struct virtnet_info *vi = rq->vq->vdev->priv; struct virtnet_rq_stats stats = {}; - int i, packets; + unsigned int len; + int packets = 0; + void *buf; + int i; - if (rq->xsk_pool) - packets = virtnet_receive_xsk_bufs(vi, rq, budget, xdp_xmit, &stats); - else - packets = virtnet_receive_packets(vi, rq, budget, xdp_xmit, &stats); + if (!vi->big_packets || vi->mergeable_rx_bufs) { + void *ctx; + + while (packets < budget && + (buf = virtnet_rq_get_buf(rq, &len, &ctx))) { + receive_buf(vi, rq, buf, len, ctx, xdp_xmit, &stats); + packets++; + } + } else { + while (packets < budget && + (buf = virtqueue_get_buf(rq->vq, &len)) != NULL) { + receive_buf(vi, rq, buf, len, NULL, xdp_xmit, &stats); + packets++; + } + } if (rq->vq->num_free > min((unsigned int)budget, virtqueue_get_vring_size(rq->vq)) / 2) { if (!try_fill_recv(vi, rq, GFP_ATOMIC)) { -- MST