Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 496bcc8d authored by Michael S. Tsirkin's avatar Michael S. Tsirkin Committed by Greg Kroah-Hartman
Browse files

virtio_net: move tx vq operation under tx queue lock



[ 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: b92f1e67 ("virtio-net: transmit napi")
Signed-off-by: default avatarMichael S. Tsirkin <mst@redhat.com>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent aac6a79e
Loading
Loading
Loading
Loading
+21 −1
Original line number Diff line number Diff line
@@ -1504,6 +1504,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 */
@@ -1513,10 +1515,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);