io_uring/zcrx: grab a net device
authorPavel Begunkov <asml.silence@gmail.com>
Sat, 15 Feb 2025 00:09:38 +0000 (16:09 -0800)
committerJens Axboe <axboe@kernel.dk>
Mon, 17 Feb 2025 12:41:09 +0000 (05:41 -0700)
Zerocopy receive needs a net device to bind to its rx queue and dma map
buffers. As a preparation to following patches, resolve a net device
from the if_idx parameter with no functional changes otherwise.

Reviewed-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
Signed-off-by: David Wei <dw@davidwei.uk>
Acked-by: Jakub Kicinski <kuba@kernel.org>
Link: https://lore.kernel.org/r/20250215000947.789731-4-dw@davidwei.uk
Signed-off-by: Jens Axboe <axboe@kernel.dk>
io_uring/zcrx.c
io_uring/zcrx.h

index 04883a3ae80c42b9a38defd838aec86a43c3025f..435cd634f91c1b3f555857cbc451905c131e499a 100644 (file)
@@ -3,6 +3,8 @@
 #include <linux/errno.h>
 #include <linux/mm.h>
 #include <linux/io_uring.h>
+#include <linux/netdevice.h>
+#include <linux/rtnetlink.h>
 
 #include <uapi/linux/io_uring.h>
 
@@ -128,13 +130,28 @@ static struct io_zcrx_ifq *io_zcrx_ifq_alloc(struct io_ring_ctx *ctx)
 
        ifq->if_rxq = -1;
        ifq->ctx = ctx;
+       spin_lock_init(&ifq->lock);
        return ifq;
 }
 
+static void io_zcrx_drop_netdev(struct io_zcrx_ifq *ifq)
+{
+       spin_lock(&ifq->lock);
+       if (ifq->netdev) {
+               netdev_put(ifq->netdev, &ifq->netdev_tracker);
+               ifq->netdev = NULL;
+       }
+       spin_unlock(&ifq->lock);
+}
+
 static void io_zcrx_ifq_free(struct io_zcrx_ifq *ifq)
 {
+       io_zcrx_drop_netdev(ifq);
+
        if (ifq->area)
                io_zcrx_free_area(ifq->area);
+       if (ifq->dev)
+               put_device(ifq->dev);
 
        io_free_rbuf_ring(ifq);
        kfree(ifq);
@@ -195,6 +212,17 @@ int io_register_zcrx_ifq(struct io_ring_ctx *ctx,
        ifq->rq_entries = reg.rq_entries;
        ifq->if_rxq = reg.if_rxq;
 
+       ret = -ENODEV;
+       ifq->netdev = netdev_get_by_index(current->nsproxy->net_ns, reg.if_idx,
+                                         &ifq->netdev_tracker, GFP_KERNEL);
+       if (!ifq->netdev)
+               goto err;
+
+       ifq->dev = ifq->netdev->dev.parent;
+       if (!ifq->dev)
+               return -EOPNOTSUPP;
+       get_device(ifq->dev);
+
        reg.offsets.rqes = sizeof(struct io_uring);
        reg.offsets.head = offsetof(struct io_uring, head);
        reg.offsets.tail = offsetof(struct io_uring, tail);
index 53fd94b65b3800a889fd6f4ba271893b6b9575ab..595bca0001d2ceb3789f2cb50371f14d69df9aa0 100644 (file)
@@ -4,6 +4,7 @@
 
 #include <linux/io_uring_types.h>
 #include <net/page_pool/types.h>
+#include <net/net_trackers.h>
 
 struct io_zcrx_area {
        struct net_iov_area     nia;
@@ -27,6 +28,10 @@ struct io_zcrx_ifq {
        u32                             rq_entries;
 
        u32                             if_rxq;
+       struct device                   *dev;
+       struct net_device               *netdev;
+       netdevice_tracker               netdev_tracker;
+       spinlock_t                      lock;
 };
 
 #if defined(CONFIG_IO_URING_ZCRX)