From aef0a43b52c2c6a688e2235fc18cddfc604d51eb Mon Sep 17 00:00:00 2001 From: Max Makarov Date: Sat, 4 Apr 2026 20:32:49 +0000 Subject: [PATCH] vdpa: fix RX failure after device reset by always using base 0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After a vDPA device reset, activate_vdpa() read avail_idx from guest memory to pass as the vring base via VHOST_SET_VRING_BASE. However, the guest memory still contained the stale avail_idx from the previous session. For a 256-entry ring, this meant base=256, causing the hardware to believe the entire RX ring was consumed with no available buffers — RX silently stopped while TX continued to work. QEMU handles this correctly by tracking last_avail_idx internally (reset to 0 in virtio_reset()) and passing that value, rather than reading from guest memory. Fix by always passing base=0 to set_vring_base(). After a device reset, both the guest driver and the vhost backend restart their rings from index 0. For live migration, the correct base should come from VHOST_GET_VRING_BASE (saved before the migration), not guest memory. Tested with mlx5_vdpa (ConnectX-6 Dx) + Windows Server 2025 (netkvm). Before: RX=0 after 3rd driver activation. After: full connectivity. Signed-off-by: Max Makarov --- virtio-devices/src/vdpa.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/virtio-devices/src/vdpa.rs b/virtio-devices/src/vdpa.rs index 4773ef55f..7cd341518 100644 --- a/virtio-devices/src/vdpa.rs +++ b/virtio-devices/src/vdpa.rs @@ -217,7 +217,7 @@ impl Vdpa { fn activate_vdpa( &mut self, - mem: &GuestMemoryMmap, + _mem: &GuestMemoryMmap, virtio_interrupt: &dyn VirtioInterrupt, queues: &[(usize, Queue, EventFd)], ) -> Result<()> { @@ -269,13 +269,7 @@ impl Vdpa { self.vhost .as_ref() .unwrap() - .set_vring_base( - *queue_index, - queue - .avail_idx(mem, Ordering::Acquire) - .map_err(Error::GetAvailableIndex)? - .0, - ) + .set_vring_base(*queue_index, 0) .map_err(Error::SetVringBase)?; if let Some(eventfd) =