Skip to content

Commit fc8c91d

Browse files
committed
Add snapshot save and restore functionality to CpuContainer
Implement Persist and the required functions for saving and restoring snapshots Note: Currently when saving a snapshot, custom CPU templates are not saved. This is because, up until now, it has only been needed at initialization. With the implementation of hotplugging however, CPU templates and the vCPU config are now required for the lifetime of the VMM. As a result of this, hotplugging will throw an error after restoring from snapshot. Signed-off-by: James Curtis <[email protected]>
1 parent ecb9e4b commit fc8c91d

File tree

4 files changed

+112
-5
lines changed

4 files changed

+112
-5
lines changed

src/vmm/src/builder.rs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ use crate::cpu_config::templates::{
3838
CpuConfiguration, CustomCpuTemplate, GetCpuTemplate, GetCpuTemplateError, GuestConfigError,
3939
KvmCapability,
4040
};
41-
use crate::cpu_config::x86_64::cpuid::{self, Cpuid};
4241
#[cfg(target_arch = "x86_64")]
4342
use crate::device_manager::acpi::ACPIDeviceManager;
4443
#[cfg(target_arch = "x86_64")]
@@ -465,6 +464,8 @@ pub enum BuildMicrovmFromSnapshotError {
465464
StartVcpus(#[from] crate::StartVcpusError),
466465
/// Failed to restore vCPUs: {0}
467466
RestoreVcpus(#[from] VcpuError),
467+
/// Failed to restore CPUID: {0}
468+
RestoreCpuId(#[from] GuestConfigError),
468469
/// Failed to apply VMM secccomp filter as none found.
469470
MissingVmmSeccompFilters,
470471
/// Failed to apply VMM secccomp filter: {0}
@@ -537,6 +538,31 @@ pub fn build_microvm_from_snapshot(
537538
#[cfg(target_arch = "x86_64")]
538539
vmm.vm.restore_state(&microvm_state.vm_state)?;
539540

541+
#[cfg(target_arch = "x86_64")]
542+
{
543+
// FIXME: Custom templates are not stored when snapshots are taken, as they were previously
544+
// only needed at boottime. With hotplugging, the template could be necessary at any time,
545+
// so snapshot must be modified in order to save custom templates
546+
547+
// let cpuid = Cpuid::try_from(vmm.vm.supported_cpuid().clone())
548+
// .map_err(GuestConfigError::CpuidFromKvmCpuid)?;
549+
550+
// let_cpu_template = &microvm_state.vm_info.cpu_template;
551+
//
552+
// let msrs = vcpus[0]
553+
// .kvm_vcpu
554+
// .get_msrs(&[])
555+
// .map_err(GuestConfigError::VcpuIoctl)?;
556+
//
557+
// let cpu_config = CpuConfiguration { cpuid, msrs };
558+
//
559+
// let vcpu_config = VcpuConfig {
560+
// vcpu_count: vcpus.len().try_into().unwrap(),
561+
// smt: microvm_state.vm_info.smt,
562+
// cpu_config,
563+
// };
564+
}
565+
540566
// Restore the boot source config paths.
541567
vm_resources.set_boot_source_config(microvm_state.vm_info.boot_source);
542568

src/vmm/src/device_manager/persist.rs

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ use super::resources::ResourceAllocator;
1919
#[cfg(target_arch = "aarch64")]
2020
use crate::arch::DeviceType;
2121
#[cfg(target_arch = "x86_64")]
22-
use crate::devices::acpi::cpu_container::CpuContainer;
22+
use crate::devices::acpi::cpu_container::{
23+
CpuContainer, CpuContainerConstructorArgs, CpuContainerError, CpuContainerState,
24+
};
2325
#[cfg(target_arch = "x86_64")]
2426
use crate::devices::acpi::vmgenid::{VMGenIDState, VMGenIdConstructorArgs, VmGenId, VmGenIdError};
2527
use crate::devices::virtio::balloon::persist::{BalloonConstructorArgs, BalloonState};
@@ -59,6 +61,9 @@ pub enum DevicePersistError {
5961
Balloon(#[from] BalloonError),
6062
/// Block: {0}
6163
Block(#[from] BlockError),
64+
/// CpuContainer: {0}
65+
#[cfg(target_arch = "x86_64")]
66+
CpuContainer(#[from] CpuContainerError),
6267
/// Device manager: {0}
6368
DeviceManager(#[from] super::mmio::MmioError),
6469
/// Mmio transport
@@ -155,6 +160,13 @@ pub struct ConnectedLegacyState {
155160
pub device_info: MMIODeviceInfo,
156161
}
157162

163+
#[cfg(target_arch = "x86_64")]
164+
#[derive(Debug, Clone, Serialize, Deserialize)]
165+
pub struct ConnectedCpuContainerState {
166+
pub device_state: CpuContainerState,
167+
pub device_info: MMIODeviceInfo,
168+
}
169+
158170
/// Holds the MMDS data store version.
159171
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
160172
pub enum MmdsVersionState {
@@ -198,6 +210,9 @@ pub struct DeviceStates {
198210
pub mmds_version: Option<MmdsVersionState>,
199211
/// Entropy device state.
200212
pub entropy_device: Option<ConnectedEntropyState>,
213+
/// Cpu Container device state.
214+
#[cfg(target_arch = "x86_64")]
215+
pub cpu_container: Option<ConnectedCpuContainerState>,
201216
}
202217

203218
/// A type used to extract the concrete `Arc<Mutex<T>>` for each of the device
@@ -253,6 +268,9 @@ pub enum ACPIDeviceManagerRestoreError {
253268
Interrupt(#[from] kvm_ioctls::Error),
254269
/// Could not create VMGenID device: {0}
255270
VMGenID(#[from] VmGenIdError),
271+
/// Could not create CpuContainer device: {0}
272+
#[cfg(target_arch = "x86_64")]
273+
CpuContainer(#[from] CpuContainerError),
256274
}
257275

258276
#[cfg(target_arch = "x86_64")]
@@ -292,11 +310,21 @@ impl<'a> Persist<'a> for MMIODeviceManager {
292310
type Error = DevicePersistError;
293311

294312
fn save(&self) -> Self::State {
313+
use crate::devices::bus::BusDevice::*;
295314
let mut states = DeviceStates::default();
315+
#[allow(unused_variables)]
296316
let _: Result<(), ()> = self.for_each_device(|devtype, devid, device_info, bus_dev| {
297-
if *devtype == crate::arch::DeviceType::BootTimer {
298-
// No need to save BootTimer state.
299-
return Ok(());
317+
match bus_dev {
318+
BootTimer(_) => return Ok(()),
319+
#[cfg(target_arch = "x86_64")]
320+
CpuContainer(x) => {
321+
states.cpu_container = Some(ConnectedCpuContainerState {
322+
device_state: x.lock().expect("Poisoned lock").save(),
323+
device_info: device_info.clone(),
324+
});
325+
return Ok(());
326+
}
327+
_ => (),
300328
}
301329

302330
#[cfg(target_arch = "aarch64")]
@@ -653,6 +681,17 @@ impl<'a> Persist<'a> for MMIODeviceManager {
653681
)?;
654682
}
655683

684+
#[cfg(target_arch = "x86_64")]
685+
if let Some(container) = &state.cpu_container {
686+
let ctor_args = CpuContainerConstructorArgs { vm };
687+
let device = Arc::new(Mutex::new(CpuContainer::restore(
688+
ctor_args,
689+
&container.device_state,
690+
)?));
691+
692+
dev_manager.register_mmio_cpu_container(vm, device, &container.device_info)?;
693+
}
694+
656695
Ok(dev_manager)
657696
}
658697
}

src/vmm/src/devices/acpi/cpu_container.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,33 @@ impl CpuContainer {
152152
}
153153
}
154154

155+
impl<'a> Persist<'a> for CpuContainer {
156+
type State = CpuContainerState;
157+
type ConstructorArgs = CpuContainerConstructorArgs<'a>;
158+
type Error = CpuContainerError;
159+
160+
fn save(&self) -> Self::State {
161+
Self::State {
162+
mmio_address: self.mmio_address.0,
163+
gsi: self.gsi,
164+
cpu_devices: self.cpu_devices.clone(),
165+
selected_cpu: self.selected_cpu,
166+
}
167+
}
168+
169+
fn restore(
170+
_constructor_args: Self::ConstructorArgs,
171+
state: &Self::State,
172+
) -> std::result::Result<Self, Self::Error> {
173+
Self::from_parts(
174+
GuestAddress(state.mmio_address),
175+
state.gsi,
176+
state.selected_cpu,
177+
state.cpu_devices.clone(),
178+
)
179+
}
180+
}
181+
155182
impl Aml for CpuContainer {
156183
fn append_aml_bytes(&self, v: &mut Vec<u8>) {
157184
// CPU hotplug controller
@@ -222,6 +249,19 @@ impl Aml for CpuContainer {
222249
}
223250
}
224251

252+
#[derive(Debug, Clone, Serialize, Deserialize)]
253+
pub struct CpuContainerState {
254+
pub mmio_address: u64,
255+
pub gsi: u32,
256+
pub cpu_devices: Vec<CpuDevice>,
257+
pub selected_cpu: u8,
258+
}
259+
260+
#[derive(Debug, Clone)]
261+
pub struct CpuContainerConstructorArgs<'a> {
262+
pub vm: &'a VmFd,
263+
}
264+
225265
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
226266
pub struct CpuDevice {
227267
/// The ID of this CPU, matches APICID

src/vmm/src/vmm_config/hotplug.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ pub enum HotplugVcpuError {
3838
VcpuStart(StartVcpusError),
3939
/// No seccomp filter for thread category: {0}
4040
MissingSeccompFilters(String),
41+
/// Cannot hotplug vCPUs after restoring from snapshot
42+
RestoredFromSnapshot,
4143
}
4244

4345
/// Config for hotplugging vCPUS

0 commit comments

Comments
 (0)