* [PATCH net-next v4 0/4] virtio-net: Link queues to NAPIs
@ 2025-02-25 2:04 Joe Damato
2025-02-25 2:04 ` [PATCH net-next v4 1/4] virtio-net: Refactor napi_enable paths Joe Damato
` (5 more replies)
0 siblings, 6 replies; 18+ messages in thread
From: Joe Damato @ 2025-02-25 2:04 UTC (permalink / raw)
To: netdev
Cc: mkarsten, gerhard, jasowang, xuanzhuo, kuba, Joe Damato,
Alexei Starovoitov, Andrew Lunn,
open list:XDP (eXpress Data Path):Keyword:(?:b|_)xdp(?:b|_),
Daniel Borkmann, David S. Miller, Eric Dumazet,
Eugenio Pérez, Jesper Dangaard Brouer, John Fastabend,
open list, Michael S. Tsirkin, Paolo Abeni,
open list:VIRTIO CORE AND NET DRIVERS
Greetings:
Welcome to v4.
Jakub recently commented [1] that I should not hold this series on
virtio-net linking queues to NAPIs behind other important work that is
on-going and suggested I re-spin, so here we are :)
This is a significant refactor from the rfcv3 and as such I've dropped
almost all of the tags from reviewers except for patch 4 (sorry Gerhard
and Jason; the changes are significant so I think patches 1-3 need to be
re-reviewed).
As per the discussion on the v3 [2], now both RX and TX NAPIs use the
API to link queues to NAPIs. Since TX-only NAPIs don't have a NAPI ID,
commit 6597e8d35851 ("netdev-genl: Elide napi_id when not present") now
correctly elides the TX-only NAPIs (instead of printing zero) when the
queues and NAPIs are linked.
See the commit message of patch 3 for an example of how to get the NAPI
to queue mapping information.
See the commit message of patch 4 for an example of how NAPI IDs are
persistent despite queue count changes.
Thanks,
Joe
v4:
- Dropped Jakub's patch (previously patch 1).
- Significant refactor from v3 affecting patches 1-3.
- Patch 4 added tags from Jason and Gerhard.
rfcv3: https://lore.kernel.org/netdev/20250121191047.269844-1-jdamato@fastly.com/
- patch 3:
- Removed the xdp checks completely, as Gerhard Engleder pointed
out, they are likely not necessary.
- patch 4:
- Added Xuan Zhuo's Reviewed-by.
v2: https://lore.kernel.org/netdev/20250116055302.14308-1-jdamato@fastly.com/
- patch 1:
- New in the v2 from Jakub.
- patch 2:
- Previously patch 1, unchanged from v1.
- Added Gerhard Engleder's Reviewed-by.
- Added Lei Yang's Tested-by.
- patch 3:
- Introduced virtnet_napi_disable to eliminate duplicated code
in virtnet_xdp_set, virtnet_rx_pause, virtnet_disable_queue_pair,
refill_work as suggested by Jason Wang.
- As a result of the above refactor, dropped Reviewed-by and
Tested-by from patch 3.
- patch 4:
- New in v2. Adds persistent NAPI configuration. See commit message
for more details.
v1: https://lore.kernel.org/netdev/20250110202605.429475-1-jdamato@fastly.com/
[1]: https://lore.kernel.org/netdev/20250221142650.3c74dcac@kernel.org/
[2]: https://lore.kernel.org/netdev/20250127142400.24eca319@kernel.org/
Joe Damato (4):
virtio-net: Refactor napi_enable paths
virtio-net: Refactor napi_disable paths
virtio-net: Map NAPIs to queues
virtio_net: Use persistent NAPI config
drivers/net/virtio_net.c | 100 ++++++++++++++++++++++++++++-----------
1 file changed, 73 insertions(+), 27 deletions(-)
base-commit: 7183877d6853801258b7a8d3b51b415982e5097e
--
2.45.2
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH net-next v4 1/4] virtio-net: Refactor napi_enable paths
2025-02-25 2:04 [PATCH net-next v4 0/4] virtio-net: Link queues to NAPIs Joe Damato
@ 2025-02-25 2:04 ` Joe Damato
2025-02-26 5:49 ` Jason Wang
2025-02-25 2:04 ` [PATCH net-next v4 2/4] virtio-net: Refactor napi_disable paths Joe Damato
` (4 subsequent siblings)
5 siblings, 1 reply; 18+ messages in thread
From: Joe Damato @ 2025-02-25 2:04 UTC (permalink / raw)
To: netdev
Cc: mkarsten, gerhard, jasowang, xuanzhuo, kuba, Joe Damato,
Michael S. Tsirkin, Eugenio Pérez, Andrew Lunn,
David S. Miller, Eric Dumazet, Paolo Abeni,
open list:VIRTIO CORE AND NET DRIVERS, open list
Refactor virtnet_napi_enable and virtnet_napi_tx_enable to take a struct
receive_queue. Create a helper, virtnet_napi_do_enable, which contains
the logic to enable a NAPI.
Signed-off-by: Joe Damato <jdamato@fastly.com>
---
drivers/net/virtio_net.c | 37 +++++++++++++++++++++----------------
1 file changed, 21 insertions(+), 16 deletions(-)
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index ac26a6201c44..133b004c7a9a 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -2807,7 +2807,8 @@ static void skb_recv_done(struct virtqueue *rvq)
virtqueue_napi_schedule(&rq->napi, rvq);
}
-static void virtnet_napi_enable(struct virtqueue *vq, struct napi_struct *napi)
+static void virtnet_napi_do_enable(struct virtqueue *vq,
+ struct napi_struct *napi)
{
napi_enable(napi);
@@ -2820,10 +2821,16 @@ static void virtnet_napi_enable(struct virtqueue *vq, struct napi_struct *napi)
local_bh_enable();
}
-static void virtnet_napi_tx_enable(struct virtnet_info *vi,
- struct virtqueue *vq,
- struct napi_struct *napi)
+static void virtnet_napi_enable(struct receive_queue *rq)
{
+ virtnet_napi_do_enable(rq->vq, &rq->napi);
+}
+
+static void virtnet_napi_tx_enable(struct send_queue *sq)
+{
+ struct virtnet_info *vi = sq->vq->vdev->priv;
+ struct napi_struct *napi = &sq->napi;
+
if (!napi->weight)
return;
@@ -2835,7 +2842,7 @@ static void virtnet_napi_tx_enable(struct virtnet_info *vi,
return;
}
- return virtnet_napi_enable(vq, napi);
+ virtnet_napi_do_enable(sq->vq, napi);
}
static void virtnet_napi_tx_disable(struct napi_struct *napi)
@@ -2856,7 +2863,7 @@ static void refill_work(struct work_struct *work)
napi_disable(&rq->napi);
still_empty = !try_fill_recv(vi, rq, GFP_KERNEL);
- virtnet_napi_enable(rq->vq, &rq->napi);
+ virtnet_napi_enable(rq);
/* In theory, this can happen: if we don't get any buffers in
* we will *never* try to fill again.
@@ -3073,8 +3080,8 @@ static int virtnet_enable_queue_pair(struct virtnet_info *vi, int qp_index)
if (err < 0)
goto err_xdp_reg_mem_model;
- virtnet_napi_enable(vi->rq[qp_index].vq, &vi->rq[qp_index].napi);
- virtnet_napi_tx_enable(vi, vi->sq[qp_index].vq, &vi->sq[qp_index].napi);
+ virtnet_napi_enable(&vi->rq[qp_index]);
+ virtnet_napi_tx_enable(&vi->sq[qp_index]);
return 0;
@@ -3339,7 +3346,7 @@ static void virtnet_rx_resume(struct virtnet_info *vi, struct receive_queue *rq)
schedule_delayed_work(&vi->refill, 0);
if (running)
- virtnet_napi_enable(rq->vq, &rq->napi);
+ virtnet_napi_enable(rq);
}
static int virtnet_rx_resize(struct virtnet_info *vi,
@@ -3402,7 +3409,7 @@ static void virtnet_tx_resume(struct virtnet_info *vi, struct send_queue *sq)
__netif_tx_unlock_bh(txq);
if (running)
- virtnet_napi_tx_enable(vi, sq->vq, &sq->napi);
+ virtnet_napi_tx_enable(sq);
}
static int virtnet_tx_resize(struct virtnet_info *vi, struct send_queue *sq,
@@ -5983,9 +5990,8 @@ static int virtnet_xdp_set(struct net_device *dev, struct bpf_prog *prog,
if (old_prog)
bpf_prog_put(old_prog);
if (netif_running(dev)) {
- virtnet_napi_enable(vi->rq[i].vq, &vi->rq[i].napi);
- virtnet_napi_tx_enable(vi, vi->sq[i].vq,
- &vi->sq[i].napi);
+ virtnet_napi_enable(&vi->rq[i]);
+ virtnet_napi_tx_enable(&vi->sq[i]);
}
}
@@ -6000,9 +6006,8 @@ static int virtnet_xdp_set(struct net_device *dev, struct bpf_prog *prog,
if (netif_running(dev)) {
for (i = 0; i < vi->max_queue_pairs; i++) {
- virtnet_napi_enable(vi->rq[i].vq, &vi->rq[i].napi);
- virtnet_napi_tx_enable(vi, vi->sq[i].vq,
- &vi->sq[i].napi);
+ virtnet_napi_enable(&vi->rq[i]);
+ virtnet_napi_tx_enable(&vi->sq[i]);
}
}
if (prog)
--
2.45.2
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH net-next v4 2/4] virtio-net: Refactor napi_disable paths
2025-02-25 2:04 [PATCH net-next v4 0/4] virtio-net: Link queues to NAPIs Joe Damato
2025-02-25 2:04 ` [PATCH net-next v4 1/4] virtio-net: Refactor napi_enable paths Joe Damato
@ 2025-02-25 2:04 ` Joe Damato
2025-02-26 5:49 ` Jason Wang
2025-02-25 2:04 ` [PATCH net-next v4 3/4] virtio-net: Map NAPIs to queues Joe Damato
` (3 subsequent siblings)
5 siblings, 1 reply; 18+ messages in thread
From: Joe Damato @ 2025-02-25 2:04 UTC (permalink / raw)
To: netdev
Cc: mkarsten, gerhard, jasowang, xuanzhuo, kuba, Joe Damato,
Michael S. Tsirkin, Eugenio Pérez, Andrew Lunn,
David S. Miller, Eric Dumazet, Paolo Abeni,
open list:VIRTIO CORE AND NET DRIVERS, open list
Create virtnet_napi_disable helper and refactor virtnet_napi_tx_disable
to take a struct send_queue.
Signed-off-by: Joe Damato <jdamato@fastly.com>
---
drivers/net/virtio_net.c | 25 +++++++++++++++++--------
1 file changed, 17 insertions(+), 8 deletions(-)
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 133b004c7a9a..e578885c1093 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -2845,12 +2845,21 @@ static void virtnet_napi_tx_enable(struct send_queue *sq)
virtnet_napi_do_enable(sq->vq, napi);
}
-static void virtnet_napi_tx_disable(struct napi_struct *napi)
+static void virtnet_napi_tx_disable(struct send_queue *sq)
{
+ struct napi_struct *napi = &sq->napi;
+
if (napi->weight)
napi_disable(napi);
}
+static void virtnet_napi_disable(struct receive_queue *rq)
+{
+ struct napi_struct *napi = &rq->napi;
+
+ napi_disable(napi);
+}
+
static void refill_work(struct work_struct *work)
{
struct virtnet_info *vi =
@@ -2861,7 +2870,7 @@ static void refill_work(struct work_struct *work)
for (i = 0; i < vi->curr_queue_pairs; i++) {
struct receive_queue *rq = &vi->rq[i];
- napi_disable(&rq->napi);
+ virtnet_napi_disable(rq);
still_empty = !try_fill_recv(vi, rq, GFP_KERNEL);
virtnet_napi_enable(rq);
@@ -3060,8 +3069,8 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
static void virtnet_disable_queue_pair(struct virtnet_info *vi, int qp_index)
{
- virtnet_napi_tx_disable(&vi->sq[qp_index].napi);
- napi_disable(&vi->rq[qp_index].napi);
+ virtnet_napi_tx_disable(&vi->sq[qp_index]);
+ virtnet_napi_disable(&vi->rq[qp_index]);
xdp_rxq_info_unreg(&vi->rq[qp_index].xdp_rxq);
}
@@ -3333,7 +3342,7 @@ static void virtnet_rx_pause(struct virtnet_info *vi, struct receive_queue *rq)
bool running = netif_running(vi->dev);
if (running) {
- napi_disable(&rq->napi);
+ virtnet_napi_disable(rq);
virtnet_cancel_dim(vi, &rq->dim);
}
}
@@ -3375,7 +3384,7 @@ static void virtnet_tx_pause(struct virtnet_info *vi, struct send_queue *sq)
qindex = sq - vi->sq;
if (running)
- virtnet_napi_tx_disable(&sq->napi);
+ virtnet_napi_tx_disable(sq);
txq = netdev_get_tx_queue(vi->dev, qindex);
@@ -5952,8 +5961,8 @@ static int virtnet_xdp_set(struct net_device *dev, struct bpf_prog *prog,
/* Make sure NAPI is not using any XDP TX queues for RX. */
if (netif_running(dev)) {
for (i = 0; i < vi->max_queue_pairs; i++) {
- napi_disable(&vi->rq[i].napi);
- virtnet_napi_tx_disable(&vi->sq[i].napi);
+ virtnet_napi_disable(&vi->rq[i]);
+ virtnet_napi_tx_disable(&vi->sq[i]);
}
}
--
2.45.2
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH net-next v4 3/4] virtio-net: Map NAPIs to queues
2025-02-25 2:04 [PATCH net-next v4 0/4] virtio-net: Link queues to NAPIs Joe Damato
2025-02-25 2:04 ` [PATCH net-next v4 1/4] virtio-net: Refactor napi_enable paths Joe Damato
2025-02-25 2:04 ` [PATCH net-next v4 2/4] virtio-net: Refactor napi_disable paths Joe Damato
@ 2025-02-25 2:04 ` Joe Damato
2025-02-26 5:48 ` Jason Wang
2025-02-25 2:04 ` [PATCH net-next v4 4/4] virtio-net: Use persistent NAPI config Joe Damato
` (2 subsequent siblings)
5 siblings, 1 reply; 18+ messages in thread
From: Joe Damato @ 2025-02-25 2:04 UTC (permalink / raw)
To: netdev
Cc: mkarsten, gerhard, jasowang, xuanzhuo, kuba, Joe Damato,
Michael S. Tsirkin, Eugenio Pérez, Andrew Lunn,
David S. Miller, Eric Dumazet, Paolo Abeni,
open list:VIRTIO CORE AND NET DRIVERS, open list
Use netif_queue_set_napi to map NAPIs to queue IDs so that the mapping
can be accessed by user apps, taking care to hold RTNL as needed.
$ ethtool -i ens4 | grep driver
driver: virtio_net
$ sudo ethtool -L ens4 combined 4
$ ./tools/net/ynl/pyynl/cli.py \
--spec Documentation/netlink/specs/netdev.yaml \
--dump queue-get --json='{"ifindex": 2}'
[{'id': 0, 'ifindex': 2, 'napi-id': 8289, 'type': 'rx'},
{'id': 1, 'ifindex': 2, 'napi-id': 8290, 'type': 'rx'},
{'id': 2, 'ifindex': 2, 'napi-id': 8291, 'type': 'rx'},
{'id': 3, 'ifindex': 2, 'napi-id': 8292, 'type': 'rx'},
{'id': 0, 'ifindex': 2, 'type': 'tx'},
{'id': 1, 'ifindex': 2, 'type': 'tx'},
{'id': 2, 'ifindex': 2, 'type': 'tx'},
{'id': 3, 'ifindex': 2, 'type': 'tx'}]
Note that virtio_net has TX-only NAPIs which do not have NAPI IDs, so
the lack of 'napi-id' in the above output is expected.
Signed-off-by: Joe Damato <jdamato@fastly.com>
---
drivers/net/virtio_net.c | 73 ++++++++++++++++++++++++++++------------
1 file changed, 52 insertions(+), 21 deletions(-)
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index e578885c1093..13bb4a563073 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -2807,6 +2807,20 @@ static void skb_recv_done(struct virtqueue *rvq)
virtqueue_napi_schedule(&rq->napi, rvq);
}
+static void virtnet_queue_set_napi(struct net_device *dev,
+ struct napi_struct *napi,
+ enum netdev_queue_type q_type, int qidx,
+ bool need_rtnl)
+{
+ if (need_rtnl)
+ rtnl_lock();
+
+ netif_queue_set_napi(dev, qidx, q_type, napi);
+
+ if (need_rtnl)
+ rtnl_unlock();
+}
+
static void virtnet_napi_do_enable(struct virtqueue *vq,
struct napi_struct *napi)
{
@@ -2821,15 +2835,21 @@ static void virtnet_napi_do_enable(struct virtqueue *vq,
local_bh_enable();
}
-static void virtnet_napi_enable(struct receive_queue *rq)
+static void virtnet_napi_enable(struct receive_queue *rq, bool need_rtnl)
{
+ struct virtnet_info *vi = rq->vq->vdev->priv;
+ int qidx = vq2rxq(rq->vq);
+
virtnet_napi_do_enable(rq->vq, &rq->napi);
+ virtnet_queue_set_napi(vi->dev, &rq->napi,
+ NETDEV_QUEUE_TYPE_RX, qidx, need_rtnl);
}
-static void virtnet_napi_tx_enable(struct send_queue *sq)
+static void virtnet_napi_tx_enable(struct send_queue *sq, bool need_rtnl)
{
struct virtnet_info *vi = sq->vq->vdev->priv;
struct napi_struct *napi = &sq->napi;
+ int qidx = vq2txq(sq->vq);
if (!napi->weight)
return;
@@ -2843,20 +2863,31 @@ static void virtnet_napi_tx_enable(struct send_queue *sq)
}
virtnet_napi_do_enable(sq->vq, napi);
+ virtnet_queue_set_napi(vi->dev, napi, NETDEV_QUEUE_TYPE_TX, qidx,
+ need_rtnl);
}
-static void virtnet_napi_tx_disable(struct send_queue *sq)
+static void virtnet_napi_tx_disable(struct send_queue *sq, bool need_rtnl)
{
+ struct virtnet_info *vi = sq->vq->vdev->priv;
struct napi_struct *napi = &sq->napi;
+ int qidx = vq2txq(sq->vq);
- if (napi->weight)
+ if (napi->weight) {
+ virtnet_queue_set_napi(vi->dev, NULL, NETDEV_QUEUE_TYPE_TX,
+ qidx, need_rtnl);
napi_disable(napi);
+ }
}
-static void virtnet_napi_disable(struct receive_queue *rq)
+static void virtnet_napi_disable(struct receive_queue *rq, bool need_rtnl)
{
+ struct virtnet_info *vi = rq->vq->vdev->priv;
struct napi_struct *napi = &rq->napi;
+ int qidx = vq2rxq(rq->vq);
+ virtnet_queue_set_napi(vi->dev, NULL, NETDEV_QUEUE_TYPE_TX, qidx,
+ need_rtnl);
napi_disable(napi);
}
@@ -2870,9 +2901,9 @@ static void refill_work(struct work_struct *work)
for (i = 0; i < vi->curr_queue_pairs; i++) {
struct receive_queue *rq = &vi->rq[i];
- virtnet_napi_disable(rq);
+ virtnet_napi_disable(rq, true);
still_empty = !try_fill_recv(vi, rq, GFP_KERNEL);
- virtnet_napi_enable(rq);
+ virtnet_napi_enable(rq, true);
/* In theory, this can happen: if we don't get any buffers in
* we will *never* try to fill again.
@@ -3069,8 +3100,8 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
static void virtnet_disable_queue_pair(struct virtnet_info *vi, int qp_index)
{
- virtnet_napi_tx_disable(&vi->sq[qp_index]);
- virtnet_napi_disable(&vi->rq[qp_index]);
+ virtnet_napi_tx_disable(&vi->sq[qp_index], false);
+ virtnet_napi_disable(&vi->rq[qp_index], false);
xdp_rxq_info_unreg(&vi->rq[qp_index].xdp_rxq);
}
@@ -3089,8 +3120,8 @@ static int virtnet_enable_queue_pair(struct virtnet_info *vi, int qp_index)
if (err < 0)
goto err_xdp_reg_mem_model;
- virtnet_napi_enable(&vi->rq[qp_index]);
- virtnet_napi_tx_enable(&vi->sq[qp_index]);
+ virtnet_napi_enable(&vi->rq[qp_index], false);
+ virtnet_napi_tx_enable(&vi->sq[qp_index], false);
return 0;
@@ -3342,7 +3373,7 @@ static void virtnet_rx_pause(struct virtnet_info *vi, struct receive_queue *rq)
bool running = netif_running(vi->dev);
if (running) {
- virtnet_napi_disable(rq);
+ virtnet_napi_disable(rq, true);
virtnet_cancel_dim(vi, &rq->dim);
}
}
@@ -3355,7 +3386,7 @@ static void virtnet_rx_resume(struct virtnet_info *vi, struct receive_queue *rq)
schedule_delayed_work(&vi->refill, 0);
if (running)
- virtnet_napi_enable(rq);
+ virtnet_napi_enable(rq, true);
}
static int virtnet_rx_resize(struct virtnet_info *vi,
@@ -3384,7 +3415,7 @@ static void virtnet_tx_pause(struct virtnet_info *vi, struct send_queue *sq)
qindex = sq - vi->sq;
if (running)
- virtnet_napi_tx_disable(sq);
+ virtnet_napi_tx_disable(sq, true);
txq = netdev_get_tx_queue(vi->dev, qindex);
@@ -3418,7 +3449,7 @@ static void virtnet_tx_resume(struct virtnet_info *vi, struct send_queue *sq)
__netif_tx_unlock_bh(txq);
if (running)
- virtnet_napi_tx_enable(sq);
+ virtnet_napi_tx_enable(sq, true);
}
static int virtnet_tx_resize(struct virtnet_info *vi, struct send_queue *sq,
@@ -5961,8 +5992,8 @@ static int virtnet_xdp_set(struct net_device *dev, struct bpf_prog *prog,
/* Make sure NAPI is not using any XDP TX queues for RX. */
if (netif_running(dev)) {
for (i = 0; i < vi->max_queue_pairs; i++) {
- virtnet_napi_disable(&vi->rq[i]);
- virtnet_napi_tx_disable(&vi->sq[i]);
+ virtnet_napi_disable(&vi->rq[i], false);
+ virtnet_napi_tx_disable(&vi->sq[i], false);
}
}
@@ -5999,8 +6030,8 @@ static int virtnet_xdp_set(struct net_device *dev, struct bpf_prog *prog,
if (old_prog)
bpf_prog_put(old_prog);
if (netif_running(dev)) {
- virtnet_napi_enable(&vi->rq[i]);
- virtnet_napi_tx_enable(&vi->sq[i]);
+ virtnet_napi_enable(&vi->rq[i], false);
+ virtnet_napi_tx_enable(&vi->sq[i], false);
}
}
@@ -6015,8 +6046,8 @@ static int virtnet_xdp_set(struct net_device *dev, struct bpf_prog *prog,
if (netif_running(dev)) {
for (i = 0; i < vi->max_queue_pairs; i++) {
- virtnet_napi_enable(&vi->rq[i]);
- virtnet_napi_tx_enable(&vi->sq[i]);
+ virtnet_napi_enable(&vi->rq[i], false);
+ virtnet_napi_tx_enable(&vi->sq[i], false);
}
}
if (prog)
--
2.45.2
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH net-next v4 4/4] virtio-net: Use persistent NAPI config
2025-02-25 2:04 [PATCH net-next v4 0/4] virtio-net: Link queues to NAPIs Joe Damato
` (2 preceding siblings ...)
2025-02-25 2:04 ` [PATCH net-next v4 3/4] virtio-net: Map NAPIs to queues Joe Damato
@ 2025-02-25 2:04 ` Joe Damato
2025-02-25 15:46 ` [PATCH net-next v4 0/4] virtio-net: Link queues to NAPIs Lei Yang
2025-02-25 15:54 ` Michael S. Tsirkin
5 siblings, 0 replies; 18+ messages in thread
From: Joe Damato @ 2025-02-25 2:04 UTC (permalink / raw)
To: netdev
Cc: mkarsten, gerhard, jasowang, xuanzhuo, kuba, Joe Damato,
Michael S. Tsirkin, Eugenio Pérez, Andrew Lunn,
David S. Miller, Eric Dumazet, Paolo Abeni,
open list:VIRTIO CORE AND NET DRIVERS, open list
Use persistent NAPI config so that NAPI IDs are not renumbered as queue
counts change.
$ sudo ethtool -l ens4 | tail -5 | egrep -i '(current|combined)'
Current hardware settings:
Combined: 4
$ ./tools/net/ynl/pyynl/cli.py \
--spec Documentation/netlink/specs/netdev.yaml \
--dump queue-get --json='{"ifindex": 2}'
[{'id': 0, 'ifindex': 2, 'napi-id': 8193, 'type': 'rx'},
{'id': 1, 'ifindex': 2, 'napi-id': 8194, 'type': 'rx'},
{'id': 2, 'ifindex': 2, 'napi-id': 8195, 'type': 'rx'},
{'id': 3, 'ifindex': 2, 'napi-id': 8196, 'type': 'rx'},
{'id': 0, 'ifindex': 2, 'type': 'tx'},
{'id': 1, 'ifindex': 2, 'type': 'tx'},
{'id': 2, 'ifindex': 2, 'type': 'tx'},
{'id': 3, 'ifindex': 2, 'type': 'tx'}]
Now adjust the queue count, note that the NAPI IDs are not renumbered:
$ sudo ethtool -L ens4 combined 1
$ ./tools/net/ynl/pyynl/cli.py \
--spec Documentation/netlink/specs/netdev.yaml \
--dump queue-get --json='{"ifindex": 2}'
[{'id': 0, 'ifindex': 2, 'napi-id': 8193, 'type': 'rx'},
{'id': 0, 'ifindex': 2, 'type': 'tx'}]
$ sudo ethtool -L ens4 combined 8
$ ./tools/net/ynl/pyynl/cli.py \
--spec Documentation/netlink/specs/netdev.yaml \
--dump queue-get --json='{"ifindex": 2}'
[{'id': 0, 'ifindex': 2, 'napi-id': 8193, 'type': 'rx'},
{'id': 1, 'ifindex': 2, 'napi-id': 8194, 'type': 'rx'},
{'id': 2, 'ifindex': 2, 'napi-id': 8195, 'type': 'rx'},
{'id': 3, 'ifindex': 2, 'napi-id': 8196, 'type': 'rx'},
{'id': 4, 'ifindex': 2, 'napi-id': 8197, 'type': 'rx'},
{'id': 5, 'ifindex': 2, 'napi-id': 8198, 'type': 'rx'},
{'id': 6, 'ifindex': 2, 'napi-id': 8199, 'type': 'rx'},
{'id': 7, 'ifindex': 2, 'napi-id': 8200, 'type': 'rx'},
[...]
Signed-off-by: Joe Damato <jdamato@fastly.com>
Reviewed-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Reviewed-by: Gerhard Engleder <gerhard@engleder-embedded.com>
Acked-by: Jason Wang <jasowang@redhat.com>
---
drivers/net/virtio_net.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 13bb4a563073..186030693eeb 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -6454,8 +6454,9 @@ static int virtnet_alloc_queues(struct virtnet_info *vi)
INIT_DELAYED_WORK(&vi->refill, refill_work);
for (i = 0; i < vi->max_queue_pairs; i++) {
vi->rq[i].pages = NULL;
- netif_napi_add_weight(vi->dev, &vi->rq[i].napi, virtnet_poll,
- napi_weight);
+ netif_napi_add_config(vi->dev, &vi->rq[i].napi, virtnet_poll,
+ i);
+ vi->rq[i].napi.weight = napi_weight;
netif_napi_add_tx_weight(vi->dev, &vi->sq[i].napi,
virtnet_poll_tx,
napi_tx ? napi_weight : 0);
--
2.45.2
^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH net-next v4 0/4] virtio-net: Link queues to NAPIs
2025-02-25 2:04 [PATCH net-next v4 0/4] virtio-net: Link queues to NAPIs Joe Damato
` (3 preceding siblings ...)
2025-02-25 2:04 ` [PATCH net-next v4 4/4] virtio-net: Use persistent NAPI config Joe Damato
@ 2025-02-25 15:46 ` Lei Yang
2025-02-26 9:41 ` Jason Wang
2025-02-25 15:54 ` Michael S. Tsirkin
5 siblings, 1 reply; 18+ messages in thread
From: Lei Yang @ 2025-02-25 15:46 UTC (permalink / raw)
To: Joe Damato
Cc: netdev, mkarsten, gerhard, jasowang, xuanzhuo, kuba,
Alexei Starovoitov, Andrew Lunn,
open list:XDP (eXpress Data Path):Keyword:(?:b|_)xdp(?:b|_),
Daniel Borkmann, David S. Miller, Eric Dumazet,
Eugenio Pérez, Jesper Dangaard Brouer, John Fastabend,
open list, Michael S. Tsirkin, Paolo Abeni,
open list:VIRTIO CORE AND NET DRIVERS
I tested this series of patches with virtio-net regression tests,
everything works fine.
Tested-by: Lei Yang <leiyang@redhat.com>
On Tue, Feb 25, 2025 at 10:05 AM Joe Damato <jdamato@fastly.com> wrote:
>
> Greetings:
>
> Welcome to v4.
>
> Jakub recently commented [1] that I should not hold this series on
> virtio-net linking queues to NAPIs behind other important work that is
> on-going and suggested I re-spin, so here we are :)
>
> This is a significant refactor from the rfcv3 and as such I've dropped
> almost all of the tags from reviewers except for patch 4 (sorry Gerhard
> and Jason; the changes are significant so I think patches 1-3 need to be
> re-reviewed).
>
> As per the discussion on the v3 [2], now both RX and TX NAPIs use the
> API to link queues to NAPIs. Since TX-only NAPIs don't have a NAPI ID,
> commit 6597e8d35851 ("netdev-genl: Elide napi_id when not present") now
> correctly elides the TX-only NAPIs (instead of printing zero) when the
> queues and NAPIs are linked.
>
> See the commit message of patch 3 for an example of how to get the NAPI
> to queue mapping information.
>
> See the commit message of patch 4 for an example of how NAPI IDs are
> persistent despite queue count changes.
>
> Thanks,
> Joe
>
> v4:
> - Dropped Jakub's patch (previously patch 1).
> - Significant refactor from v3 affecting patches 1-3.
> - Patch 4 added tags from Jason and Gerhard.
>
> rfcv3: https://lore.kernel.org/netdev/20250121191047.269844-1-jdamato@fastly.com/
> - patch 3:
> - Removed the xdp checks completely, as Gerhard Engleder pointed
> out, they are likely not necessary.
>
> - patch 4:
> - Added Xuan Zhuo's Reviewed-by.
>
> v2: https://lore.kernel.org/netdev/20250116055302.14308-1-jdamato@fastly.com/
> - patch 1:
> - New in the v2 from Jakub.
>
> - patch 2:
> - Previously patch 1, unchanged from v1.
> - Added Gerhard Engleder's Reviewed-by.
> - Added Lei Yang's Tested-by.
>
> - patch 3:
> - Introduced virtnet_napi_disable to eliminate duplicated code
> in virtnet_xdp_set, virtnet_rx_pause, virtnet_disable_queue_pair,
> refill_work as suggested by Jason Wang.
> - As a result of the above refactor, dropped Reviewed-by and
> Tested-by from patch 3.
>
> - patch 4:
> - New in v2. Adds persistent NAPI configuration. See commit message
> for more details.
>
> v1: https://lore.kernel.org/netdev/20250110202605.429475-1-jdamato@fastly.com/
>
> [1]: https://lore.kernel.org/netdev/20250221142650.3c74dcac@kernel.org/
> [2]: https://lore.kernel.org/netdev/20250127142400.24eca319@kernel.org/
>
> Joe Damato (4):
> virtio-net: Refactor napi_enable paths
> virtio-net: Refactor napi_disable paths
> virtio-net: Map NAPIs to queues
> virtio_net: Use persistent NAPI config
>
> drivers/net/virtio_net.c | 100 ++++++++++++++++++++++++++++-----------
> 1 file changed, 73 insertions(+), 27 deletions(-)
>
>
> base-commit: 7183877d6853801258b7a8d3b51b415982e5097e
> --
> 2.45.2
>
>
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH net-next v4 0/4] virtio-net: Link queues to NAPIs
2025-02-25 2:04 [PATCH net-next v4 0/4] virtio-net: Link queues to NAPIs Joe Damato
` (4 preceding siblings ...)
2025-02-25 15:46 ` [PATCH net-next v4 0/4] virtio-net: Link queues to NAPIs Lei Yang
@ 2025-02-25 15:54 ` Michael S. Tsirkin
5 siblings, 0 replies; 18+ messages in thread
From: Michael S. Tsirkin @ 2025-02-25 15:54 UTC (permalink / raw)
To: Joe Damato
Cc: netdev, mkarsten, gerhard, jasowang, xuanzhuo, kuba,
Alexei Starovoitov, Andrew Lunn,
open list:XDP (eXpress Data Path):Keyword:(?:b|_)xdp(?:b|_),
Daniel Borkmann, David S. Miller, Eric Dumazet,
Eugenio Pérez, Jesper Dangaard Brouer, John Fastabend,
open list, Paolo Abeni, open list:VIRTIO CORE AND NET DRIVERS
On Tue, Feb 25, 2025 at 02:04:47AM +0000, Joe Damato wrote:
> Greetings:
>
> Welcome to v4.
>
> Jakub recently commented [1] that I should not hold this series on
> virtio-net linking queues to NAPIs behind other important work that is
> on-going and suggested I re-spin, so here we are :)
>
> This is a significant refactor from the rfcv3 and as such I've dropped
> almost all of the tags from reviewers except for patch 4 (sorry Gerhard
> and Jason; the changes are significant so I think patches 1-3 need to be
> re-reviewed).
>
> As per the discussion on the v3 [2], now both RX and TX NAPIs use the
> API to link queues to NAPIs. Since TX-only NAPIs don't have a NAPI ID,
> commit 6597e8d35851 ("netdev-genl: Elide napi_id when not present") now
> correctly elides the TX-only NAPIs (instead of printing zero) when the
> queues and NAPIs are linked.
>
> See the commit message of patch 3 for an example of how to get the NAPI
> to queue mapping information.
>
> See the commit message of patch 4 for an example of how NAPI IDs are
> persistent despite queue count changes.
>
> Thanks,
> Joe
Acked-by: Michael S. Tsirkin <mst@redhat.com>
> v4:
> - Dropped Jakub's patch (previously patch 1).
> - Significant refactor from v3 affecting patches 1-3.
> - Patch 4 added tags from Jason and Gerhard.
>
> rfcv3: https://lore.kernel.org/netdev/20250121191047.269844-1-jdamato@fastly.com/
> - patch 3:
> - Removed the xdp checks completely, as Gerhard Engleder pointed
> out, they are likely not necessary.
>
> - patch 4:
> - Added Xuan Zhuo's Reviewed-by.
>
> v2: https://lore.kernel.org/netdev/20250116055302.14308-1-jdamato@fastly.com/
> - patch 1:
> - New in the v2 from Jakub.
>
> - patch 2:
> - Previously patch 1, unchanged from v1.
> - Added Gerhard Engleder's Reviewed-by.
> - Added Lei Yang's Tested-by.
>
> - patch 3:
> - Introduced virtnet_napi_disable to eliminate duplicated code
> in virtnet_xdp_set, virtnet_rx_pause, virtnet_disable_queue_pair,
> refill_work as suggested by Jason Wang.
> - As a result of the above refactor, dropped Reviewed-by and
> Tested-by from patch 3.
>
> - patch 4:
> - New in v2. Adds persistent NAPI configuration. See commit message
> for more details.
>
> v1: https://lore.kernel.org/netdev/20250110202605.429475-1-jdamato@fastly.com/
>
> [1]: https://lore.kernel.org/netdev/20250221142650.3c74dcac@kernel.org/
> [2]: https://lore.kernel.org/netdev/20250127142400.24eca319@kernel.org/
>
> Joe Damato (4):
> virtio-net: Refactor napi_enable paths
> virtio-net: Refactor napi_disable paths
> virtio-net: Map NAPIs to queues
> virtio_net: Use persistent NAPI config
>
> drivers/net/virtio_net.c | 100 ++++++++++++++++++++++++++++-----------
> 1 file changed, 73 insertions(+), 27 deletions(-)
>
>
> base-commit: 7183877d6853801258b7a8d3b51b415982e5097e
> --
> 2.45.2
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH net-next v4 3/4] virtio-net: Map NAPIs to queues
2025-02-25 2:04 ` [PATCH net-next v4 3/4] virtio-net: Map NAPIs to queues Joe Damato
@ 2025-02-26 5:48 ` Jason Wang
2025-02-26 18:03 ` Joe Damato
0 siblings, 1 reply; 18+ messages in thread
From: Jason Wang @ 2025-02-26 5:48 UTC (permalink / raw)
To: Joe Damato
Cc: netdev, mkarsten, gerhard, xuanzhuo, kuba, Michael S. Tsirkin,
Eugenio Pérez, Andrew Lunn, David S. Miller, Eric Dumazet,
Paolo Abeni, open list:VIRTIO CORE AND NET DRIVERS, open list
On Tue, Feb 25, 2025 at 10:05 AM Joe Damato <jdamato@fastly.com> wrote:
>
> Use netif_queue_set_napi to map NAPIs to queue IDs so that the mapping
> can be accessed by user apps, taking care to hold RTNL as needed.
I may miss something but I wonder whether letting the caller hold the
lock is better.
More below.
>
> $ ethtool -i ens4 | grep driver
> driver: virtio_net
>
> $ sudo ethtool -L ens4 combined 4
>
> $ ./tools/net/ynl/pyynl/cli.py \
> --spec Documentation/netlink/specs/netdev.yaml \
> --dump queue-get --json='{"ifindex": 2}'
> [{'id': 0, 'ifindex': 2, 'napi-id': 8289, 'type': 'rx'},
> {'id': 1, 'ifindex': 2, 'napi-id': 8290, 'type': 'rx'},
> {'id': 2, 'ifindex': 2, 'napi-id': 8291, 'type': 'rx'},
> {'id': 3, 'ifindex': 2, 'napi-id': 8292, 'type': 'rx'},
> {'id': 0, 'ifindex': 2, 'type': 'tx'},
> {'id': 1, 'ifindex': 2, 'type': 'tx'},
> {'id': 2, 'ifindex': 2, 'type': 'tx'},
> {'id': 3, 'ifindex': 2, 'type': 'tx'}]
>
> Note that virtio_net has TX-only NAPIs which do not have NAPI IDs, so
> the lack of 'napi-id' in the above output is expected.
>
> Signed-off-by: Joe Damato <jdamato@fastly.com>
> ---
> drivers/net/virtio_net.c | 73 ++++++++++++++++++++++++++++------------
> 1 file changed, 52 insertions(+), 21 deletions(-)
>
> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> index e578885c1093..13bb4a563073 100644
> --- a/drivers/net/virtio_net.c
> +++ b/drivers/net/virtio_net.c
> @@ -2807,6 +2807,20 @@ static void skb_recv_done(struct virtqueue *rvq)
> virtqueue_napi_schedule(&rq->napi, rvq);
> }
>
> +static void virtnet_queue_set_napi(struct net_device *dev,
> + struct napi_struct *napi,
> + enum netdev_queue_type q_type, int qidx,
> + bool need_rtnl)
> +{
> + if (need_rtnl)
> + rtnl_lock();
> +
> + netif_queue_set_napi(dev, qidx, q_type, napi);
> +
> + if (need_rtnl)
> + rtnl_unlock();
> +}
> +
> static void virtnet_napi_do_enable(struct virtqueue *vq,
> struct napi_struct *napi)
> {
> @@ -2821,15 +2835,21 @@ static void virtnet_napi_do_enable(struct virtqueue *vq,
> local_bh_enable();
> }
>
> -static void virtnet_napi_enable(struct receive_queue *rq)
> +static void virtnet_napi_enable(struct receive_queue *rq, bool need_rtnl)
> {
> + struct virtnet_info *vi = rq->vq->vdev->priv;
> + int qidx = vq2rxq(rq->vq);
> +
> virtnet_napi_do_enable(rq->vq, &rq->napi);
> + virtnet_queue_set_napi(vi->dev, &rq->napi,
> + NETDEV_QUEUE_TYPE_RX, qidx, need_rtnl);
> }
>
> -static void virtnet_napi_tx_enable(struct send_queue *sq)
> +static void virtnet_napi_tx_enable(struct send_queue *sq, bool need_rtnl)
> {
> struct virtnet_info *vi = sq->vq->vdev->priv;
> struct napi_struct *napi = &sq->napi;
> + int qidx = vq2txq(sq->vq);
>
> if (!napi->weight)
> return;
> @@ -2843,20 +2863,31 @@ static void virtnet_napi_tx_enable(struct send_queue *sq)
> }
>
> virtnet_napi_do_enable(sq->vq, napi);
> + virtnet_queue_set_napi(vi->dev, napi, NETDEV_QUEUE_TYPE_TX, qidx,
> + need_rtnl);
> }
>
> -static void virtnet_napi_tx_disable(struct send_queue *sq)
> +static void virtnet_napi_tx_disable(struct send_queue *sq, bool need_rtnl)
> {
> + struct virtnet_info *vi = sq->vq->vdev->priv;
> struct napi_struct *napi = &sq->napi;
> + int qidx = vq2txq(sq->vq);
>
> - if (napi->weight)
> + if (napi->weight) {
> + virtnet_queue_set_napi(vi->dev, NULL, NETDEV_QUEUE_TYPE_TX,
> + qidx, need_rtnl);
> napi_disable(napi);
> + }
> }
>
> -static void virtnet_napi_disable(struct receive_queue *rq)
> +static void virtnet_napi_disable(struct receive_queue *rq, bool need_rtnl)
> {
> + struct virtnet_info *vi = rq->vq->vdev->priv;
> struct napi_struct *napi = &rq->napi;
> + int qidx = vq2rxq(rq->vq);
>
> + virtnet_queue_set_napi(vi->dev, NULL, NETDEV_QUEUE_TYPE_TX, qidx,
> + need_rtnl);
> napi_disable(napi);
> }
>
> @@ -2870,9 +2901,9 @@ static void refill_work(struct work_struct *work)
> for (i = 0; i < vi->curr_queue_pairs; i++) {
> struct receive_queue *rq = &vi->rq[i];
>
> - virtnet_napi_disable(rq);
> + virtnet_napi_disable(rq, true);
> still_empty = !try_fill_recv(vi, rq, GFP_KERNEL);
> - virtnet_napi_enable(rq);
> + virtnet_napi_enable(rq, true);
>
> /* In theory, this can happen: if we don't get any buffers in
> * we will *never* try to fill again.
> @@ -3069,8 +3100,8 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
>
> static void virtnet_disable_queue_pair(struct virtnet_info *vi, int qp_index)
> {
> - virtnet_napi_tx_disable(&vi->sq[qp_index]);
> - virtnet_napi_disable(&vi->rq[qp_index]);
> + virtnet_napi_tx_disable(&vi->sq[qp_index], false);
> + virtnet_napi_disable(&vi->rq[qp_index], false);
> xdp_rxq_info_unreg(&vi->rq[qp_index].xdp_rxq);
> }
>
> @@ -3089,8 +3120,8 @@ static int virtnet_enable_queue_pair(struct virtnet_info *vi, int qp_index)
> if (err < 0)
> goto err_xdp_reg_mem_model;
>
> - virtnet_napi_enable(&vi->rq[qp_index]);
> - virtnet_napi_tx_enable(&vi->sq[qp_index]);
> + virtnet_napi_enable(&vi->rq[qp_index], false);
> + virtnet_napi_tx_enable(&vi->sq[qp_index], false);
>
> return 0;
>
> @@ -3342,7 +3373,7 @@ static void virtnet_rx_pause(struct virtnet_info *vi, struct receive_queue *rq)
> bool running = netif_running(vi->dev);
>
> if (running) {
> - virtnet_napi_disable(rq);
> + virtnet_napi_disable(rq, true);
During the resize, the rtnl lock has been held on the ethtool path
rtnl_lock();
rc = __dev_ethtool(net, ifr, useraddr, ethcmd, state);
rtnl_unlock();
virtnet_rx_resize()
virtnet_rx_pause()
and in the case of XSK binding, I see ASSERT_RTNL in xp_assign_dev() at least.
Thanks
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH net-next v4 1/4] virtio-net: Refactor napi_enable paths
2025-02-25 2:04 ` [PATCH net-next v4 1/4] virtio-net: Refactor napi_enable paths Joe Damato
@ 2025-02-26 5:49 ` Jason Wang
0 siblings, 0 replies; 18+ messages in thread
From: Jason Wang @ 2025-02-26 5:49 UTC (permalink / raw)
To: Joe Damato
Cc: netdev, mkarsten, gerhard, xuanzhuo, kuba, Michael S. Tsirkin,
Eugenio Pérez, Andrew Lunn, David S. Miller, Eric Dumazet,
Paolo Abeni, open list:VIRTIO CORE AND NET DRIVERS, open list
On Tue, Feb 25, 2025 at 10:05 AM Joe Damato <jdamato@fastly.com> wrote:
>
> Refactor virtnet_napi_enable and virtnet_napi_tx_enable to take a struct
> receive_queue. Create a helper, virtnet_napi_do_enable, which contains
> the logic to enable a NAPI.
>
> Signed-off-by: Joe Damato <jdamato@fastly.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Thanks
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH net-next v4 2/4] virtio-net: Refactor napi_disable paths
2025-02-25 2:04 ` [PATCH net-next v4 2/4] virtio-net: Refactor napi_disable paths Joe Damato
@ 2025-02-26 5:49 ` Jason Wang
0 siblings, 0 replies; 18+ messages in thread
From: Jason Wang @ 2025-02-26 5:49 UTC (permalink / raw)
To: Joe Damato
Cc: netdev, mkarsten, gerhard, xuanzhuo, kuba, Michael S. Tsirkin,
Eugenio Pérez, Andrew Lunn, David S. Miller, Eric Dumazet,
Paolo Abeni, open list:VIRTIO CORE AND NET DRIVERS, open list
On Tue, Feb 25, 2025 at 10:05 AM Joe Damato <jdamato@fastly.com> wrote:
>
> Create virtnet_napi_disable helper and refactor virtnet_napi_tx_disable
> to take a struct send_queue.
>
> Signed-off-by: Joe Damato <jdamato@fastly.com>
> ---
Acked-by: Jason Wang <jasowang@redhat.com>
Thanks
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH net-next v4 0/4] virtio-net: Link queues to NAPIs
2025-02-25 15:46 ` [PATCH net-next v4 0/4] virtio-net: Link queues to NAPIs Lei Yang
@ 2025-02-26 9:41 ` Jason Wang
0 siblings, 0 replies; 18+ messages in thread
From: Jason Wang @ 2025-02-26 9:41 UTC (permalink / raw)
To: Lei Yang
Cc: Joe Damato, netdev, mkarsten, gerhard, xuanzhuo, kuba,
Alexei Starovoitov, Andrew Lunn,
open list:XDP (eXpress Data Path):Keyword:(?:b|_)xdp(?:b|_),
Daniel Borkmann, David S. Miller, Eric Dumazet,
Eugenio Pérez, Jesper Dangaard Brouer, John Fastabend,
open list, Michael S. Tsirkin, Paolo Abeni,
open list:VIRTIO CORE AND NET DRIVERS
On Tue, Feb 25, 2025 at 11:47 PM Lei Yang <leiyang@redhat.com> wrote:
>
> I tested this series of patches with virtio-net regression tests,
> everything works fine.
>
> Tested-by: Lei Yang <leiyang@redhat.com>
If it's possible, I would like to add the resize (via ethtool) support
in the regression test.
Thanks
>
>
> On Tue, Feb 25, 2025 at 10:05 AM Joe Damato <jdamato@fastly.com> wrote:
> >
> > Greetings:
> >
> > Welcome to v4.
> >
> > Jakub recently commented [1] that I should not hold this series on
> > virtio-net linking queues to NAPIs behind other important work that is
> > on-going and suggested I re-spin, so here we are :)
> >
> > This is a significant refactor from the rfcv3 and as such I've dropped
> > almost all of the tags from reviewers except for patch 4 (sorry Gerhard
> > and Jason; the changes are significant so I think patches 1-3 need to be
> > re-reviewed).
> >
> > As per the discussion on the v3 [2], now both RX and TX NAPIs use the
> > API to link queues to NAPIs. Since TX-only NAPIs don't have a NAPI ID,
> > commit 6597e8d35851 ("netdev-genl: Elide napi_id when not present") now
> > correctly elides the TX-only NAPIs (instead of printing zero) when the
> > queues and NAPIs are linked.
> >
> > See the commit message of patch 3 for an example of how to get the NAPI
> > to queue mapping information.
> >
> > See the commit message of patch 4 for an example of how NAPI IDs are
> > persistent despite queue count changes.
> >
> > Thanks,
> > Joe
> >
> > v4:
> > - Dropped Jakub's patch (previously patch 1).
> > - Significant refactor from v3 affecting patches 1-3.
> > - Patch 4 added tags from Jason and Gerhard.
> >
> > rfcv3: https://lore.kernel.org/netdev/20250121191047.269844-1-jdamato@fastly.com/
> > - patch 3:
> > - Removed the xdp checks completely, as Gerhard Engleder pointed
> > out, they are likely not necessary.
> >
> > - patch 4:
> > - Added Xuan Zhuo's Reviewed-by.
> >
> > v2: https://lore.kernel.org/netdev/20250116055302.14308-1-jdamato@fastly.com/
> > - patch 1:
> > - New in the v2 from Jakub.
> >
> > - patch 2:
> > - Previously patch 1, unchanged from v1.
> > - Added Gerhard Engleder's Reviewed-by.
> > - Added Lei Yang's Tested-by.
> >
> > - patch 3:
> > - Introduced virtnet_napi_disable to eliminate duplicated code
> > in virtnet_xdp_set, virtnet_rx_pause, virtnet_disable_queue_pair,
> > refill_work as suggested by Jason Wang.
> > - As a result of the above refactor, dropped Reviewed-by and
> > Tested-by from patch 3.
> >
> > - patch 4:
> > - New in v2. Adds persistent NAPI configuration. See commit message
> > for more details.
> >
> > v1: https://lore.kernel.org/netdev/20250110202605.429475-1-jdamato@fastly.com/
> >
> > [1]: https://lore.kernel.org/netdev/20250221142650.3c74dcac@kernel.org/
> > [2]: https://lore.kernel.org/netdev/20250127142400.24eca319@kernel.org/
> >
> > Joe Damato (4):
> > virtio-net: Refactor napi_enable paths
> > virtio-net: Refactor napi_disable paths
> > virtio-net: Map NAPIs to queues
> > virtio_net: Use persistent NAPI config
> >
> > drivers/net/virtio_net.c | 100 ++++++++++++++++++++++++++++-----------
> > 1 file changed, 73 insertions(+), 27 deletions(-)
> >
> >
> > base-commit: 7183877d6853801258b7a8d3b51b415982e5097e
> > --
> > 2.45.2
> >
> >
>
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH net-next v4 3/4] virtio-net: Map NAPIs to queues
2025-02-26 5:48 ` Jason Wang
@ 2025-02-26 18:03 ` Joe Damato
2025-02-26 18:08 ` Joe Damato
2025-02-26 22:11 ` Michael S. Tsirkin
0 siblings, 2 replies; 18+ messages in thread
From: Joe Damato @ 2025-02-26 18:03 UTC (permalink / raw)
To: Jason Wang
Cc: netdev, mkarsten, gerhard, xuanzhuo, kuba, Michael S. Tsirkin,
Eugenio Pérez, Andrew Lunn, David S. Miller, Eric Dumazet,
Paolo Abeni, open list:VIRTIO CORE AND NET DRIVERS, open list
On Wed, Feb 26, 2025 at 01:48:50PM +0800, Jason Wang wrote:
> On Tue, Feb 25, 2025 at 10:05 AM Joe Damato <jdamato@fastly.com> wrote:
> >
> > Use netif_queue_set_napi to map NAPIs to queue IDs so that the mapping
> > can be accessed by user apps, taking care to hold RTNL as needed.
>
> I may miss something but I wonder whether letting the caller hold the
> lock is better.
Hmm...
Double checking all the paths over again, here's what I see:
- refill_work, delayed work that needs RTNL so this change seems
right?
- virtnet_disable_queue_pair, called from virtnet_open and
virtnet_close. When called via NDO these are safe and hold RTNL,
but they can be called from power management and need RTNL.
- virtnet_enable_queue_pair called from virtnet_open, safe when
used via NDO but needs RTNL when used via power management.
- virtnet_rx_pause called in both paths as you mentioned, one
which needs RTNL and one which doesn't.
I think there are a couple ways to fix this:
1. Edit this patch to remove the virtnet_queue_set_napi helper,
and call netif_queue_set_napi from the napi_enable and
napi_disable helpers directly. Modify code calling into these
paths to hold rtnl (or not) as described above.
2. Modify virtnet_enable_queue_pair, virtnet_disable_queue_pair,
and virtnet_rx_pause to take a "bool need_rtnl" as an a
function argument and pass that through.
I'm not sure which is cleaner and I do not have a preference.
Can you let me know which you prefer? I am happy to implement either
one for the next revision.
[...]
> > ---
> > drivers/net/virtio_net.c | 73 ++++++++++++++++++++++++++++------------
> > 1 file changed, 52 insertions(+), 21 deletions(-)
> >
> > diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> > index e578885c1093..13bb4a563073 100644
> > --- a/drivers/net/virtio_net.c
> > +++ b/drivers/net/virtio_net.c
> > @@ -2807,6 +2807,20 @@ static void skb_recv_done(struct virtqueue *rvq)
> > virtqueue_napi_schedule(&rq->napi, rvq);
> > }
> >
> > +static void virtnet_queue_set_napi(struct net_device *dev,
> > + struct napi_struct *napi,
> > + enum netdev_queue_type q_type, int qidx,
> > + bool need_rtnl)
> > +{
> > + if (need_rtnl)
> > + rtnl_lock();
> > +
> > + netif_queue_set_napi(dev, qidx, q_type, napi);
> > +
> > + if (need_rtnl)
> > + rtnl_unlock();
> > +}
> > +
> > static void virtnet_napi_do_enable(struct virtqueue *vq,
> > struct napi_struct *napi)
> > {
> > @@ -2821,15 +2835,21 @@ static void virtnet_napi_do_enable(struct virtqueue *vq,
> > local_bh_enable();
> > }
> >
> > -static void virtnet_napi_enable(struct receive_queue *rq)
> > +static void virtnet_napi_enable(struct receive_queue *rq, bool need_rtnl)
> > {
> > + struct virtnet_info *vi = rq->vq->vdev->priv;
> > + int qidx = vq2rxq(rq->vq);
> > +
> > virtnet_napi_do_enable(rq->vq, &rq->napi);
> > + virtnet_queue_set_napi(vi->dev, &rq->napi,
> > + NETDEV_QUEUE_TYPE_RX, qidx, need_rtnl);
> > }
> >
> > -static void virtnet_napi_tx_enable(struct send_queue *sq)
> > +static void virtnet_napi_tx_enable(struct send_queue *sq, bool need_rtnl)
> > {
> > struct virtnet_info *vi = sq->vq->vdev->priv;
> > struct napi_struct *napi = &sq->napi;
> > + int qidx = vq2txq(sq->vq);
> >
> > if (!napi->weight)
> > return;
> > @@ -2843,20 +2863,31 @@ static void virtnet_napi_tx_enable(struct send_queue *sq)
> > }
> >
> > virtnet_napi_do_enable(sq->vq, napi);
> > + virtnet_queue_set_napi(vi->dev, napi, NETDEV_QUEUE_TYPE_TX, qidx,
> > + need_rtnl);
> > }
> >
> > -static void virtnet_napi_tx_disable(struct send_queue *sq)
> > +static void virtnet_napi_tx_disable(struct send_queue *sq, bool need_rtnl)
> > {
> > + struct virtnet_info *vi = sq->vq->vdev->priv;
> > struct napi_struct *napi = &sq->napi;
> > + int qidx = vq2txq(sq->vq);
> >
> > - if (napi->weight)
> > + if (napi->weight) {
> > + virtnet_queue_set_napi(vi->dev, NULL, NETDEV_QUEUE_TYPE_TX,
> > + qidx, need_rtnl);
> > napi_disable(napi);
> > + }
> > }
> >
> > -static void virtnet_napi_disable(struct receive_queue *rq)
> > +static void virtnet_napi_disable(struct receive_queue *rq, bool need_rtnl)
> > {
> > + struct virtnet_info *vi = rq->vq->vdev->priv;
> > struct napi_struct *napi = &rq->napi;
> > + int qidx = vq2rxq(rq->vq);
> >
> > + virtnet_queue_set_napi(vi->dev, NULL, NETDEV_QUEUE_TYPE_TX, qidx,
> > + need_rtnl);
> > napi_disable(napi);
> > }
> >
> > @@ -2870,9 +2901,9 @@ static void refill_work(struct work_struct *work)
> > for (i = 0; i < vi->curr_queue_pairs; i++) {
> > struct receive_queue *rq = &vi->rq[i];
> >
> > - virtnet_napi_disable(rq);
> > + virtnet_napi_disable(rq, true);
> > still_empty = !try_fill_recv(vi, rq, GFP_KERNEL);
> > - virtnet_napi_enable(rq);
> > + virtnet_napi_enable(rq, true);
> >
> > /* In theory, this can happen: if we don't get any buffers in
> > * we will *never* try to fill again.
> > @@ -3069,8 +3100,8 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
> >
> > static void virtnet_disable_queue_pair(struct virtnet_info *vi, int qp_index)
> > {
> > - virtnet_napi_tx_disable(&vi->sq[qp_index]);
> > - virtnet_napi_disable(&vi->rq[qp_index]);
> > + virtnet_napi_tx_disable(&vi->sq[qp_index], false);
> > + virtnet_napi_disable(&vi->rq[qp_index], false);
> > xdp_rxq_info_unreg(&vi->rq[qp_index].xdp_rxq);
> > }
> >
> > @@ -3089,8 +3120,8 @@ static int virtnet_enable_queue_pair(struct virtnet_info *vi, int qp_index)
> > if (err < 0)
> > goto err_xdp_reg_mem_model;
> >
> > - virtnet_napi_enable(&vi->rq[qp_index]);
> > - virtnet_napi_tx_enable(&vi->sq[qp_index]);
> > + virtnet_napi_enable(&vi->rq[qp_index], false);
> > + virtnet_napi_tx_enable(&vi->sq[qp_index], false);
> >
> > return 0;
> >
> > @@ -3342,7 +3373,7 @@ static void virtnet_rx_pause(struct virtnet_info *vi, struct receive_queue *rq)
> > bool running = netif_running(vi->dev);
> >
> > if (running) {
> > - virtnet_napi_disable(rq);
> > + virtnet_napi_disable(rq, true);
>
> During the resize, the rtnl lock has been held on the ethtool path
>
> rtnl_lock();
> rc = __dev_ethtool(net, ifr, useraddr, ethcmd, state);
> rtnl_unlock();
>
> virtnet_rx_resize()
> virtnet_rx_pause()
>
> and in the case of XSK binding, I see ASSERT_RTNL in xp_assign_dev() at least.
Thanks for catching this. I re-read all the paths and I think I've
outlined a few other issues above.
Please let me know which of the proposed methods above you'd like me
to implement to get this merged.
Thanks.
---
pw-bot: cr
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH net-next v4 3/4] virtio-net: Map NAPIs to queues
2025-02-26 18:03 ` Joe Damato
@ 2025-02-26 18:08 ` Joe Damato
2025-02-26 20:27 ` Joe Damato
2025-02-26 22:11 ` Michael S. Tsirkin
1 sibling, 1 reply; 18+ messages in thread
From: Joe Damato @ 2025-02-26 18:08 UTC (permalink / raw)
To: Jason Wang, netdev, mkarsten, gerhard, xuanzhuo, kuba,
Michael S. Tsirkin, Eugenio Pérez, Andrew Lunn,
David S. Miller, Eric Dumazet, Paolo Abeni,
open list:VIRTIO CORE AND NET DRIVERS, open list
On Wed, Feb 26, 2025 at 01:03:09PM -0500, Joe Damato wrote:
> On Wed, Feb 26, 2025 at 01:48:50PM +0800, Jason Wang wrote:
> > On Tue, Feb 25, 2025 at 10:05 AM Joe Damato <jdamato@fastly.com> wrote:
> > >
> > > Use netif_queue_set_napi to map NAPIs to queue IDs so that the mapping
> > > can be accessed by user apps, taking care to hold RTNL as needed.
> >
> > I may miss something but I wonder whether letting the caller hold the
> > lock is better.
>
> Hmm...
>
> Double checking all the paths over again, here's what I see:
> - refill_work, delayed work that needs RTNL so this change seems
> right?
>
> - virtnet_disable_queue_pair, called from virtnet_open and
> virtnet_close. When called via NDO these are safe and hold RTNL,
> but they can be called from power management and need RTNL.
>
> - virtnet_enable_queue_pair called from virtnet_open, safe when
> used via NDO but needs RTNL when used via power management.
>
> - virtnet_rx_pause called in both paths as you mentioned, one
> which needs RTNL and one which doesn't.
Sorry, I missed more paths:
- virtnet_rx_resume
- virtnet_tx_pause and virtnet_tx_resume
which are similar to path you mentioned (virtnet_rx_pause) and need
rtnl in one of two different paths.
Let me know if I missed any paths and what your preferred way to fix
this would be?
I think both options below are possible and I have no strong
preference.
>
> I think there are a couple ways to fix this:
>
> 1. Edit this patch to remove the virtnet_queue_set_napi helper,
> and call netif_queue_set_napi from the napi_enable and
> napi_disable helpers directly. Modify code calling into these
> paths to hold rtnl (or not) as described above.
>
> 2. Modify virtnet_enable_queue_pair, virtnet_disable_queue_pair,
> and virtnet_rx_pause to take a "bool need_rtnl" as an a
> function argument and pass that through.
>
> I'm not sure which is cleaner and I do not have a preference.
>
> Can you let me know which you prefer? I am happy to implement either
> one for the next revision.
>
> [...]
>
> > > ---
> > > drivers/net/virtio_net.c | 73 ++++++++++++++++++++++++++++------------
> > > 1 file changed, 52 insertions(+), 21 deletions(-)
> > >
> > > diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> > > index e578885c1093..13bb4a563073 100644
> > > --- a/drivers/net/virtio_net.c
> > > +++ b/drivers/net/virtio_net.c
> > > @@ -2807,6 +2807,20 @@ static void skb_recv_done(struct virtqueue *rvq)
> > > virtqueue_napi_schedule(&rq->napi, rvq);
> > > }
> > >
> > > +static void virtnet_queue_set_napi(struct net_device *dev,
> > > + struct napi_struct *napi,
> > > + enum netdev_queue_type q_type, int qidx,
> > > + bool need_rtnl)
> > > +{
> > > + if (need_rtnl)
> > > + rtnl_lock();
> > > +
> > > + netif_queue_set_napi(dev, qidx, q_type, napi);
> > > +
> > > + if (need_rtnl)
> > > + rtnl_unlock();
> > > +}
> > > +
> > > static void virtnet_napi_do_enable(struct virtqueue *vq,
> > > struct napi_struct *napi)
> > > {
> > > @@ -2821,15 +2835,21 @@ static void virtnet_napi_do_enable(struct virtqueue *vq,
> > > local_bh_enable();
> > > }
> > >
> > > -static void virtnet_napi_enable(struct receive_queue *rq)
> > > +static void virtnet_napi_enable(struct receive_queue *rq, bool need_rtnl)
> > > {
> > > + struct virtnet_info *vi = rq->vq->vdev->priv;
> > > + int qidx = vq2rxq(rq->vq);
> > > +
> > > virtnet_napi_do_enable(rq->vq, &rq->napi);
> > > + virtnet_queue_set_napi(vi->dev, &rq->napi,
> > > + NETDEV_QUEUE_TYPE_RX, qidx, need_rtnl);
> > > }
> > >
> > > -static void virtnet_napi_tx_enable(struct send_queue *sq)
> > > +static void virtnet_napi_tx_enable(struct send_queue *sq, bool need_rtnl)
> > > {
> > > struct virtnet_info *vi = sq->vq->vdev->priv;
> > > struct napi_struct *napi = &sq->napi;
> > > + int qidx = vq2txq(sq->vq);
> > >
> > > if (!napi->weight)
> > > return;
> > > @@ -2843,20 +2863,31 @@ static void virtnet_napi_tx_enable(struct send_queue *sq)
> > > }
> > >
> > > virtnet_napi_do_enable(sq->vq, napi);
> > > + virtnet_queue_set_napi(vi->dev, napi, NETDEV_QUEUE_TYPE_TX, qidx,
> > > + need_rtnl);
> > > }
> > >
> > > -static void virtnet_napi_tx_disable(struct send_queue *sq)
> > > +static void virtnet_napi_tx_disable(struct send_queue *sq, bool need_rtnl)
> > > {
> > > + struct virtnet_info *vi = sq->vq->vdev->priv;
> > > struct napi_struct *napi = &sq->napi;
> > > + int qidx = vq2txq(sq->vq);
> > >
> > > - if (napi->weight)
> > > + if (napi->weight) {
> > > + virtnet_queue_set_napi(vi->dev, NULL, NETDEV_QUEUE_TYPE_TX,
> > > + qidx, need_rtnl);
> > > napi_disable(napi);
> > > + }
> > > }
> > >
> > > -static void virtnet_napi_disable(struct receive_queue *rq)
> > > +static void virtnet_napi_disable(struct receive_queue *rq, bool need_rtnl)
> > > {
> > > + struct virtnet_info *vi = rq->vq->vdev->priv;
> > > struct napi_struct *napi = &rq->napi;
> > > + int qidx = vq2rxq(rq->vq);
> > >
> > > + virtnet_queue_set_napi(vi->dev, NULL, NETDEV_QUEUE_TYPE_TX, qidx,
> > > + need_rtnl);
> > > napi_disable(napi);
> > > }
> > >
> > > @@ -2870,9 +2901,9 @@ static void refill_work(struct work_struct *work)
> > > for (i = 0; i < vi->curr_queue_pairs; i++) {
> > > struct receive_queue *rq = &vi->rq[i];
> > >
> > > - virtnet_napi_disable(rq);
> > > + virtnet_napi_disable(rq, true);
> > > still_empty = !try_fill_recv(vi, rq, GFP_KERNEL);
> > > - virtnet_napi_enable(rq);
> > > + virtnet_napi_enable(rq, true);
> > >
> > > /* In theory, this can happen: if we don't get any buffers in
> > > * we will *never* try to fill again.
> > > @@ -3069,8 +3100,8 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
> > >
> > > static void virtnet_disable_queue_pair(struct virtnet_info *vi, int qp_index)
> > > {
> > > - virtnet_napi_tx_disable(&vi->sq[qp_index]);
> > > - virtnet_napi_disable(&vi->rq[qp_index]);
> > > + virtnet_napi_tx_disable(&vi->sq[qp_index], false);
> > > + virtnet_napi_disable(&vi->rq[qp_index], false);
> > > xdp_rxq_info_unreg(&vi->rq[qp_index].xdp_rxq);
> > > }
> > >
> > > @@ -3089,8 +3120,8 @@ static int virtnet_enable_queue_pair(struct virtnet_info *vi, int qp_index)
> > > if (err < 0)
> > > goto err_xdp_reg_mem_model;
> > >
> > > - virtnet_napi_enable(&vi->rq[qp_index]);
> > > - virtnet_napi_tx_enable(&vi->sq[qp_index]);
> > > + virtnet_napi_enable(&vi->rq[qp_index], false);
> > > + virtnet_napi_tx_enable(&vi->sq[qp_index], false);
> > >
> > > return 0;
> > >
> > > @@ -3342,7 +3373,7 @@ static void virtnet_rx_pause(struct virtnet_info *vi, struct receive_queue *rq)
> > > bool running = netif_running(vi->dev);
> > >
> > > if (running) {
> > > - virtnet_napi_disable(rq);
> > > + virtnet_napi_disable(rq, true);
> >
> > During the resize, the rtnl lock has been held on the ethtool path
> >
> > rtnl_lock();
> > rc = __dev_ethtool(net, ifr, useraddr, ethcmd, state);
> > rtnl_unlock();
> >
> > virtnet_rx_resize()
> > virtnet_rx_pause()
> >
> > and in the case of XSK binding, I see ASSERT_RTNL in xp_assign_dev() at least.
>
> Thanks for catching this. I re-read all the paths and I think I've
> outlined a few other issues above.
>
> Please let me know which of the proposed methods above you'd like me
> to implement to get this merged.
>
> Thanks.
>
> ---
> pw-bot: cr
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH net-next v4 3/4] virtio-net: Map NAPIs to queues
2025-02-26 18:08 ` Joe Damato
@ 2025-02-26 20:27 ` Joe Damato
2025-02-26 22:13 ` Michael S. Tsirkin
0 siblings, 1 reply; 18+ messages in thread
From: Joe Damato @ 2025-02-26 20:27 UTC (permalink / raw)
To: Jason Wang, netdev, mkarsten, gerhard, xuanzhuo, kuba,
Michael S. Tsirkin, Eugenio Pérez, Andrew Lunn,
David S. Miller, Eric Dumazet, Paolo Abeni,
open list:VIRTIO CORE AND NET DRIVERS, open list
On Wed, Feb 26, 2025 at 01:08:49PM -0500, Joe Damato wrote:
> On Wed, Feb 26, 2025 at 01:03:09PM -0500, Joe Damato wrote:
> > On Wed, Feb 26, 2025 at 01:48:50PM +0800, Jason Wang wrote:
> > > On Tue, Feb 25, 2025 at 10:05 AM Joe Damato <jdamato@fastly.com> wrote:
> > > >
> > > > Use netif_queue_set_napi to map NAPIs to queue IDs so that the mapping
> > > > can be accessed by user apps, taking care to hold RTNL as needed.
> > >
> > > I may miss something but I wonder whether letting the caller hold the
> > > lock is better.
> >
> > Hmm...
> >
> > Double checking all the paths over again, here's what I see:
> > - refill_work, delayed work that needs RTNL so this change seems
> > right?
> >
> > - virtnet_disable_queue_pair, called from virtnet_open and
> > virtnet_close. When called via NDO these are safe and hold RTNL,
> > but they can be called from power management and need RTNL.
> >
> > - virtnet_enable_queue_pair called from virtnet_open, safe when
> > used via NDO but needs RTNL when used via power management.
> >
> > - virtnet_rx_pause called in both paths as you mentioned, one
> > which needs RTNL and one which doesn't.
>
> Sorry, I missed more paths:
>
> - virtnet_rx_resume
> - virtnet_tx_pause and virtnet_tx_resume
>
> which are similar to path you mentioned (virtnet_rx_pause) and need
> rtnl in one of two different paths.
>
> Let me know if I missed any paths and what your preferred way to fix
> this would be?
>
> I think both options below are possible and I have no strong
> preference.
OK, my apologies. I read your message and the code wrong. Sorry for
the back-to-back emails from me.
Please ignore my message above... I think after re-reading the code,
here's where I've arrived:
- refill_work needs to hold RTNL (as in the existing patch)
- virtnet_rx_pause, virtnet_rx_resume, virtnet_tx_pause,
virtnet_tx_resume -- all do NOT need to hold RTNL because it is
already held in the ethtool resize path and the XSK path, as you
explained, but I mis-read (sorry).
- virtnet_disable_queue_pair and virtnet_enable_queue_pair both
need to hold RTNL only when called via power management, but not
when called via ndo_open or ndo_close
Is my understanding correct and does it match your understanding?
If so, that means there are two issues:
1. Fixing the hardcoded bools in rx_pause, rx_resume, tx_pause,
tx_resume (all should be false, RTNL is not needed).
2. Handling the power management case which calls virtnet_open and
virtnet_close.
I made a small diff included below as an example of a possible
solution:
1. Modify virtnet_disable_queue_pair and virtnet_enable_queue_pair
to take a "bool need_rtnl" and pass it through to the helpers
they call.
2. Create two helpers, virtnet_do_open and virt_do_close both of
which take struct net_device *dev, bool need_rtnl. virtnet_open
and virtnet_close are modified to call the helpers and pass
false for need_rtnl. The power management paths call the
helpers and pass true for need_rtnl. (fixes issue 2 above)
3. Fix the bools for rx_pause, rx_resume, tx_pause, tx_resume to
pass false since all paths that I could find that lead to these
functions hold RTNL. (fixes issue 1 above)
See the diff below (which can be applied on top of patch 3) to see
what it looks like.
If you are OK with this approach, I will send a v5 where patch 3
includes the changes shown in this diff.
Please let me know what you think:
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 13bb4a563073..76ecb8f3ce9a 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -3098,14 +3098,16 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
return received;
}
-static void virtnet_disable_queue_pair(struct virtnet_info *vi, int qp_index)
+static void virtnet_disable_queue_pair(struct virtnet_info *vi, int qp_index,
+ bool need_rtnl)
{
- virtnet_napi_tx_disable(&vi->sq[qp_index], false);
- virtnet_napi_disable(&vi->rq[qp_index], false);
+ virtnet_napi_tx_disable(&vi->sq[qp_index], need_rtnl);
+ virtnet_napi_disable(&vi->rq[qp_index], need_rtnl);
xdp_rxq_info_unreg(&vi->rq[qp_index].xdp_rxq);
}
-static int virtnet_enable_queue_pair(struct virtnet_info *vi, int qp_index)
+static int virtnet_enable_queue_pair(struct virtnet_info *vi, int qp_index,
+ bool need_rtnl)
{
struct net_device *dev = vi->dev;
int err;
@@ -3120,8 +3122,8 @@ static int virtnet_enable_queue_pair(struct virtnet_info *vi, int qp_index)
if (err < 0)
goto err_xdp_reg_mem_model;
- virtnet_napi_enable(&vi->rq[qp_index], false);
- virtnet_napi_tx_enable(&vi->sq[qp_index], false);
+ virtnet_napi_enable(&vi->rq[qp_index], need_rtnl);
+ virtnet_napi_tx_enable(&vi->sq[qp_index], need_rtnl);
return 0;
@@ -3156,7 +3158,7 @@ static void virtnet_update_settings(struct virtnet_info *vi)
vi->duplex = duplex;
}
-static int virtnet_open(struct net_device *dev)
+static int virtnet_do_open(struct net_device *dev, bool need_rtnl)
{
struct virtnet_info *vi = netdev_priv(dev);
int i, err;
@@ -3169,7 +3171,7 @@ static int virtnet_open(struct net_device *dev)
if (!try_fill_recv(vi, &vi->rq[i], GFP_KERNEL))
schedule_delayed_work(&vi->refill, 0);
- err = virtnet_enable_queue_pair(vi, i);
+ err = virtnet_enable_queue_pair(vi, i, need_rtnl);
if (err < 0)
goto err_enable_qp;
}
@@ -3190,13 +3192,18 @@ static int virtnet_open(struct net_device *dev)
cancel_delayed_work_sync(&vi->refill);
for (i--; i >= 0; i--) {
- virtnet_disable_queue_pair(vi, i);
+ virtnet_disable_queue_pair(vi, i, need_rtnl);
virtnet_cancel_dim(vi, &vi->rq[i].dim);
}
return err;
}
+static int virtnet_open(struct net_device *dev)
+{
+ return virtnet_do_open(dev, false);
+}
+
static int virtnet_poll_tx(struct napi_struct *napi, int budget)
{
struct send_queue *sq = container_of(napi, struct send_queue, napi);
@@ -3373,7 +3380,7 @@ static void virtnet_rx_pause(struct virtnet_info *vi, struct receive_queue *rq)
bool running = netif_running(vi->dev);
if (running) {
- virtnet_napi_disable(rq, true);
+ virtnet_napi_disable(rq, false);
virtnet_cancel_dim(vi, &rq->dim);
}
}
@@ -3386,7 +3393,7 @@ static void virtnet_rx_resume(struct virtnet_info *vi, struct receive_queue *rq)
schedule_delayed_work(&vi->refill, 0);
if (running)
- virtnet_napi_enable(rq, true);
+ virtnet_napi_enable(rq, false);
}
static int virtnet_rx_resize(struct virtnet_info *vi,
@@ -3415,7 +3422,7 @@ static void virtnet_tx_pause(struct virtnet_info *vi, struct send_queue *sq)
qindex = sq - vi->sq;
if (running)
- virtnet_napi_tx_disable(sq, true);
+ virtnet_napi_tx_disable(sq, false);
txq = netdev_get_tx_queue(vi->dev, qindex);
@@ -3449,7 +3456,7 @@ static void virtnet_tx_resume(struct virtnet_info *vi, struct send_queue *sq)
__netif_tx_unlock_bh(txq);
if (running)
- virtnet_napi_tx_enable(sq, true);
+ virtnet_napi_tx_enable(sq, false);
}
static int virtnet_tx_resize(struct virtnet_info *vi, struct send_queue *sq,
@@ -3708,7 +3715,7 @@ static int virtnet_set_queues(struct virtnet_info *vi, u16 queue_pairs)
return 0;
}
-static int virtnet_close(struct net_device *dev)
+static int virtnet_do_close(struct net_device *dev, bool need_rtnl)
{
struct virtnet_info *vi = netdev_priv(dev);
int i;
@@ -3727,7 +3734,7 @@ static int virtnet_close(struct net_device *dev)
cancel_work_sync(&vi->config_work);
for (i = 0; i < vi->max_queue_pairs; i++) {
- virtnet_disable_queue_pair(vi, i);
+ virtnet_disable_queue_pair(vi, i, need_rtnl);
virtnet_cancel_dim(vi, &vi->rq[i].dim);
}
@@ -3736,6 +3743,11 @@ static int virtnet_close(struct net_device *dev)
return 0;
}
+static int virtnet_close(struct net_device *dev)
+{
+ return virtnet_do_close(dev, false);
+}
+
static void virtnet_rx_mode_work(struct work_struct *work)
{
struct virtnet_info *vi =
@@ -5682,7 +5694,7 @@ static void virtnet_freeze_down(struct virtio_device *vdev)
netif_device_detach(vi->dev);
netif_tx_unlock_bh(vi->dev);
if (netif_running(vi->dev))
- virtnet_close(vi->dev);
+ virtnet_do_close(vi->dev, true);
}
static int init_vqs(struct virtnet_info *vi);
@@ -5702,7 +5714,7 @@ static int virtnet_restore_up(struct virtio_device *vdev)
enable_rx_mode_work(vi);
if (netif_running(vi->dev)) {
- err = virtnet_open(vi->dev);
+ err = virtnet_do_open(vi->dev, false);
if (err)
return err;
}
^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH net-next v4 3/4] virtio-net: Map NAPIs to queues
2025-02-26 18:03 ` Joe Damato
2025-02-26 18:08 ` Joe Damato
@ 2025-02-26 22:11 ` Michael S. Tsirkin
1 sibling, 0 replies; 18+ messages in thread
From: Michael S. Tsirkin @ 2025-02-26 22:11 UTC (permalink / raw)
To: Joe Damato, Jason Wang, netdev, mkarsten, gerhard, xuanzhuo, kuba,
Eugenio Pérez, Andrew Lunn, David S. Miller, Eric Dumazet,
Paolo Abeni, open list:VIRTIO CORE AND NET DRIVERS, open list
On Wed, Feb 26, 2025 at 01:03:09PM -0500, Joe Damato wrote:
> On Wed, Feb 26, 2025 at 01:48:50PM +0800, Jason Wang wrote:
> > On Tue, Feb 25, 2025 at 10:05 AM Joe Damato <jdamato@fastly.com> wrote:
> > >
> > > Use netif_queue_set_napi to map NAPIs to queue IDs so that the mapping
> > > can be accessed by user apps, taking care to hold RTNL as needed.
> >
> > I may miss something but I wonder whether letting the caller hold the
> > lock is better.
>
> Hmm...
>
> Double checking all the paths over again, here's what I see:
> - refill_work, delayed work that needs RTNL so this change seems
> right?
>
> - virtnet_disable_queue_pair, called from virtnet_open and
> virtnet_close. When called via NDO these are safe and hold RTNL,
> but they can be called from power management and need RTNL.
>
> - virtnet_enable_queue_pair called from virtnet_open, safe when
> used via NDO but needs RTNL when used via power management.
>
> - virtnet_rx_pause called in both paths as you mentioned, one
> which needs RTNL and one which doesn't.
>
> I think there are a couple ways to fix this:
>
> 1. Edit this patch to remove the virtnet_queue_set_napi helper,
> and call netif_queue_set_napi from the napi_enable and
> napi_disable helpers directly. Modify code calling into these
> paths to hold rtnl (or not) as described above.
>
> 2. Modify virtnet_enable_queue_pair, virtnet_disable_queue_pair,
> and virtnet_rx_pause to take a "bool need_rtnl" as an a
> function argument and pass that through.
>
> I'm not sure which is cleaner and I do not have a preference.
>
> Can you let me know which you prefer? I am happy to implement either
> one for the next revision.
1 seems cleaner.
taking locks depending on paths is confusing
> [...]
>
> > > ---
> > > drivers/net/virtio_net.c | 73 ++++++++++++++++++++++++++++------------
> > > 1 file changed, 52 insertions(+), 21 deletions(-)
> > >
> > > diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> > > index e578885c1093..13bb4a563073 100644
> > > --- a/drivers/net/virtio_net.c
> > > +++ b/drivers/net/virtio_net.c
> > > @@ -2807,6 +2807,20 @@ static void skb_recv_done(struct virtqueue *rvq)
> > > virtqueue_napi_schedule(&rq->napi, rvq);
> > > }
> > >
> > > +static void virtnet_queue_set_napi(struct net_device *dev,
> > > + struct napi_struct *napi,
> > > + enum netdev_queue_type q_type, int qidx,
> > > + bool need_rtnl)
> > > +{
> > > + if (need_rtnl)
> > > + rtnl_lock();
> > > +
> > > + netif_queue_set_napi(dev, qidx, q_type, napi);
> > > +
> > > + if (need_rtnl)
> > > + rtnl_unlock();
> > > +}
> > > +
> > > static void virtnet_napi_do_enable(struct virtqueue *vq,
> > > struct napi_struct *napi)
> > > {
> > > @@ -2821,15 +2835,21 @@ static void virtnet_napi_do_enable(struct virtqueue *vq,
> > > local_bh_enable();
> > > }
> > >
> > > -static void virtnet_napi_enable(struct receive_queue *rq)
> > > +static void virtnet_napi_enable(struct receive_queue *rq, bool need_rtnl)
> > > {
> > > + struct virtnet_info *vi = rq->vq->vdev->priv;
> > > + int qidx = vq2rxq(rq->vq);
> > > +
> > > virtnet_napi_do_enable(rq->vq, &rq->napi);
> > > + virtnet_queue_set_napi(vi->dev, &rq->napi,
> > > + NETDEV_QUEUE_TYPE_RX, qidx, need_rtnl);
> > > }
> > >
> > > -static void virtnet_napi_tx_enable(struct send_queue *sq)
> > > +static void virtnet_napi_tx_enable(struct send_queue *sq, bool need_rtnl)
> > > {
> > > struct virtnet_info *vi = sq->vq->vdev->priv;
> > > struct napi_struct *napi = &sq->napi;
> > > + int qidx = vq2txq(sq->vq);
> > >
> > > if (!napi->weight)
> > > return;
> > > @@ -2843,20 +2863,31 @@ static void virtnet_napi_tx_enable(struct send_queue *sq)
> > > }
> > >
> > > virtnet_napi_do_enable(sq->vq, napi);
> > > + virtnet_queue_set_napi(vi->dev, napi, NETDEV_QUEUE_TYPE_TX, qidx,
> > > + need_rtnl);
> > > }
> > >
> > > -static void virtnet_napi_tx_disable(struct send_queue *sq)
> > > +static void virtnet_napi_tx_disable(struct send_queue *sq, bool need_rtnl)
> > > {
> > > + struct virtnet_info *vi = sq->vq->vdev->priv;
> > > struct napi_struct *napi = &sq->napi;
> > > + int qidx = vq2txq(sq->vq);
> > >
> > > - if (napi->weight)
> > > + if (napi->weight) {
> > > + virtnet_queue_set_napi(vi->dev, NULL, NETDEV_QUEUE_TYPE_TX,
> > > + qidx, need_rtnl);
> > > napi_disable(napi);
> > > + }
> > > }
> > >
> > > -static void virtnet_napi_disable(struct receive_queue *rq)
> > > +static void virtnet_napi_disable(struct receive_queue *rq, bool need_rtnl)
> > > {
> > > + struct virtnet_info *vi = rq->vq->vdev->priv;
> > > struct napi_struct *napi = &rq->napi;
> > > + int qidx = vq2rxq(rq->vq);
> > >
> > > + virtnet_queue_set_napi(vi->dev, NULL, NETDEV_QUEUE_TYPE_TX, qidx,
> > > + need_rtnl);
> > > napi_disable(napi);
> > > }
> > >
> > > @@ -2870,9 +2901,9 @@ static void refill_work(struct work_struct *work)
> > > for (i = 0; i < vi->curr_queue_pairs; i++) {
> > > struct receive_queue *rq = &vi->rq[i];
> > >
> > > - virtnet_napi_disable(rq);
> > > + virtnet_napi_disable(rq, true);
> > > still_empty = !try_fill_recv(vi, rq, GFP_KERNEL);
> > > - virtnet_napi_enable(rq);
> > > + virtnet_napi_enable(rq, true);
> > >
> > > /* In theory, this can happen: if we don't get any buffers in
> > > * we will *never* try to fill again.
> > > @@ -3069,8 +3100,8 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
> > >
> > > static void virtnet_disable_queue_pair(struct virtnet_info *vi, int qp_index)
> > > {
> > > - virtnet_napi_tx_disable(&vi->sq[qp_index]);
> > > - virtnet_napi_disable(&vi->rq[qp_index]);
> > > + virtnet_napi_tx_disable(&vi->sq[qp_index], false);
> > > + virtnet_napi_disable(&vi->rq[qp_index], false);
> > > xdp_rxq_info_unreg(&vi->rq[qp_index].xdp_rxq);
> > > }
> > >
> > > @@ -3089,8 +3120,8 @@ static int virtnet_enable_queue_pair(struct virtnet_info *vi, int qp_index)
> > > if (err < 0)
> > > goto err_xdp_reg_mem_model;
> > >
> > > - virtnet_napi_enable(&vi->rq[qp_index]);
> > > - virtnet_napi_tx_enable(&vi->sq[qp_index]);
> > > + virtnet_napi_enable(&vi->rq[qp_index], false);
> > > + virtnet_napi_tx_enable(&vi->sq[qp_index], false);
> > >
> > > return 0;
> > >
> > > @@ -3342,7 +3373,7 @@ static void virtnet_rx_pause(struct virtnet_info *vi, struct receive_queue *rq)
> > > bool running = netif_running(vi->dev);
> > >
> > > if (running) {
> > > - virtnet_napi_disable(rq);
> > > + virtnet_napi_disable(rq, true);
> >
> > During the resize, the rtnl lock has been held on the ethtool path
> >
> > rtnl_lock();
> > rc = __dev_ethtool(net, ifr, useraddr, ethcmd, state);
> > rtnl_unlock();
> >
> > virtnet_rx_resize()
> > virtnet_rx_pause()
> >
> > and in the case of XSK binding, I see ASSERT_RTNL in xp_assign_dev() at least.
>
> Thanks for catching this. I re-read all the paths and I think I've
> outlined a few other issues above.
>
> Please let me know which of the proposed methods above you'd like me
> to implement to get this merged.
>
> Thanks.
>
> ---
> pw-bot: cr
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH net-next v4 3/4] virtio-net: Map NAPIs to queues
2025-02-26 20:27 ` Joe Damato
@ 2025-02-26 22:13 ` Michael S. Tsirkin
2025-02-27 4:18 ` Jason Wang
0 siblings, 1 reply; 18+ messages in thread
From: Michael S. Tsirkin @ 2025-02-26 22:13 UTC (permalink / raw)
To: Joe Damato, Jason Wang, netdev, mkarsten, gerhard, xuanzhuo, kuba,
Eugenio Pérez, Andrew Lunn, David S. Miller, Eric Dumazet,
Paolo Abeni, open list:VIRTIO CORE AND NET DRIVERS, open list
On Wed, Feb 26, 2025 at 03:27:42PM -0500, Joe Damato wrote:
> On Wed, Feb 26, 2025 at 01:08:49PM -0500, Joe Damato wrote:
> > On Wed, Feb 26, 2025 at 01:03:09PM -0500, Joe Damato wrote:
> > > On Wed, Feb 26, 2025 at 01:48:50PM +0800, Jason Wang wrote:
> > > > On Tue, Feb 25, 2025 at 10:05 AM Joe Damato <jdamato@fastly.com> wrote:
> > > > >
> > > > > Use netif_queue_set_napi to map NAPIs to queue IDs so that the mapping
> > > > > can be accessed by user apps, taking care to hold RTNL as needed.
> > > >
> > > > I may miss something but I wonder whether letting the caller hold the
> > > > lock is better.
> > >
> > > Hmm...
> > >
> > > Double checking all the paths over again, here's what I see:
> > > - refill_work, delayed work that needs RTNL so this change seems
> > > right?
> > >
> > > - virtnet_disable_queue_pair, called from virtnet_open and
> > > virtnet_close. When called via NDO these are safe and hold RTNL,
> > > but they can be called from power management and need RTNL.
> > >
> > > - virtnet_enable_queue_pair called from virtnet_open, safe when
> > > used via NDO but needs RTNL when used via power management.
> > >
> > > - virtnet_rx_pause called in both paths as you mentioned, one
> > > which needs RTNL and one which doesn't.
> >
> > Sorry, I missed more paths:
> >
> > - virtnet_rx_resume
> > - virtnet_tx_pause and virtnet_tx_resume
> >
> > which are similar to path you mentioned (virtnet_rx_pause) and need
> > rtnl in one of two different paths.
> >
> > Let me know if I missed any paths and what your preferred way to fix
> > this would be?
> >
> > I think both options below are possible and I have no strong
> > preference.
>
> OK, my apologies. I read your message and the code wrong. Sorry for
> the back-to-back emails from me.
>
> Please ignore my message above... I think after re-reading the code,
> here's where I've arrived:
>
> - refill_work needs to hold RTNL (as in the existing patch)
>
> - virtnet_rx_pause, virtnet_rx_resume, virtnet_tx_pause,
> virtnet_tx_resume -- all do NOT need to hold RTNL because it is
> already held in the ethtool resize path and the XSK path, as you
> explained, but I mis-read (sorry).
>
> - virtnet_disable_queue_pair and virtnet_enable_queue_pair both
> need to hold RTNL only when called via power management, but not
> when called via ndo_open or ndo_close
>
> Is my understanding correct and does it match your understanding?
>
> If so, that means there are two issues:
>
> 1. Fixing the hardcoded bools in rx_pause, rx_resume, tx_pause,
> tx_resume (all should be false, RTNL is not needed).
>
> 2. Handling the power management case which calls virtnet_open and
> virtnet_close.
>
> I made a small diff included below as an example of a possible
> solution:
>
> 1. Modify virtnet_disable_queue_pair and virtnet_enable_queue_pair
> to take a "bool need_rtnl" and pass it through to the helpers
> they call.
>
> 2. Create two helpers, virtnet_do_open and virt_do_close both of
> which take struct net_device *dev, bool need_rtnl. virtnet_open
> and virtnet_close are modified to call the helpers and pass
> false for need_rtnl. The power management paths call the
> helpers and pass true for need_rtnl. (fixes issue 2 above)
>
> 3. Fix the bools for rx_pause, rx_resume, tx_pause, tx_resume to
> pass false since all paths that I could find that lead to these
> functions hold RTNL. (fixes issue 1 above)
>
> See the diff below (which can be applied on top of patch 3) to see
> what it looks like.
>
> If you are OK with this approach, I will send a v5 where patch 3
> includes the changes shown in this diff.
>
> Please let me know what you think:
Looks ok I think.
> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> index 13bb4a563073..76ecb8f3ce9a 100644
> --- a/drivers/net/virtio_net.c
> +++ b/drivers/net/virtio_net.c
> @@ -3098,14 +3098,16 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
> return received;
> }
>
> -static void virtnet_disable_queue_pair(struct virtnet_info *vi, int qp_index)
> +static void virtnet_disable_queue_pair(struct virtnet_info *vi, int qp_index,
> + bool need_rtnl)
> {
> - virtnet_napi_tx_disable(&vi->sq[qp_index], false);
> - virtnet_napi_disable(&vi->rq[qp_index], false);
> + virtnet_napi_tx_disable(&vi->sq[qp_index], need_rtnl);
> + virtnet_napi_disable(&vi->rq[qp_index], need_rtnl);
> xdp_rxq_info_unreg(&vi->rq[qp_index].xdp_rxq);
> }
>
> -static int virtnet_enable_queue_pair(struct virtnet_info *vi, int qp_index)
> +static int virtnet_enable_queue_pair(struct virtnet_info *vi, int qp_index,
> + bool need_rtnl)
> {
> struct net_device *dev = vi->dev;
> int err;
> @@ -3120,8 +3122,8 @@ static int virtnet_enable_queue_pair(struct virtnet_info *vi, int qp_index)
> if (err < 0)
> goto err_xdp_reg_mem_model;
>
> - virtnet_napi_enable(&vi->rq[qp_index], false);
> - virtnet_napi_tx_enable(&vi->sq[qp_index], false);
> + virtnet_napi_enable(&vi->rq[qp_index], need_rtnl);
> + virtnet_napi_tx_enable(&vi->sq[qp_index], need_rtnl);
>
> return 0;
>
> @@ -3156,7 +3158,7 @@ static void virtnet_update_settings(struct virtnet_info *vi)
> vi->duplex = duplex;
> }
>
> -static int virtnet_open(struct net_device *dev)
> +static int virtnet_do_open(struct net_device *dev, bool need_rtnl)
> {
> struct virtnet_info *vi = netdev_priv(dev);
> int i, err;
> @@ -3169,7 +3171,7 @@ static int virtnet_open(struct net_device *dev)
> if (!try_fill_recv(vi, &vi->rq[i], GFP_KERNEL))
> schedule_delayed_work(&vi->refill, 0);
>
> - err = virtnet_enable_queue_pair(vi, i);
> + err = virtnet_enable_queue_pair(vi, i, need_rtnl);
> if (err < 0)
> goto err_enable_qp;
> }
> @@ -3190,13 +3192,18 @@ static int virtnet_open(struct net_device *dev)
> cancel_delayed_work_sync(&vi->refill);
>
> for (i--; i >= 0; i--) {
> - virtnet_disable_queue_pair(vi, i);
> + virtnet_disable_queue_pair(vi, i, need_rtnl);
> virtnet_cancel_dim(vi, &vi->rq[i].dim);
> }
>
> return err;
> }
>
> +static int virtnet_open(struct net_device *dev)
> +{
> + return virtnet_do_open(dev, false);
> +}
> +
> static int virtnet_poll_tx(struct napi_struct *napi, int budget)
> {
> struct send_queue *sq = container_of(napi, struct send_queue, napi);
> @@ -3373,7 +3380,7 @@ static void virtnet_rx_pause(struct virtnet_info *vi, struct receive_queue *rq)
> bool running = netif_running(vi->dev);
>
> if (running) {
> - virtnet_napi_disable(rq, true);
> + virtnet_napi_disable(rq, false);
> virtnet_cancel_dim(vi, &rq->dim);
> }
> }
> @@ -3386,7 +3393,7 @@ static void virtnet_rx_resume(struct virtnet_info *vi, struct receive_queue *rq)
> schedule_delayed_work(&vi->refill, 0);
>
> if (running)
> - virtnet_napi_enable(rq, true);
> + virtnet_napi_enable(rq, false);
> }
>
> static int virtnet_rx_resize(struct virtnet_info *vi,
> @@ -3415,7 +3422,7 @@ static void virtnet_tx_pause(struct virtnet_info *vi, struct send_queue *sq)
> qindex = sq - vi->sq;
>
> if (running)
> - virtnet_napi_tx_disable(sq, true);
> + virtnet_napi_tx_disable(sq, false);
>
> txq = netdev_get_tx_queue(vi->dev, qindex);
>
> @@ -3449,7 +3456,7 @@ static void virtnet_tx_resume(struct virtnet_info *vi, struct send_queue *sq)
> __netif_tx_unlock_bh(txq);
>
> if (running)
> - virtnet_napi_tx_enable(sq, true);
> + virtnet_napi_tx_enable(sq, false);
> }
>
> static int virtnet_tx_resize(struct virtnet_info *vi, struct send_queue *sq,
> @@ -3708,7 +3715,7 @@ static int virtnet_set_queues(struct virtnet_info *vi, u16 queue_pairs)
> return 0;
> }
>
> -static int virtnet_close(struct net_device *dev)
> +static int virtnet_do_close(struct net_device *dev, bool need_rtnl)
> {
> struct virtnet_info *vi = netdev_priv(dev);
> int i;
> @@ -3727,7 +3734,7 @@ static int virtnet_close(struct net_device *dev)
> cancel_work_sync(&vi->config_work);
>
> for (i = 0; i < vi->max_queue_pairs; i++) {
> - virtnet_disable_queue_pair(vi, i);
> + virtnet_disable_queue_pair(vi, i, need_rtnl);
> virtnet_cancel_dim(vi, &vi->rq[i].dim);
> }
>
> @@ -3736,6 +3743,11 @@ static int virtnet_close(struct net_device *dev)
> return 0;
> }
>
> +static int virtnet_close(struct net_device *dev)
> +{
> + return virtnet_do_close(dev, false);
> +}
> +
> static void virtnet_rx_mode_work(struct work_struct *work)
> {
> struct virtnet_info *vi =
> @@ -5682,7 +5694,7 @@ static void virtnet_freeze_down(struct virtio_device *vdev)
> netif_device_detach(vi->dev);
> netif_tx_unlock_bh(vi->dev);
> if (netif_running(vi->dev))
> - virtnet_close(vi->dev);
> + virtnet_do_close(vi->dev, true);
> }
>
> static int init_vqs(struct virtnet_info *vi);
> @@ -5702,7 +5714,7 @@ static int virtnet_restore_up(struct virtio_device *vdev)
> enable_rx_mode_work(vi);
>
> if (netif_running(vi->dev)) {
> - err = virtnet_open(vi->dev);
> + err = virtnet_do_open(vi->dev, false);
> if (err)
> return err;
> }
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH net-next v4 3/4] virtio-net: Map NAPIs to queues
2025-02-26 22:13 ` Michael S. Tsirkin
@ 2025-02-27 4:18 ` Jason Wang
2025-02-27 4:48 ` Joe Damato
0 siblings, 1 reply; 18+ messages in thread
From: Jason Wang @ 2025-02-27 4:18 UTC (permalink / raw)
To: Michael S. Tsirkin
Cc: Joe Damato, netdev, mkarsten, gerhard, xuanzhuo, kuba,
Eugenio Pérez, Andrew Lunn, David S. Miller, Eric Dumazet,
Paolo Abeni, open list:VIRTIO CORE AND NET DRIVERS, open list
On Thu, Feb 27, 2025 at 6:13 AM Michael S. Tsirkin <mst@redhat.com> wrote:
>
> On Wed, Feb 26, 2025 at 03:27:42PM -0500, Joe Damato wrote:
> > On Wed, Feb 26, 2025 at 01:08:49PM -0500, Joe Damato wrote:
> > > On Wed, Feb 26, 2025 at 01:03:09PM -0500, Joe Damato wrote:
> > > > On Wed, Feb 26, 2025 at 01:48:50PM +0800, Jason Wang wrote:
> > > > > On Tue, Feb 25, 2025 at 10:05 AM Joe Damato <jdamato@fastly.com> wrote:
> > > > > >
> > > > > > Use netif_queue_set_napi to map NAPIs to queue IDs so that the mapping
> > > > > > can be accessed by user apps, taking care to hold RTNL as needed.
> > > > >
> > > > > I may miss something but I wonder whether letting the caller hold the
> > > > > lock is better.
> > > >
> > > > Hmm...
> > > >
> > > > Double checking all the paths over again, here's what I see:
> > > > - refill_work, delayed work that needs RTNL so this change seems
> > > > right?
> > > >
> > > > - virtnet_disable_queue_pair, called from virtnet_open and
> > > > virtnet_close. When called via NDO these are safe and hold RTNL,
> > > > but they can be called from power management and need RTNL.
> > > >
> > > > - virtnet_enable_queue_pair called from virtnet_open, safe when
> > > > used via NDO but needs RTNL when used via power management.
> > > >
> > > > - virtnet_rx_pause called in both paths as you mentioned, one
> > > > which needs RTNL and one which doesn't.
> > >
> > > Sorry, I missed more paths:
> > >
> > > - virtnet_rx_resume
> > > - virtnet_tx_pause and virtnet_tx_resume
> > >
> > > which are similar to path you mentioned (virtnet_rx_pause) and need
> > > rtnl in one of two different paths.
> > >
> > > Let me know if I missed any paths and what your preferred way to fix
> > > this would be?
> > >
> > > I think both options below are possible and I have no strong
> > > preference.
> >
> > OK, my apologies. I read your message and the code wrong. Sorry for
> > the back-to-back emails from me.
> >
> > Please ignore my message above... I think after re-reading the code,
> > here's where I've arrived:
> >
> > - refill_work needs to hold RTNL (as in the existing patch)
> >
> > - virtnet_rx_pause, virtnet_rx_resume, virtnet_tx_pause,
> > virtnet_tx_resume -- all do NOT need to hold RTNL because it is
> > already held in the ethtool resize path and the XSK path, as you
> > explained, but I mis-read (sorry).
> >
> > - virtnet_disable_queue_pair and virtnet_enable_queue_pair both
> > need to hold RTNL only when called via power management, but not
> > when called via ndo_open or ndo_close
> >
> > Is my understanding correct and does it match your understanding?
> >
> > If so, that means there are two issues:
> >
> > 1. Fixing the hardcoded bools in rx_pause, rx_resume, tx_pause,
> > tx_resume (all should be false, RTNL is not needed).
> >
> > 2. Handling the power management case which calls virtnet_open and
> > virtnet_close.
> >
> > I made a small diff included below as an example of a possible
> > solution:
> >
> > 1. Modify virtnet_disable_queue_pair and virtnet_enable_queue_pair
> > to take a "bool need_rtnl" and pass it through to the helpers
> > they call.
> >
> > 2. Create two helpers, virtnet_do_open and virt_do_close both of
> > which take struct net_device *dev, bool need_rtnl. virtnet_open
> > and virtnet_close are modified to call the helpers and pass
> > false for need_rtnl. The power management paths call the
> > helpers and pass true for need_rtnl. (fixes issue 2 above)
> >
> > 3. Fix the bools for rx_pause, rx_resume, tx_pause, tx_resume to
> > pass false since all paths that I could find that lead to these
> > functions hold RTNL. (fixes issue 1 above)
> >
> > See the diff below (which can be applied on top of patch 3) to see
> > what it looks like.
> >
> > If you are OK with this approach, I will send a v5 where patch 3
> > includes the changes shown in this diff.
> >
> > Please let me know what you think:
>
>
>
> Looks ok I think.
>
> > diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> > index 13bb4a563073..76ecb8f3ce9a 100644
> > --- a/drivers/net/virtio_net.c
> > +++ b/drivers/net/virtio_net.c
> > @@ -3098,14 +3098,16 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
> > return received;
> > }
> >
> > -static void virtnet_disable_queue_pair(struct virtnet_info *vi, int qp_index)
> > +static void virtnet_disable_queue_pair(struct virtnet_info *vi, int qp_index,
> > + bool need_rtnl)
> > {
> > - virtnet_napi_tx_disable(&vi->sq[qp_index], false);
> > - virtnet_napi_disable(&vi->rq[qp_index], false);
> > + virtnet_napi_tx_disable(&vi->sq[qp_index], need_rtnl);
> > + virtnet_napi_disable(&vi->rq[qp_index], need_rtnl);
> > xdp_rxq_info_unreg(&vi->rq[qp_index].xdp_rxq);
> > }
> >
> > -static int virtnet_enable_queue_pair(struct virtnet_info *vi, int qp_index)
> > +static int virtnet_enable_queue_pair(struct virtnet_info *vi, int qp_index,
> > + bool need_rtnl)
> > {
> > struct net_device *dev = vi->dev;
> > int err;
> > @@ -3120,8 +3122,8 @@ static int virtnet_enable_queue_pair(struct virtnet_info *vi, int qp_index)
> > if (err < 0)
> > goto err_xdp_reg_mem_model;
> >
> > - virtnet_napi_enable(&vi->rq[qp_index], false);
> > - virtnet_napi_tx_enable(&vi->sq[qp_index], false);
> > + virtnet_napi_enable(&vi->rq[qp_index], need_rtnl);
> > + virtnet_napi_tx_enable(&vi->sq[qp_index], need_rtnl);
> >
> > return 0;
> >
> > @@ -3156,7 +3158,7 @@ static void virtnet_update_settings(struct virtnet_info *vi)
> > vi->duplex = duplex;
> > }
> >
> > -static int virtnet_open(struct net_device *dev)
> > +static int virtnet_do_open(struct net_device *dev, bool need_rtnl)
> > {
> > struct virtnet_info *vi = netdev_priv(dev);
> > int i, err;
> > @@ -3169,7 +3171,7 @@ static int virtnet_open(struct net_device *dev)
> > if (!try_fill_recv(vi, &vi->rq[i], GFP_KERNEL))
> > schedule_delayed_work(&vi->refill, 0);
> >
> > - err = virtnet_enable_queue_pair(vi, i);
> > + err = virtnet_enable_queue_pair(vi, i, need_rtnl);
> > if (err < 0)
> > goto err_enable_qp;
> > }
> > @@ -3190,13 +3192,18 @@ static int virtnet_open(struct net_device *dev)
> > cancel_delayed_work_sync(&vi->refill);
> >
> > for (i--; i >= 0; i--) {
> > - virtnet_disable_queue_pair(vi, i);
> > + virtnet_disable_queue_pair(vi, i, need_rtnl);
> > virtnet_cancel_dim(vi, &vi->rq[i].dim);
> > }
> >
> > return err;
> > }
> >
> > +static int virtnet_open(struct net_device *dev)
> > +{
> > + return virtnet_do_open(dev, false);
> > +}
> > +
> > static int virtnet_poll_tx(struct napi_struct *napi, int budget)
> > {
> > struct send_queue *sq = container_of(napi, struct send_queue, napi);
> > @@ -3373,7 +3380,7 @@ static void virtnet_rx_pause(struct virtnet_info *vi, struct receive_queue *rq)
> > bool running = netif_running(vi->dev);
> >
> > if (running) {
> > - virtnet_napi_disable(rq, true);
> > + virtnet_napi_disable(rq, false);
> > virtnet_cancel_dim(vi, &rq->dim);
> > }
> > }
> > @@ -3386,7 +3393,7 @@ static void virtnet_rx_resume(struct virtnet_info *vi, struct receive_queue *rq)
> > schedule_delayed_work(&vi->refill, 0);
> >
> > if (running)
> > - virtnet_napi_enable(rq, true);
> > + virtnet_napi_enable(rq, false);
> > }
> >
> > static int virtnet_rx_resize(struct virtnet_info *vi,
> > @@ -3415,7 +3422,7 @@ static void virtnet_tx_pause(struct virtnet_info *vi, struct send_queue *sq)
> > qindex = sq - vi->sq;
> >
> > if (running)
> > - virtnet_napi_tx_disable(sq, true);
> > + virtnet_napi_tx_disable(sq, false);
> >
> > txq = netdev_get_tx_queue(vi->dev, qindex);
> >
> > @@ -3449,7 +3456,7 @@ static void virtnet_tx_resume(struct virtnet_info *vi, struct send_queue *sq)
> > __netif_tx_unlock_bh(txq);
> >
> > if (running)
> > - virtnet_napi_tx_enable(sq, true);
> > + virtnet_napi_tx_enable(sq, false);
Instead of this, it looks to me it would be much simpler if we can
just hold the rtnl lock in freeze/restore.
Thanks
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH net-next v4 3/4] virtio-net: Map NAPIs to queues
2025-02-27 4:18 ` Jason Wang
@ 2025-02-27 4:48 ` Joe Damato
0 siblings, 0 replies; 18+ messages in thread
From: Joe Damato @ 2025-02-27 4:48 UTC (permalink / raw)
To: Jason Wang
Cc: Michael S. Tsirkin, netdev, mkarsten, gerhard, xuanzhuo, kuba,
Eugenio Pérez, Andrew Lunn, David S. Miller, Eric Dumazet,
Paolo Abeni, open list:VIRTIO CORE AND NET DRIVERS, open list
On Thu, Feb 27, 2025 at 12:18:33PM +0800, Jason Wang wrote:
> On Thu, Feb 27, 2025 at 6:13 AM Michael S. Tsirkin <mst@redhat.com> wrote:
> >
> > On Wed, Feb 26, 2025 at 03:27:42PM -0500, Joe Damato wrote:
> > > On Wed, Feb 26, 2025 at 01:08:49PM -0500, Joe Damato wrote:
> > > > On Wed, Feb 26, 2025 at 01:03:09PM -0500, Joe Damato wrote:
> > > > > On Wed, Feb 26, 2025 at 01:48:50PM +0800, Jason Wang wrote:
> > > > > > On Tue, Feb 25, 2025 at 10:05 AM Joe Damato <jdamato@fastly.com> wrote:
> > > > > > >
> > > > > > > Use netif_queue_set_napi to map NAPIs to queue IDs so that the mapping
> > > > > > > can be accessed by user apps, taking care to hold RTNL as needed.
> > > > > >
> > > > > > I may miss something but I wonder whether letting the caller hold the
> > > > > > lock is better.
> > > > >
> > > > > Hmm...
> > > > >
> > > > > Double checking all the paths over again, here's what I see:
> > > > > - refill_work, delayed work that needs RTNL so this change seems
> > > > > right?
> > > > >
> > > > > - virtnet_disable_queue_pair, called from virtnet_open and
> > > > > virtnet_close. When called via NDO these are safe and hold RTNL,
> > > > > but they can be called from power management and need RTNL.
> > > > >
> > > > > - virtnet_enable_queue_pair called from virtnet_open, safe when
> > > > > used via NDO but needs RTNL when used via power management.
> > > > >
> > > > > - virtnet_rx_pause called in both paths as you mentioned, one
> > > > > which needs RTNL and one which doesn't.
> > > >
> > > > Sorry, I missed more paths:
> > > >
> > > > - virtnet_rx_resume
> > > > - virtnet_tx_pause and virtnet_tx_resume
> > > >
> > > > which are similar to path you mentioned (virtnet_rx_pause) and need
> > > > rtnl in one of two different paths.
> > > >
> > > > Let me know if I missed any paths and what your preferred way to fix
> > > > this would be?
> > > >
> > > > I think both options below are possible and I have no strong
> > > > preference.
> > >
> > > OK, my apologies. I read your message and the code wrong. Sorry for
> > > the back-to-back emails from me.
> > >
> > > Please ignore my message above... I think after re-reading the code,
> > > here's where I've arrived:
> > >
> > > - refill_work needs to hold RTNL (as in the existing patch)
> > >
> > > - virtnet_rx_pause, virtnet_rx_resume, virtnet_tx_pause,
> > > virtnet_tx_resume -- all do NOT need to hold RTNL because it is
> > > already held in the ethtool resize path and the XSK path, as you
> > > explained, but I mis-read (sorry).
> > >
> > > - virtnet_disable_queue_pair and virtnet_enable_queue_pair both
> > > need to hold RTNL only when called via power management, but not
> > > when called via ndo_open or ndo_close
> > >
> > > Is my understanding correct and does it match your understanding?
> > >
> > > If so, that means there are two issues:
> > >
> > > 1. Fixing the hardcoded bools in rx_pause, rx_resume, tx_pause,
> > > tx_resume (all should be false, RTNL is not needed).
> > >
> > > 2. Handling the power management case which calls virtnet_open and
> > > virtnet_close.
> > >
> > > I made a small diff included below as an example of a possible
> > > solution:
> > >
> > > 1. Modify virtnet_disable_queue_pair and virtnet_enable_queue_pair
> > > to take a "bool need_rtnl" and pass it through to the helpers
> > > they call.
> > >
> > > 2. Create two helpers, virtnet_do_open and virt_do_close both of
> > > which take struct net_device *dev, bool need_rtnl. virtnet_open
> > > and virtnet_close are modified to call the helpers and pass
> > > false for need_rtnl. The power management paths call the
> > > helpers and pass true for need_rtnl. (fixes issue 2 above)
> > >
> > > 3. Fix the bools for rx_pause, rx_resume, tx_pause, tx_resume to
> > > pass false since all paths that I could find that lead to these
> > > functions hold RTNL. (fixes issue 1 above)
> > >
> > > See the diff below (which can be applied on top of patch 3) to see
> > > what it looks like.
> > >
> > > If you are OK with this approach, I will send a v5 where patch 3
> > > includes the changes shown in this diff.
> > >
> > > Please let me know what you think:
> >
> >
> >
> > Looks ok I think.
> >
> > > diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> > > index 13bb4a563073..76ecb8f3ce9a 100644
> > > --- a/drivers/net/virtio_net.c
> > > +++ b/drivers/net/virtio_net.c
> > > @@ -3098,14 +3098,16 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
> > > return received;
> > > }
> > >
> > > -static void virtnet_disable_queue_pair(struct virtnet_info *vi, int qp_index)
> > > +static void virtnet_disable_queue_pair(struct virtnet_info *vi, int qp_index,
> > > + bool need_rtnl)
> > > {
> > > - virtnet_napi_tx_disable(&vi->sq[qp_index], false);
> > > - virtnet_napi_disable(&vi->rq[qp_index], false);
> > > + virtnet_napi_tx_disable(&vi->sq[qp_index], need_rtnl);
> > > + virtnet_napi_disable(&vi->rq[qp_index], need_rtnl);
> > > xdp_rxq_info_unreg(&vi->rq[qp_index].xdp_rxq);
> > > }
> > >
> > > -static int virtnet_enable_queue_pair(struct virtnet_info *vi, int qp_index)
> > > +static int virtnet_enable_queue_pair(struct virtnet_info *vi, int qp_index,
> > > + bool need_rtnl)
> > > {
> > > struct net_device *dev = vi->dev;
> > > int err;
> > > @@ -3120,8 +3122,8 @@ static int virtnet_enable_queue_pair(struct virtnet_info *vi, int qp_index)
> > > if (err < 0)
> > > goto err_xdp_reg_mem_model;
> > >
> > > - virtnet_napi_enable(&vi->rq[qp_index], false);
> > > - virtnet_napi_tx_enable(&vi->sq[qp_index], false);
> > > + virtnet_napi_enable(&vi->rq[qp_index], need_rtnl);
> > > + virtnet_napi_tx_enable(&vi->sq[qp_index], need_rtnl);
> > >
> > > return 0;
> > >
> > > @@ -3156,7 +3158,7 @@ static void virtnet_update_settings(struct virtnet_info *vi)
> > > vi->duplex = duplex;
> > > }
> > >
> > > -static int virtnet_open(struct net_device *dev)
> > > +static int virtnet_do_open(struct net_device *dev, bool need_rtnl)
> > > {
> > > struct virtnet_info *vi = netdev_priv(dev);
> > > int i, err;
> > > @@ -3169,7 +3171,7 @@ static int virtnet_open(struct net_device *dev)
> > > if (!try_fill_recv(vi, &vi->rq[i], GFP_KERNEL))
> > > schedule_delayed_work(&vi->refill, 0);
> > >
> > > - err = virtnet_enable_queue_pair(vi, i);
> > > + err = virtnet_enable_queue_pair(vi, i, need_rtnl);
> > > if (err < 0)
> > > goto err_enable_qp;
> > > }
> > > @@ -3190,13 +3192,18 @@ static int virtnet_open(struct net_device *dev)
> > > cancel_delayed_work_sync(&vi->refill);
> > >
> > > for (i--; i >= 0; i--) {
> > > - virtnet_disable_queue_pair(vi, i);
> > > + virtnet_disable_queue_pair(vi, i, need_rtnl);
> > > virtnet_cancel_dim(vi, &vi->rq[i].dim);
> > > }
> > >
> > > return err;
> > > }
> > >
> > > +static int virtnet_open(struct net_device *dev)
> > > +{
> > > + return virtnet_do_open(dev, false);
> > > +}
> > > +
> > > static int virtnet_poll_tx(struct napi_struct *napi, int budget)
> > > {
> > > struct send_queue *sq = container_of(napi, struct send_queue, napi);
> > > @@ -3373,7 +3380,7 @@ static void virtnet_rx_pause(struct virtnet_info *vi, struct receive_queue *rq)
> > > bool running = netif_running(vi->dev);
> > >
> > > if (running) {
> > > - virtnet_napi_disable(rq, true);
> > > + virtnet_napi_disable(rq, false);
> > > virtnet_cancel_dim(vi, &rq->dim);
> > > }
> > > }
> > > @@ -3386,7 +3393,7 @@ static void virtnet_rx_resume(struct virtnet_info *vi, struct receive_queue *rq)
> > > schedule_delayed_work(&vi->refill, 0);
> > >
> > > if (running)
> > > - virtnet_napi_enable(rq, true);
> > > + virtnet_napi_enable(rq, false);
> > > }
> > >
> > > static int virtnet_rx_resize(struct virtnet_info *vi,
> > > @@ -3415,7 +3422,7 @@ static void virtnet_tx_pause(struct virtnet_info *vi, struct send_queue *sq)
> > > qindex = sq - vi->sq;
> > >
> > > if (running)
> > > - virtnet_napi_tx_disable(sq, true);
> > > + virtnet_napi_tx_disable(sq, false);
> > >
> > > txq = netdev_get_tx_queue(vi->dev, qindex);
> > >
> > > @@ -3449,7 +3456,7 @@ static void virtnet_tx_resume(struct virtnet_info *vi, struct send_queue *sq)
> > > __netif_tx_unlock_bh(txq);
> > >
> > > if (running)
> > > - virtnet_napi_tx_enable(sq, true);
> > > + virtnet_napi_tx_enable(sq, false);
>
> Instead of this, it looks to me it would be much simpler if we can
> just hold the rtnl lock in freeze/restore.
I disagree.
Holding RTNL for all of open and close instead of just the 1 API
call that needs it has the possibility of introducing other lock
ordering bugs now or in the future.
We only need RTNL for 1 API, why hold it for all of open or close?
^ permalink raw reply [flat|nested] 18+ messages in thread
end of thread, other threads:[~2025-02-27 4:48 UTC | newest]
Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-02-25 2:04 [PATCH net-next v4 0/4] virtio-net: Link queues to NAPIs Joe Damato
2025-02-25 2:04 ` [PATCH net-next v4 1/4] virtio-net: Refactor napi_enable paths Joe Damato
2025-02-26 5:49 ` Jason Wang
2025-02-25 2:04 ` [PATCH net-next v4 2/4] virtio-net: Refactor napi_disable paths Joe Damato
2025-02-26 5:49 ` Jason Wang
2025-02-25 2:04 ` [PATCH net-next v4 3/4] virtio-net: Map NAPIs to queues Joe Damato
2025-02-26 5:48 ` Jason Wang
2025-02-26 18:03 ` Joe Damato
2025-02-26 18:08 ` Joe Damato
2025-02-26 20:27 ` Joe Damato
2025-02-26 22:13 ` Michael S. Tsirkin
2025-02-27 4:18 ` Jason Wang
2025-02-27 4:48 ` Joe Damato
2025-02-26 22:11 ` Michael S. Tsirkin
2025-02-25 2:04 ` [PATCH net-next v4 4/4] virtio-net: Use persistent NAPI config Joe Damato
2025-02-25 15:46 ` [PATCH net-next v4 0/4] virtio-net: Link queues to NAPIs Lei Yang
2025-02-26 9:41 ` Jason Wang
2025-02-25 15:54 ` Michael S. Tsirkin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).