vdpa: fix RX failure after device reset by always using base 0

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 <maxpain@linux.com>
This commit is contained in:
Max Makarov
2026-04-04 20:32:49 +00:00
committed by Bo Chen
parent f56c8392ea
commit aef0a43b52

View File

@@ -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) =