virtio_net_backend_read_poll_set() re-enables TAP read polling on
vmstart even when kernel vhost has already taken over RX.

That lets QEMU userspace and vhost race on the same tap fd and can
corrupt the restored virtqueue state during migration switchover.

Keep read_poll disabled for TAP backends with a started vhost_net, while
leaving pure userspace backends unchanged.

Signed-off-by: Cindy Lu <[email protected]>
---
 hw/net/virtio-net.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index d6d2188863..616590fb82 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -1322,9 +1322,19 @@ static void virtio_net_backend_read_poll_set(VirtIONet 
*n, bool enable)
     for (i = 0; i < (int)n->max_ncs; i++) {
         NetClientState *frontend = qemu_get_subqueue(n->nic, i);
         NetClientState *backend = frontend ? frontend->peer : NULL;
+        bool backend_enable = enable;
 
         if (backend && backend->info && backend->info->read_poll) {
-            backend->info->read_poll(backend, enable);
+            /*
+             * When vhost is active, the kernel backend owns the tap RX path.
+             * Re-enabling QEMU read_poll on vmstart makes userspace and vhost
+             * race on the same tap fd, which can corrupt the restored RX ring
+             * during migration switchover replay.
+             */
+            if (enable && get_vhost_net(backend) && n->vhost_started) {
+                backend_enable = false;
+            }
+            backend->info->read_poll(backend, backend_enable);
         }
     }
 }
-- 
2.52.0


Reply via email to