From c3f1c3ee3df276c3e416845e67542aed146f142c Mon Sep 17 00:00:00 2001 From: Alexandru Matei Date: Fri, 22 Mar 2024 13:49:08 +0200 Subject: [PATCH] virtio-devices: save pci configuration capability state in snapshot When restoring a VM, the VirtioPciCfgCapInfo struct is not properly initialized. All fields are 0, including the offset where the capabibility starts. Hence, when you read a PCI configuration register in the range [0..length(VirtioPciCfgCap)] you get the value 0 instead of the actual register contents. Linux rescans the whole PCI bus when adding a new device. It reads the values vendor_id and device_id for every device. Because these are stored at offset 0 in pci configuration space, their value is 0 for existing devices. As such, Linux considers that the devices have been unplugged and it removes them from the system. Fixes: #6265 Signed-off-by: Alexandru Matei --- virtio-devices/src/transport/pci_device.rs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/virtio-devices/src/transport/pci_device.rs b/virtio-devices/src/transport/pci_device.rs index 931d722d5..58e79ae33 100644 --- a/virtio-devices/src/transport/pci_device.rs +++ b/virtio-devices/src/transport/pci_device.rs @@ -278,6 +278,8 @@ pub struct VirtioPciDeviceState { device_activated: bool, queues: Vec, interrupt_status: usize, + cap_pci_cfg_offset: usize, + cap_pci_cfg: Vec, } impl VersionMapped for VirtioPciDeviceState {} @@ -530,7 +532,7 @@ impl VirtioPciDevice { )) })?; - let (device_activated, interrupt_status) = if let Some(state) = state { + let (device_activated, interrupt_status, cap_pci_cfg_info) = if let Some(state) = state { // Update virtqueues indexes for both available and used rings. for (i, queue) in queues.iter_mut().enumerate() { queue.set_size(state.queues[i].size); @@ -558,9 +560,16 @@ impl VirtioPciDevice { ); } - (state.device_activated, state.interrupt_status) + ( + state.device_activated, + state.interrupt_status, + VirtioPciCfgCapInfo { + offset: state.cap_pci_cfg_offset, + cap: *VirtioPciCfgCap::from_slice(&state.cap_pci_cfg).unwrap(), + }, + ) } else { - (false, 0) + (false, 0, VirtioPciCfgCapInfo::default()) }; // Dropping the MutexGuard to unlock the VirtioDevice. This is required @@ -585,7 +594,7 @@ impl VirtioPciDevice { settings_bar: 0, use_64bit_bar, interrupt_source_group, - cap_pci_cfg_info: VirtioPciCfgCapInfo::default(), + cap_pci_cfg_info, bar_regions: vec![], activate_evt, dma_handler, @@ -634,6 +643,8 @@ impl VirtioPciDevice { used_ring: q.used_ring(), }) .collect(), + cap_pci_cfg_offset: self.cap_pci_cfg_info.offset, + cap_pci_cfg: self.cap_pci_cfg_info.cap.bytes().to_vec(), } }