| From c9d0f2fb94ed972e295f5f0b4f6d9924bb23d2d8 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Tue, 13 Apr 2021 01:35:26 -0400 |
| Subject: virtio_net: move tx vq operation under tx queue lock |
| |
| From: Michael S. Tsirkin <mst@redhat.com> |
| |
| [ Upstream commit 5a2f966d0f3fa0ef6dada7ab9eda74cacee96b8a ] |
| |
| It's unsafe to operate a vq from multiple threads. |
| Unfortunately this is exactly what we do when invoking |
| clean tx poll from rx napi. |
| Same happens with napi-tx even without the |
| opportunistic cleaning from the receive interrupt: that races |
| with processing the vq in start_xmit. |
| |
| As a fix move everything that deals with the vq to under tx lock. |
| |
| Fixes: b92f1e6751a6 ("virtio-net: transmit napi") |
| Signed-off-by: Michael S. Tsirkin <mst@redhat.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/net/virtio_net.c | 22 +++++++++++++++++++++- |
| 1 file changed, 21 insertions(+), 1 deletion(-) |
| |
| diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c |
| index db9a876035ec..beb086023093 100644 |
| --- a/drivers/net/virtio_net.c |
| +++ b/drivers/net/virtio_net.c |
| @@ -1514,6 +1514,8 @@ static int virtnet_poll_tx(struct napi_struct *napi, int budget) |
| struct virtnet_info *vi = sq->vq->vdev->priv; |
| unsigned int index = vq2txq(sq->vq); |
| struct netdev_queue *txq; |
| + int opaque; |
| + bool done; |
| |
| if (unlikely(is_xdp_raw_buffer_queue(vi, index))) { |
| /* We don't need to enable cb for XDP */ |
| @@ -1523,10 +1525,28 @@ static int virtnet_poll_tx(struct napi_struct *napi, int budget) |
| |
| txq = netdev_get_tx_queue(vi->dev, index); |
| __netif_tx_lock(txq, raw_smp_processor_id()); |
| + virtqueue_disable_cb(sq->vq); |
| free_old_xmit_skbs(sq, true); |
| + |
| + opaque = virtqueue_enable_cb_prepare(sq->vq); |
| + |
| + done = napi_complete_done(napi, 0); |
| + |
| + if (!done) |
| + virtqueue_disable_cb(sq->vq); |
| + |
| __netif_tx_unlock(txq); |
| |
| - virtqueue_napi_complete(napi, sq->vq, 0); |
| + if (done) { |
| + if (unlikely(virtqueue_poll(sq->vq, opaque))) { |
| + if (napi_schedule_prep(napi)) { |
| + __netif_tx_lock(txq, raw_smp_processor_id()); |
| + virtqueue_disable_cb(sq->vq); |
| + __netif_tx_unlock(txq); |
| + __napi_schedule(napi); |
| + } |
| + } |
| + } |
| |
| if (sq->vq->num_free >= 2 + MAX_SKB_FRAGS) |
| netif_tx_wake_queue(txq); |
| -- |
| 2.30.2 |
| |