vmm: virtio-devices: Restore every VirtioDevice upon creation

Following the new design proposal to improve the restore codepath when
migrating a VM, all virtio devices are supplied with an optional state
they can use to restore from. The restore() implementation every device
was providing has been removed in order to prevent from going through
the restoration twice.

Here is the list of devices now following the new restore design:

- Block (virtio-block)
- Net (virtio-net)
- Rng (virtio-rng)
- Fs (vhost-user-fs)
- Blk (vhost-user-block)
- Net (vhost-user-net)
- Pmem (virtio-pmem)
- Vsock (virtio-vsock)
- Mem (virtio-mem)
- Balloon (virtio-balloon)
- Watchdog (virtio-watchdog)
- Vdpa (vDPA)
- Console (virtio-console)
- Iommu (virtio-iommu)

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
Sebastien Boeuf
2022-10-18 17:14:43 +02:00
parent 157db33d65
commit 1f0e5eb66a
26 changed files with 716 additions and 699 deletions
+55 -81
View File
@@ -64,6 +64,8 @@ pub enum Error {
ResetOwner(vhost::Error),
#[error("Failed to set backend specific features: {0}")]
SetBackendFeatures(vhost::Error),
#[error("Failed to set backend configuration: {0}")]
SetConfig(vhost::Error),
#[error("Failed to set eventfd notifying about a configuration change: {0}")]
SetConfigCall(vhost::Error),
#[error("Failed to set virtio features: {0}")]
@@ -107,14 +109,11 @@ impl VersionMapped for VdpaState {}
pub struct Vdpa {
common: VirtioCommon,
id: String,
mem: GuestMemoryAtomic<GuestMemoryMmap>,
device_path: String,
vhost: Option<VhostKernVdpa<GuestMemoryAtomic<GuestMemoryMmap>>>,
iova_range: VhostVdpaIovaRange,
enabled_queues: BTreeMap<usize, bool>,
backend_features: u64,
migrating: bool,
buffered_maps: Vec<(u64, u64, u64, bool)>,
}
impl Vdpa {
@@ -123,61 +122,77 @@ impl Vdpa {
device_path: &str,
mem: GuestMemoryAtomic<GuestMemoryMmap>,
num_queues: u16,
restoring: bool,
state: Option<VdpaState>,
) -> Result<Self> {
if restoring {
return Ok(Vdpa {
common: VirtioCommon {
queue_sizes: vec![1024; num_queues as usize],
min_queues: num_queues,
..Default::default()
},
id,
mem,
device_path: device_path.to_string(),
vhost: None,
iova_range: VhostVdpaIovaRange { first: 0, last: 0 },
enabled_queues: BTreeMap::new(),
backend_features: 0,
migrating: false,
buffered_maps: Vec::new(),
});
}
let mut vhost =
VhostKernVdpa::new(device_path, mem.clone()).map_err(Error::CreateVhostVdpa)?;
let mut vhost = VhostKernVdpa::new(device_path, mem).map_err(Error::CreateVhostVdpa)?;
vhost.set_owner().map_err(Error::SetOwner)?;
let device_type = vhost.get_device_id().map_err(Error::GetDeviceId)?;
let queue_size = vhost.get_vring_num().map_err(Error::GetVringNum)?;
let avail_features = vhost.get_features().map_err(Error::GetFeatures)?;
let backend_features = vhost
.get_backend_features()
.map_err(Error::GetBackendFeatures)?;
vhost.set_backend_features_acked(backend_features);
let iova_range = vhost.get_iova_range().map_err(Error::GetIovaRange)?;
let (
device_type,
avail_features,
acked_features,
queue_sizes,
iova_range,
backend_features,
) = if let Some(state) = state {
info!("Restoring vDPA {}", id);
if avail_features & (1u64 << VIRTIO_F_IOMMU_PLATFORM) == 0 {
return Err(Error::MissingAccessPlatformVirtioFeature);
}
vhost.set_backend_features_acked(state.backend_features);
vhost
.set_config(0, state.config.as_slice())
.map_err(Error::SetConfig)?;
(
state.device_type,
state.avail_features,
state.acked_features,
state.queue_sizes,
VhostVdpaIovaRange {
first: state.iova_range_first,
last: state.iova_range_last,
},
state.backend_features,
)
} else {
let device_type = vhost.get_device_id().map_err(Error::GetDeviceId)?;
let queue_size = vhost.get_vring_num().map_err(Error::GetVringNum)?;
let avail_features = vhost.get_features().map_err(Error::GetFeatures)?;
let backend_features = vhost
.get_backend_features()
.map_err(Error::GetBackendFeatures)?;
vhost.set_backend_features_acked(backend_features);
let iova_range = vhost.get_iova_range().map_err(Error::GetIovaRange)?;
if avail_features & (1u64 << VIRTIO_F_IOMMU_PLATFORM) == 0 {
return Err(Error::MissingAccessPlatformVirtioFeature);
}
(
device_type,
avail_features,
0,
vec![queue_size; num_queues as usize],
iova_range,
backend_features,
)
};
Ok(Vdpa {
common: VirtioCommon {
device_type,
queue_sizes: vec![queue_size; num_queues as usize],
queue_sizes,
avail_features,
acked_features,
min_queues: num_queues,
..Default::default()
},
id,
mem,
device_path: device_path.to_string(),
vhost: Some(vhost),
iova_range,
enabled_queues: BTreeMap::new(),
backend_features,
migrating: false,
buffered_maps: Vec::new(),
})
}
@@ -318,12 +333,6 @@ impl Vdpa {
host_vaddr: *const u8,
readonly: bool,
) -> Result<()> {
if self.vhost.is_none() {
self.buffered_maps
.push((iova, size, host_vaddr as u64, readonly));
return Ok(());
}
let iova_last = iova + size - 1;
if iova < self.iova_range.first || iova_last > self.iova_range.last {
return Err(Error::InvalidIovaRange(iova, iova_last));
@@ -373,33 +382,6 @@ impl Vdpa {
backend_features: self.backend_features,
})
}
fn set_state(&mut self, state: &VdpaState) -> Result<()> {
self.common.avail_features = state.avail_features;
self.common.acked_features = state.acked_features;
self.common.device_type = state.device_type;
self.common.queue_sizes = state.queue_sizes.clone();
self.iova_range = VhostVdpaIovaRange {
first: state.iova_range_first,
last: state.iova_range_last,
};
self.backend_features = state.backend_features;
let mut vhost = VhostKernVdpa::new(self.device_path.as_str(), self.mem.clone())
.map_err(Error::CreateVhostVdpa)?;
vhost.set_owner().map_err(Error::SetOwner)?;
vhost.set_backend_features_acked(self.backend_features);
self.vhost = Some(vhost);
self.write_config(0, state.config.as_slice());
let maps: Vec<(u64, u64, u64, bool)> = self.buffered_maps.drain(..).collect();
for (iova, size, host_vaddr, readonly) in maps {
self.dma_map(iova, size, host_vaddr as *const u8, readonly)?;
}
Ok(())
}
}
impl VirtioDevice for Vdpa {
@@ -514,14 +496,6 @@ impl Snapshottable for Vdpa {
Ok(snapshot)
}
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
self.set_state(&snapshot.to_versioned_state(&self.id)?)
.map_err(|e| {
MigratableError::Restore(anyhow!("Error restoring vDPA device: {:?}", e))
})?;
Ok(())
}
}
impl Transportable for Vdpa {}