mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
vmm: Prepare code to accept multiple virtio-mem devices
Both MemoryManager and DeviceManager are updated through this commit to handle the creation of multiple virtio-mem devices if needed. For now, only the framework is in place, but the behavior remains the same, which means only the memory zone created from '--memory' generates a virtio-mem region that can be used for resize. Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
+31
-26
@@ -110,7 +110,7 @@ const SERIAL_DEVICE_NAME_PREFIX: &str = "_serial";
|
|||||||
const CONSOLE_DEVICE_NAME: &str = "_console";
|
const CONSOLE_DEVICE_NAME: &str = "_console";
|
||||||
const DISK_DEVICE_NAME_PREFIX: &str = "_disk";
|
const DISK_DEVICE_NAME_PREFIX: &str = "_disk";
|
||||||
const FS_DEVICE_NAME_PREFIX: &str = "_fs";
|
const FS_DEVICE_NAME_PREFIX: &str = "_fs";
|
||||||
const MEM_DEVICE_NAME: &str = "_mem";
|
const MEM_DEVICE_NAME_PREFIX: &str = "_mem";
|
||||||
const BALLOON_DEVICE_NAME: &str = "_balloon";
|
const BALLOON_DEVICE_NAME: &str = "_balloon";
|
||||||
const NET_DEVICE_NAME_PREFIX: &str = "_net";
|
const NET_DEVICE_NAME_PREFIX: &str = "_net";
|
||||||
const PMEM_DEVICE_NAME_PREFIX: &str = "_pmem";
|
const PMEM_DEVICE_NAME_PREFIX: &str = "_pmem";
|
||||||
@@ -2419,34 +2419,39 @@ impl DeviceManager {
|
|||||||
|
|
||||||
let mm = self.memory_manager.clone();
|
let mm = self.memory_manager.clone();
|
||||||
let mm = mm.lock().unwrap();
|
let mm = mm.lock().unwrap();
|
||||||
if let (Some(region), Some(resize)) = (&mm.virtiomem_region, &mm.virtiomem_resize) {
|
for (_, memory_zone) in mm.memory_zones().iter() {
|
||||||
let id = String::from(MEM_DEVICE_NAME);
|
if let (Some(region), Some(resize)) = (
|
||||||
|
memory_zone.virtiomem_region(),
|
||||||
|
memory_zone.virtiomem_resize(),
|
||||||
|
) {
|
||||||
|
let id = self.next_device_name(MEM_DEVICE_NAME_PREFIX)?;
|
||||||
|
|
||||||
let virtio_mem_device = Arc::new(Mutex::new(
|
let virtio_mem_device = Arc::new(Mutex::new(
|
||||||
virtio_devices::Mem::new(
|
virtio_devices::Mem::new(
|
||||||
|
id.clone(),
|
||||||
|
®ion,
|
||||||
|
resize
|
||||||
|
.try_clone()
|
||||||
|
.map_err(DeviceManagerError::TryCloneVirtioMemResize)?,
|
||||||
|
self.seccomp_action.clone(),
|
||||||
|
)
|
||||||
|
.map_err(DeviceManagerError::CreateVirtioMem)?,
|
||||||
|
));
|
||||||
|
|
||||||
|
devices.push((
|
||||||
|
Arc::clone(&virtio_mem_device) as VirtioDeviceArc,
|
||||||
|
false,
|
||||||
id.clone(),
|
id.clone(),
|
||||||
®ion,
|
));
|
||||||
resize
|
|
||||||
.try_clone()
|
|
||||||
.map_err(DeviceManagerError::TryCloneVirtioMemResize)?,
|
|
||||||
self.seccomp_action.clone(),
|
|
||||||
)
|
|
||||||
.map_err(DeviceManagerError::CreateVirtioMem)?,
|
|
||||||
));
|
|
||||||
|
|
||||||
devices.push((
|
// Fill the device tree with a new node. In case of restore, we
|
||||||
Arc::clone(&virtio_mem_device) as VirtioDeviceArc,
|
// know there is nothing to do, so we can simply override the
|
||||||
false,
|
// existing entry.
|
||||||
id.clone(),
|
self.device_tree
|
||||||
));
|
.lock()
|
||||||
|
.unwrap()
|
||||||
// Fill the device tree with a new node. In case of restore, we
|
.insert(id.clone(), device_node!(id, virtio_mem_device));
|
||||||
// know there is nothing to do, so we can simply override the
|
}
|
||||||
// existing entry.
|
|
||||||
self.device_tree
|
|
||||||
.lock()
|
|
||||||
.unwrap()
|
|
||||||
.insert(id.clone(), device_node!(id, virtio_mem_device));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(devices)
|
Ok(devices)
|
||||||
|
|||||||
+77
-42
@@ -99,8 +99,6 @@ pub struct MemoryManager {
|
|||||||
boot_ram: u64,
|
boot_ram: u64,
|
||||||
current_ram: u64,
|
current_ram: u64,
|
||||||
next_hotplug_slot: usize,
|
next_hotplug_slot: usize,
|
||||||
pub virtiomem_region: Option<Arc<GuestRegionMmap>>,
|
|
||||||
pub virtiomem_resize: Option<virtio_devices::Resize>,
|
|
||||||
snapshot: Mutex<Option<GuestMemoryLoadGuard<GuestMemoryMmap>>>,
|
snapshot: Mutex<Option<GuestMemoryLoadGuard<GuestMemoryMmap>>>,
|
||||||
shared: bool,
|
shared: bool,
|
||||||
hugepages: bool,
|
hugepages: bool,
|
||||||
@@ -205,6 +203,18 @@ pub enum Error {
|
|||||||
|
|
||||||
/// Memory zone identifier is not unique.
|
/// Memory zone identifier is not unique.
|
||||||
DuplicateZoneId,
|
DuplicateZoneId,
|
||||||
|
|
||||||
|
/// No virtio-mem resizing handler found.
|
||||||
|
MissingVirtioMemHandler,
|
||||||
|
|
||||||
|
/// No default memory zone found.
|
||||||
|
MissingDefaultMemoryZone,
|
||||||
|
|
||||||
|
/// Failed getting the expected amount of memory zones.
|
||||||
|
InvalidNumberOfMemoryZones,
|
||||||
|
|
||||||
|
/// Invalid size for resizing. Can be anything except 0.
|
||||||
|
InvalidHotplugSize,
|
||||||
}
|
}
|
||||||
|
|
||||||
const ENABLE_FLAG: usize = 0;
|
const ENABLE_FLAG: usize = 0;
|
||||||
@@ -476,7 +486,7 @@ impl MemoryManager {
|
|||||||
.map(|r| (r.0, r.1))
|
.map(|r| (r.0, r.1))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let (mem_regions, memory_zones) =
|
let (mem_regions, mut memory_zones) =
|
||||||
Self::create_memory_regions_from_zones(&ram_regions, &zones, prefault, ext_regions)?;
|
Self::create_memory_regions_from_zones(&ram_regions, &zones, prefault, ext_regions)?;
|
||||||
|
|
||||||
let guest_memory =
|
let guest_memory =
|
||||||
@@ -485,37 +495,55 @@ 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 = MemoryManager::start_addr(guest_memory.last_addr(), false);
|
let mut start_of_device_area = MemoryManager::start_addr(guest_memory.last_addr(), false);
|
||||||
|
let mut virtiomem_regions: Vec<Arc<GuestRegionMmap>> = Vec::new();
|
||||||
|
|
||||||
let mut virtiomem_region = None;
|
if !use_zones {
|
||||||
let mut virtiomem_resize = None;
|
if memory_zones.len() != 1 {
|
||||||
if let Some(size) = config.hotplug_size {
|
return Err(Error::InvalidNumberOfMemoryZones);
|
||||||
if config.hotplug_method == HotplugMethod::VirtioMem {
|
}
|
||||||
// Alignment must be "natural" i.e. same as size of block
|
|
||||||
let start_addr = GuestAddress(
|
|
||||||
(start_of_device_area.0 + virtio_devices::VIRTIO_MEM_DEFAULT_BLOCK_SIZE - 1)
|
|
||||||
/ virtio_devices::VIRTIO_MEM_DEFAULT_BLOCK_SIZE
|
|
||||||
* virtio_devices::VIRTIO_MEM_DEFAULT_BLOCK_SIZE,
|
|
||||||
);
|
|
||||||
|
|
||||||
if !use_zones {
|
if let Some(memory_zone) = memory_zones.get_mut(DEFAULT_MEMORY_ZONE) {
|
||||||
virtiomem_region = Some(MemoryManager::create_ram_region(
|
if let Some(size) = config.hotplug_size {
|
||||||
&None,
|
if size == 0 {
|
||||||
0,
|
error!("'hotplug_size' can't be 0");
|
||||||
start_addr,
|
return Err(Error::InvalidHotplugSize);
|
||||||
size as usize,
|
}
|
||||||
false,
|
|
||||||
config.shared,
|
if config.hotplug_method == HotplugMethod::VirtioMem {
|
||||||
config.hugepages,
|
// Alignment must be "natural" i.e. same as size of block
|
||||||
None,
|
let start_addr = GuestAddress(
|
||||||
&None,
|
(start_of_device_area.0
|
||||||
)?);
|
+ virtio_devices::VIRTIO_MEM_DEFAULT_BLOCK_SIZE
|
||||||
|
- 1)
|
||||||
|
/ virtio_devices::VIRTIO_MEM_DEFAULT_BLOCK_SIZE
|
||||||
|
* virtio_devices::VIRTIO_MEM_DEFAULT_BLOCK_SIZE,
|
||||||
|
);
|
||||||
|
|
||||||
|
let region = MemoryManager::create_ram_region(
|
||||||
|
&None,
|
||||||
|
0,
|
||||||
|
start_addr,
|
||||||
|
size as usize,
|
||||||
|
false,
|
||||||
|
config.shared,
|
||||||
|
config.hugepages,
|
||||||
|
None,
|
||||||
|
&None,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
virtiomem_regions.push(region.clone());
|
||||||
|
|
||||||
|
memory_zone.virtiomem_region = Some(region);
|
||||||
|
memory_zone.virtiomem_resize =
|
||||||
|
Some(virtio_devices::Resize::new().map_err(Error::EventFdFail)?);
|
||||||
|
|
||||||
|
start_of_device_area = start_addr.unchecked_add(size);
|
||||||
|
} else {
|
||||||
|
start_of_device_area = start_of_device_area.unchecked_add(size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtiomem_resize = Some(virtio_devices::Resize::new().map_err(Error::EventFdFail)?);
|
|
||||||
|
|
||||||
start_of_device_area = start_addr.unchecked_add(size);
|
|
||||||
} else {
|
} else {
|
||||||
start_of_device_area = start_of_device_area.unchecked_add(size);
|
return Err(Error::MissingDefaultMemoryZone);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -558,8 +586,6 @@ impl MemoryManager {
|
|||||||
boot_ram: config.size,
|
boot_ram: config.size,
|
||||||
current_ram: config.size,
|
current_ram: config.size,
|
||||||
next_hotplug_slot: 0,
|
next_hotplug_slot: 0,
|
||||||
virtiomem_region: virtiomem_region.clone(),
|
|
||||||
virtiomem_resize,
|
|
||||||
snapshot: Mutex::new(None),
|
snapshot: Mutex::new(None),
|
||||||
shared: config.shared,
|
shared: config.shared,
|
||||||
hugepages: config.hugepages,
|
hugepages: config.hugepages,
|
||||||
@@ -582,7 +608,7 @@ impl MemoryManager {
|
|||||||
Ok(())
|
Ok(())
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
if let Some(region) = virtiomem_region {
|
for region in virtiomem_regions.iter() {
|
||||||
memory_manager.lock().unwrap().create_userspace_mapping(
|
memory_manager.lock().unwrap().create_userspace_mapping(
|
||||||
region.start_addr().raw_value(),
|
region.start_addr().raw_value(),
|
||||||
region.len() as u64,
|
region.len() as u64,
|
||||||
@@ -1089,18 +1115,27 @@ impl MemoryManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn virtiomem_resize(&mut self, size: u64) -> Result<(), Error> {
|
pub fn virtiomem_resize(&mut self, size: u64) -> Result<(), Error> {
|
||||||
let region = self.virtiomem_region.take();
|
let virtiomem_region =
|
||||||
if let Some(region) = region {
|
if let Some(memory_zone) = self.memory_zones.get_mut(DEFAULT_MEMORY_ZONE) {
|
||||||
self.add_region(region)?;
|
if let Some(resize) = &memory_zone.virtiomem_resize {
|
||||||
}
|
resize.work(size).map_err(Error::VirtioMemResizeFail)?;
|
||||||
|
} else {
|
||||||
|
error!("Failed resizing virtio-mem region: No virtio-mem handler");
|
||||||
|
return Err(Error::MissingVirtioMemHandler);
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(resize) = &self.virtiomem_resize {
|
memory_zone.virtiomem_region.take()
|
||||||
resize.work(size).map_err(Error::VirtioMemResizeFail)?;
|
} else {
|
||||||
|
error!("Failed resizing virtio-mem region: No default memory zone");
|
||||||
|
return Err(Error::MissingDefaultMemoryZone);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add the region if that's the first time we resize.
|
||||||
|
if let Some(region) = virtiomem_region {
|
||||||
|
self.add_region(region)
|
||||||
} else {
|
} else {
|
||||||
panic!("should not fail here");
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn balloon_resize(&mut self, expected_ram: u64) -> Result<u64, Error> {
|
pub fn balloon_resize(&mut self, expected_ram: u64) -> Result<u64, Error> {
|
||||||
|
|||||||
Reference in New Issue
Block a user