Skip to content

Commit 4bc1281

Browse files
minhbq-99kuba-moo
authored andcommitted
virtio-net: disable delayed refill when pausing rx
When pausing rx (e.g. set up xdp, xsk pool, rx resize), we call napi_disable() on the receive queue's napi. In delayed refill_work, it also calls napi_disable() on the receive queue's napi. When napi_disable() is called on an already disabled napi, it will sleep in napi_disable_locked while still holding the netdev_lock. As a result, later napi_enable gets stuck too as it cannot acquire the netdev_lock. This leads to refill_work and the pause-then-resume tx are stuck altogether. This scenario can be reproducible by binding a XDP socket to virtio-net interface without setting up the fill ring. As a result, try_fill_recv will fail until the fill ring is set up and refill_work is scheduled. This commit adds virtnet_rx_(pause/resume)_all helpers and fixes up the virtnet_rx_resume to disable future and cancel all inflights delayed refill_work before calling napi_disable() to pause the rx. Fixes: 413f027 ("net: protect NAPI enablement with netdev_lock()") Acked-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Bui Quang Minh <minhquangbui99@gmail.com> Acked-by: Jason Wang <jasowang@redhat.com> Link: https://patch.msgid.link/20250417072806.18660-2-minhquangbui99@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
1 parent b7f0ee9 commit 4bc1281

File tree

1 file changed

+57
-12
lines changed

1 file changed

+57
-12
lines changed

drivers/net/virtio_net.c

Lines changed: 57 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3342,7 +3342,8 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
33423342
return NETDEV_TX_OK;
33433343
}
33443344

3345-
static void virtnet_rx_pause(struct virtnet_info *vi, struct receive_queue *rq)
3345+
static void __virtnet_rx_pause(struct virtnet_info *vi,
3346+
struct receive_queue *rq)
33463347
{
33473348
bool running = netif_running(vi->dev);
33483349

@@ -3352,17 +3353,63 @@ static void virtnet_rx_pause(struct virtnet_info *vi, struct receive_queue *rq)
33523353
}
33533354
}
33543355

3355-
static void virtnet_rx_resume(struct virtnet_info *vi, struct receive_queue *rq)
3356+
static void virtnet_rx_pause_all(struct virtnet_info *vi)
3357+
{
3358+
int i;
3359+
3360+
/*
3361+
* Make sure refill_work does not run concurrently to
3362+
* avoid napi_disable race which leads to deadlock.
3363+
*/
3364+
disable_delayed_refill(vi);
3365+
cancel_delayed_work_sync(&vi->refill);
3366+
for (i = 0; i < vi->max_queue_pairs; i++)
3367+
__virtnet_rx_pause(vi, &vi->rq[i]);
3368+
}
3369+
3370+
static void virtnet_rx_pause(struct virtnet_info *vi, struct receive_queue *rq)
3371+
{
3372+
/*
3373+
* Make sure refill_work does not run concurrently to
3374+
* avoid napi_disable race which leads to deadlock.
3375+
*/
3376+
disable_delayed_refill(vi);
3377+
cancel_delayed_work_sync(&vi->refill);
3378+
__virtnet_rx_pause(vi, rq);
3379+
}
3380+
3381+
static void __virtnet_rx_resume(struct virtnet_info *vi,
3382+
struct receive_queue *rq,
3383+
bool refill)
33563384
{
33573385
bool running = netif_running(vi->dev);
33583386

3359-
if (!try_fill_recv(vi, rq, GFP_KERNEL))
3387+
if (refill && !try_fill_recv(vi, rq, GFP_KERNEL))
33603388
schedule_delayed_work(&vi->refill, 0);
33613389

33623390
if (running)
33633391
virtnet_napi_enable(rq);
33643392
}
33653393

3394+
static void virtnet_rx_resume_all(struct virtnet_info *vi)
3395+
{
3396+
int i;
3397+
3398+
enable_delayed_refill(vi);
3399+
for (i = 0; i < vi->max_queue_pairs; i++) {
3400+
if (i < vi->curr_queue_pairs)
3401+
__virtnet_rx_resume(vi, &vi->rq[i], true);
3402+
else
3403+
__virtnet_rx_resume(vi, &vi->rq[i], false);
3404+
}
3405+
}
3406+
3407+
static void virtnet_rx_resume(struct virtnet_info *vi, struct receive_queue *rq)
3408+
{
3409+
enable_delayed_refill(vi);
3410+
__virtnet_rx_resume(vi, rq, true);
3411+
}
3412+
33663413
static int virtnet_rx_resize(struct virtnet_info *vi,
33673414
struct receive_queue *rq, u32 ring_num)
33683415
{
@@ -5959,12 +6006,12 @@ static int virtnet_xdp_set(struct net_device *dev, struct bpf_prog *prog,
59596006
if (prog)
59606007
bpf_prog_add(prog, vi->max_queue_pairs - 1);
59616008

6009+
virtnet_rx_pause_all(vi);
6010+
59626011
/* Make sure NAPI is not using any XDP TX queues for RX. */
59636012
if (netif_running(dev)) {
5964-
for (i = 0; i < vi->max_queue_pairs; i++) {
5965-
virtnet_napi_disable(&vi->rq[i]);
6013+
for (i = 0; i < vi->max_queue_pairs; i++)
59666014
virtnet_napi_tx_disable(&vi->sq[i]);
5967-
}
59686015
}
59696016

59706017
if (!prog) {
@@ -5996,13 +6043,12 @@ static int virtnet_xdp_set(struct net_device *dev, struct bpf_prog *prog,
59966043
vi->xdp_enabled = false;
59976044
}
59986045

6046+
virtnet_rx_resume_all(vi);
59996047
for (i = 0; i < vi->max_queue_pairs; i++) {
60006048
if (old_prog)
60016049
bpf_prog_put(old_prog);
6002-
if (netif_running(dev)) {
6003-
virtnet_napi_enable(&vi->rq[i]);
6050+
if (netif_running(dev))
60046051
virtnet_napi_tx_enable(&vi->sq[i]);
6005-
}
60066052
}
60076053

60086054
return 0;
@@ -6014,11 +6060,10 @@ static int virtnet_xdp_set(struct net_device *dev, struct bpf_prog *prog,
60146060
rcu_assign_pointer(vi->rq[i].xdp_prog, old_prog);
60156061
}
60166062

6063+
virtnet_rx_resume_all(vi);
60176064
if (netif_running(dev)) {
6018-
for (i = 0; i < vi->max_queue_pairs; i++) {
6019-
virtnet_napi_enable(&vi->rq[i]);
6065+
for (i = 0; i < vi->max_queue_pairs; i++)
60206066
virtnet_napi_tx_enable(&vi->sq[i]);
6021-
}
60226067
}
60236068
if (prog)
60246069
bpf_prog_sub(prog, vi->max_queue_pairs - 1);

0 commit comments

Comments
 (0)