mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2024-10-01 02:55:45 +00:00
vmm: Create MemoryManager from restore data
Extending the MemoryManager::new() function to be able to create a MemoryManager from data that have been previously stored instead of always creating everything from scratch. This change brings real added value as it allows a VM to be restored respecting the proper memory layout instead of hoping the regions will be created the way they were before. Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
parent
5b177b205b
commit
6a55768d94
@ -218,6 +218,9 @@ pub enum Error {
|
|||||||
/// Cannot restore VM
|
/// Cannot restore VM
|
||||||
Restore(MigratableError),
|
Restore(MigratableError),
|
||||||
|
|
||||||
|
/// Cannot restore VM because source URL is missing
|
||||||
|
RestoreMissingSourceUrl,
|
||||||
|
|
||||||
/// Cannot create the system allocator
|
/// Cannot create the system allocator
|
||||||
CreateSystemAllocator,
|
CreateSystemAllocator,
|
||||||
|
|
||||||
@ -516,7 +519,6 @@ impl MemoryManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Restore both GuestMemory regions along with MemoryZone zones.
|
// Restore both GuestMemory regions along with MemoryZone zones.
|
||||||
#[allow(dead_code)]
|
|
||||||
fn restore_memory_regions_and_zones(
|
fn restore_memory_regions_and_zones(
|
||||||
guest_ram_mappings: &[GuestRamMapping],
|
guest_ram_mappings: &[GuestRamMapping],
|
||||||
zones_config: &[MemoryZoneConfig],
|
zones_config: &[MemoryZoneConfig],
|
||||||
@ -817,38 +819,10 @@ impl MemoryManager {
|
|||||||
prefault: Option<bool>,
|
prefault: Option<bool>,
|
||||||
phys_bits: u8,
|
phys_bits: u8,
|
||||||
#[cfg(feature = "tdx")] tdx_enabled: bool,
|
#[cfg(feature = "tdx")] tdx_enabled: bool,
|
||||||
|
restore_data: Option<&MemoryManagerSnapshotData>,
|
||||||
) -> Result<Arc<Mutex<MemoryManager>>, Error> {
|
) -> Result<Arc<Mutex<MemoryManager>>, Error> {
|
||||||
let user_provided_zones = config.size == 0;
|
let user_provided_zones = config.size == 0;
|
||||||
|
|
||||||
let (ram_size, zones, allow_mem_hotplug) =
|
|
||||||
Self::validate_memory_config(config, user_provided_zones)?;
|
|
||||||
|
|
||||||
// Init guest memory
|
|
||||||
let arch_mem_regions = arch::arch_memory_regions(ram_size);
|
|
||||||
|
|
||||||
let ram_regions: Vec<(GuestAddress, usize)> = arch_mem_regions
|
|
||||||
.iter()
|
|
||||||
.filter(|r| r.2 == RegionType::Ram)
|
|
||||||
.map(|r| (r.0, r.1))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let arch_mem_regions: Vec<ArchMemRegion> = arch_mem_regions
|
|
||||||
.iter()
|
|
||||||
.map(|(a, b, c)| ArchMemRegion {
|
|
||||||
base: a.0,
|
|
||||||
size: *b,
|
|
||||||
r_type: *c,
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let (mem_regions, mut memory_zones) =
|
|
||||||
Self::create_memory_regions_from_zones(&ram_regions, &zones, prefault)?;
|
|
||||||
|
|
||||||
let mut guest_memory =
|
|
||||||
GuestMemoryMmap::from_arc_regions(mem_regions).map_err(Error::GuestMemory)?;
|
|
||||||
|
|
||||||
let boot_guest_memory = guest_memory.clone();
|
|
||||||
|
|
||||||
let mmio_address_space_size = mmio_address_space_size(phys_bits);
|
let mmio_address_space_size = mmio_address_space_size(phys_bits);
|
||||||
debug_assert_eq!(
|
debug_assert_eq!(
|
||||||
(((mmio_address_space_size) >> 16) << 16),
|
(((mmio_address_space_size) >> 16) << 16),
|
||||||
@ -856,78 +830,155 @@ impl MemoryManager {
|
|||||||
);
|
);
|
||||||
let end_of_device_area = GuestAddress(mmio_address_space_size - 1);
|
let end_of_device_area = GuestAddress(mmio_address_space_size - 1);
|
||||||
|
|
||||||
let mut start_of_device_area =
|
let (ram_size, zones, allow_mem_hotplug) =
|
||||||
MemoryManager::start_addr(guest_memory.last_addr(), allow_mem_hotplug)?;
|
Self::validate_memory_config(config, user_provided_zones)?;
|
||||||
|
|
||||||
// Update list of memory zones for resize.
|
let (
|
||||||
for zone in zones.iter() {
|
start_of_device_area,
|
||||||
if let Some(memory_zone) = memory_zones.get_mut(&zone.id) {
|
boot_ram,
|
||||||
if let Some(hotplug_size) = zone.hotplug_size {
|
current_ram,
|
||||||
if hotplug_size == 0 {
|
arch_mem_regions,
|
||||||
error!("'hotplug_size' can't be 0");
|
memory_zones,
|
||||||
return Err(Error::InvalidHotplugSize);
|
guest_memory,
|
||||||
}
|
boot_guest_memory,
|
||||||
|
hotplug_slots,
|
||||||
if !user_provided_zones && config.hotplug_method == HotplugMethod::Acpi {
|
next_memory_slot,
|
||||||
start_of_device_area = start_of_device_area
|
selected_slot,
|
||||||
.checked_add(hotplug_size)
|
next_hotplug_slot,
|
||||||
.ok_or(Error::GuestAddressOverFlow)?;
|
) = if let Some(data) = restore_data {
|
||||||
} else {
|
let (regions, memory_zones) =
|
||||||
// Alignment must be "natural" i.e. same as size of block
|
Self::restore_memory_regions_and_zones(&data.guest_ram_mappings, &zones, prefault)?;
|
||||||
let start_addr = GuestAddress(
|
let guest_memory =
|
||||||
(start_of_device_area.0 + virtio_devices::VIRTIO_MEM_ALIGN_SIZE - 1)
|
GuestMemoryMmap::from_arc_regions(regions).map_err(Error::GuestMemory)?;
|
||||||
/ virtio_devices::VIRTIO_MEM_ALIGN_SIZE
|
let boot_guest_memory = guest_memory.clone();
|
||||||
* virtio_devices::VIRTIO_MEM_ALIGN_SIZE,
|
(
|
||||||
);
|
GuestAddress(data.start_of_device_area),
|
||||||
|
data.boot_ram,
|
||||||
// When `prefault` is set by vm_restore, memory manager
|
data.current_ram,
|
||||||
// will create ram region with `prefault` option in
|
data.arch_mem_regions.clone(),
|
||||||
// restore config rather than same option in zone
|
memory_zones,
|
||||||
let region = MemoryManager::create_ram_region(
|
guest_memory,
|
||||||
&None,
|
boot_guest_memory,
|
||||||
0,
|
data.hotplug_slots.clone(),
|
||||||
start_addr,
|
data.next_memory_slot,
|
||||||
hotplug_size as usize,
|
data.selected_slot,
|
||||||
match prefault {
|
data.next_hotplug_slot,
|
||||||
Some(pf) => pf,
|
)
|
||||||
None => zone.prefault,
|
} else {
|
||||||
},
|
// Init guest memory
|
||||||
zone.shared,
|
let arch_mem_regions = arch::arch_memory_regions(ram_size);
|
||||||
zone.hugepages,
|
|
||||||
zone.hugepage_size,
|
let ram_regions: Vec<(GuestAddress, usize)> = arch_mem_regions
|
||||||
zone.host_numa_node,
|
.iter()
|
||||||
)?;
|
.filter(|r| r.2 == RegionType::Ram)
|
||||||
|
.map(|r| (r.0, r.1))
|
||||||
guest_memory = guest_memory
|
.collect();
|
||||||
.insert_region(Arc::clone(®ion))
|
|
||||||
.map_err(Error::GuestMemory)?;
|
let arch_mem_regions: Vec<ArchMemRegion> = arch_mem_regions
|
||||||
|
.iter()
|
||||||
let hotplugged_size = zone.hotplugged_size.unwrap_or(0);
|
.map(|(a, b, c)| ArchMemRegion {
|
||||||
let region_size = region.len();
|
base: a.0,
|
||||||
memory_zone.virtio_mem_zone = Some(VirtioMemZone {
|
size: *b,
|
||||||
region,
|
r_type: *c,
|
||||||
resize_handler: virtio_devices::Resize::new(hotplugged_size)
|
})
|
||||||
.map_err(Error::EventFdFail)?,
|
.collect();
|
||||||
hotplugged_size,
|
|
||||||
hugepages: zone.hugepages,
|
let (mem_regions, mut memory_zones) =
|
||||||
blocks_state: Arc::new(Mutex::new(BlocksState::new(region_size))),
|
Self::create_memory_regions_from_zones(&ram_regions, &zones, prefault)?;
|
||||||
});
|
|
||||||
|
let mut guest_memory =
|
||||||
start_of_device_area = start_addr
|
GuestMemoryMmap::from_arc_regions(mem_regions).map_err(Error::GuestMemory)?;
|
||||||
.checked_add(hotplug_size)
|
|
||||||
.ok_or(Error::GuestAddressOverFlow)?;
|
let boot_guest_memory = guest_memory.clone();
|
||||||
|
|
||||||
|
let mut start_of_device_area =
|
||||||
|
MemoryManager::start_addr(guest_memory.last_addr(), allow_mem_hotplug)?;
|
||||||
|
|
||||||
|
// Update list of memory zones for resize.
|
||||||
|
for zone in zones.iter() {
|
||||||
|
if let Some(memory_zone) = memory_zones.get_mut(&zone.id) {
|
||||||
|
if let Some(hotplug_size) = zone.hotplug_size {
|
||||||
|
if hotplug_size == 0 {
|
||||||
|
error!("'hotplug_size' can't be 0");
|
||||||
|
return Err(Error::InvalidHotplugSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
if !user_provided_zones && config.hotplug_method == HotplugMethod::Acpi {
|
||||||
|
start_of_device_area = start_of_device_area
|
||||||
|
.checked_add(hotplug_size)
|
||||||
|
.ok_or(Error::GuestAddressOverFlow)?;
|
||||||
|
} else {
|
||||||
|
// Alignment must be "natural" i.e. same as size of block
|
||||||
|
let start_addr = GuestAddress(
|
||||||
|
(start_of_device_area.0 + virtio_devices::VIRTIO_MEM_ALIGN_SIZE
|
||||||
|
- 1)
|
||||||
|
/ virtio_devices::VIRTIO_MEM_ALIGN_SIZE
|
||||||
|
* virtio_devices::VIRTIO_MEM_ALIGN_SIZE,
|
||||||
|
);
|
||||||
|
|
||||||
|
// When `prefault` is set by vm_restore, memory manager
|
||||||
|
// will create ram region with `prefault` option in
|
||||||
|
// restore config rather than same option in zone
|
||||||
|
let region = MemoryManager::create_ram_region(
|
||||||
|
&None,
|
||||||
|
0,
|
||||||
|
start_addr,
|
||||||
|
hotplug_size as usize,
|
||||||
|
match prefault {
|
||||||
|
Some(pf) => pf,
|
||||||
|
None => zone.prefault,
|
||||||
|
},
|
||||||
|
zone.shared,
|
||||||
|
zone.hugepages,
|
||||||
|
zone.hugepage_size,
|
||||||
|
zone.host_numa_node,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
guest_memory = guest_memory
|
||||||
|
.insert_region(Arc::clone(®ion))
|
||||||
|
.map_err(Error::GuestMemory)?;
|
||||||
|
|
||||||
|
let hotplugged_size = zone.hotplugged_size.unwrap_or(0);
|
||||||
|
let region_size = region.len();
|
||||||
|
memory_zone.virtio_mem_zone = Some(VirtioMemZone {
|
||||||
|
region,
|
||||||
|
resize_handler: virtio_devices::Resize::new(hotplugged_size)
|
||||||
|
.map_err(Error::EventFdFail)?,
|
||||||
|
hotplugged_size,
|
||||||
|
hugepages: zone.hugepages,
|
||||||
|
blocks_state: Arc::new(Mutex::new(BlocksState::new(region_size))),
|
||||||
|
});
|
||||||
|
|
||||||
|
start_of_device_area = start_addr
|
||||||
|
.checked_add(hotplug_size)
|
||||||
|
.ok_or(Error::GuestAddressOverFlow)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
return Err(Error::MissingZoneIdentifier);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return Err(Error::MissingZoneIdentifier);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
let mut hotplug_slots = Vec::with_capacity(HOTPLUG_COUNT);
|
||||||
|
hotplug_slots.resize_with(HOTPLUG_COUNT, HotPlugState::default);
|
||||||
|
|
||||||
|
(
|
||||||
|
start_of_device_area,
|
||||||
|
ram_size,
|
||||||
|
ram_size,
|
||||||
|
arch_mem_regions,
|
||||||
|
memory_zones,
|
||||||
|
guest_memory,
|
||||||
|
boot_guest_memory,
|
||||||
|
hotplug_slots,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
let guest_memory = GuestMemoryAtomic::new(guest_memory);
|
let guest_memory = GuestMemoryAtomic::new(guest_memory);
|
||||||
|
|
||||||
let mut hotplug_slots = Vec::with_capacity(HOTPLUG_COUNT);
|
|
||||||
hotplug_slots.resize_with(HOTPLUG_COUNT, HotPlugState::default);
|
|
||||||
|
|
||||||
// Both MMIO and PIO address spaces start at address 0.
|
// Both MMIO and PIO address spaces start at address 0.
|
||||||
let allocator = Arc::new(Mutex::new(
|
let allocator = Arc::new(Mutex::new(
|
||||||
SystemAllocator::new(
|
SystemAllocator::new(
|
||||||
@ -967,18 +1018,18 @@ impl MemoryManager {
|
|||||||
let mut memory_manager = MemoryManager {
|
let mut memory_manager = MemoryManager {
|
||||||
boot_guest_memory,
|
boot_guest_memory,
|
||||||
guest_memory,
|
guest_memory,
|
||||||
next_memory_slot: 0,
|
next_memory_slot,
|
||||||
start_of_device_area,
|
start_of_device_area,
|
||||||
end_of_device_area,
|
end_of_device_area,
|
||||||
vm,
|
vm,
|
||||||
hotplug_slots,
|
hotplug_slots,
|
||||||
selected_slot: 0,
|
selected_slot,
|
||||||
mergeable: config.mergeable,
|
mergeable: config.mergeable,
|
||||||
allocator,
|
allocator,
|
||||||
hotplug_method: config.hotplug_method.clone(),
|
hotplug_method: config.hotplug_method.clone(),
|
||||||
boot_ram: ram_size,
|
boot_ram,
|
||||||
current_ram: ram_size,
|
current_ram,
|
||||||
next_hotplug_slot: 0,
|
next_hotplug_slot,
|
||||||
shared: config.shared,
|
shared: config.shared,
|
||||||
hugepages: config.hugepages,
|
hugepages: config.hugepages,
|
||||||
hugepage_size: config.hugepage_size,
|
hugepage_size: config.hugepage_size,
|
||||||
@ -1008,15 +1059,6 @@ impl MemoryManager {
|
|||||||
prefault: bool,
|
prefault: bool,
|
||||||
phys_bits: u8,
|
phys_bits: u8,
|
||||||
) -> Result<Arc<Mutex<MemoryManager>>, Error> {
|
) -> Result<Arc<Mutex<MemoryManager>>, Error> {
|
||||||
let mm = MemoryManager::new(
|
|
||||||
vm,
|
|
||||||
config,
|
|
||||||
Some(prefault),
|
|
||||||
phys_bits,
|
|
||||||
#[cfg(feature = "tdx")]
|
|
||||||
false,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
if let Some(source_url) = source_url {
|
if let Some(source_url) = source_url {
|
||||||
let mut memory_file_path = url_to_path(source_url).map_err(Error::Restore)?;
|
let mut memory_file_path = url_to_path(source_url).map_err(Error::Restore)?;
|
||||||
memory_file_path.push(String::from(SNAPSHOT_FILENAME));
|
memory_file_path.push(String::from(SNAPSHOT_FILENAME));
|
||||||
@ -1025,12 +1067,24 @@ impl MemoryManager {
|
|||||||
.to_versioned_state(MEMORY_MANAGER_SNAPSHOT_ID)
|
.to_versioned_state(MEMORY_MANAGER_SNAPSHOT_ID)
|
||||||
.map_err(Error::Restore)?;
|
.map_err(Error::Restore)?;
|
||||||
|
|
||||||
|
let mm = MemoryManager::new(
|
||||||
|
vm,
|
||||||
|
config,
|
||||||
|
Some(prefault),
|
||||||
|
phys_bits,
|
||||||
|
#[cfg(feature = "tdx")]
|
||||||
|
false,
|
||||||
|
None,
|
||||||
|
)?;
|
||||||
|
|
||||||
mm.lock()
|
mm.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.fill_saved_regions(memory_file_path, mem_snapshot.memory_ranges)?;
|
.fill_saved_regions(memory_file_path, mem_snapshot.memory_ranges)?;
|
||||||
}
|
|
||||||
|
|
||||||
Ok(mm)
|
Ok(mm)
|
||||||
|
} else {
|
||||||
|
Err(Error::RestoreMissingSourceUrl)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn memfd_create(name: &ffi::CStr, flags: u32) -> Result<RawFd, io::Error> {
|
fn memfd_create(name: &ffi::CStr, flags: u32) -> Result<RawFd, io::Error> {
|
||||||
|
@ -750,6 +750,7 @@ impl Vm {
|
|||||||
phys_bits,
|
phys_bits,
|
||||||
#[cfg(feature = "tdx")]
|
#[cfg(feature = "tdx")]
|
||||||
tdx_enabled,
|
tdx_enabled,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.map_err(Error::MemoryManager)?;
|
.map_err(Error::MemoryManager)?;
|
||||||
|
|
||||||
@ -866,6 +867,7 @@ impl Vm {
|
|||||||
phys_bits,
|
phys_bits,
|
||||||
#[cfg(feature = "tdx")]
|
#[cfg(feature = "tdx")]
|
||||||
false,
|
false,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.map_err(Error::MemoryManager)?;
|
.map_err(Error::MemoryManager)?;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user