From 4e1b78e1ffc70ee0048f74d30fd684c6ab5f4496 Mon Sep 17 00:00:00 2001 From: Sebastien Boeuf Date: Mon, 14 Sep 2020 20:23:45 +0200 Subject: [PATCH] vmm: Add 'hotplugged_size' to memory parameters Add the new option 'hotplugged_size' to both --memory-zone and --memory parameters so that we can let the user specify a certain amount of memory being plugged at boot. This is also part of making sure we can store the virtio-mem size over a reboot of the VM. Signed-off-by: Sebastien Boeuf --- docs/memory.md | 49 ++++++++++++++++++++- src/main.rs | 7 ++- vmm/src/api/openapi/cloud-hypervisor.yaml | 6 +++ vmm/src/config.rs | 20 ++++++++- vmm/src/memory_manager.rs | 53 +++++++++++++++++++++++ 5 files changed, 130 insertions(+), 5 deletions(-) diff --git a/docs/memory.md b/docs/memory.md index 24f6b00ce..7b80f79f3 100644 --- a/docs/memory.md +++ b/docs/memory.md @@ -17,6 +17,7 @@ struct MemoryConfig { hugepages: bool, hotplug_method: HotplugMethod, hotplug_size: Option, + hotplugged_size: Option, balloon: bool, balloon_size: u64, zones: Option>, @@ -24,7 +25,7 @@ struct MemoryConfig { ``` ``` ---memory Memory parameters "size=,mergeable=on|off,shared=on|off,hugepages=on|off,hotplug_method=acpi|virtio-mem,hotplug_size=,balloon=on|off" +--memory Memory parameters "size=,mergeable=on|off,shared=on|off,hugepages=on|off,hotplug_method=acpi|virtio-mem,hotplug_size=,hotplugged_size=,balloon=on|off" ``` ### `size` @@ -120,6 +121,27 @@ _Example_ --memory size=1G,hotplug_size=1G ``` +### `hotplugged_size` + +Amount of memory that will be dynamically added to the VM at boot. This option +allows for starting a VM with a certain amount of memory that can be reduced +during runtime. + +This is only valid when the `hotplug_method` is `virtio-mem` as it does not +make sense for the `acpi` use case. When using ACPI, the memory can't be +resized after it has been extended. + +This option is only valid when `hotplug_size` is specified, and its value can't +exceed the value of `hotplug_size`. + +Value is an unsigned integer of 64 bits. A value of 0 is invalid. + +_Example_ + +``` +--memory size=1G,hotplug_method=virtio-mem,hotplug_size=1G,hotplugged_size=512M +``` + ### `balloon` Specifies if the `virtio-balloon` device must be activated. This creates a @@ -149,11 +171,12 @@ struct MemoryZoneConfig { hugepages: bool, host_numa_node: Option, hotplug_size: Option, + hotplugged_size: Option, } ``` ``` ---memory-zone User defined memory zone parameters "size=,file=,shared=on|off,hugepages=on|off,host_numa_node=,id=,hotplug_size=" +--memory-zone User defined memory zone parameters "size=,file=,shared=on|off,hugepages=on|off,host_numa_node=,id=,hotplug_size=,hotplugged_size=" ``` This parameter expects one or more occurences, allowing for a list of memory @@ -303,6 +326,28 @@ _Example_ --memory-zone id=mem0,size=1G,hotplug_size=1G ``` +### `hotplugged_size` + +Amount of memory that will be dynamically added to a memory zone at VM's boot. +This option allows for starting a VM with a certain amount of memory that can +be reduced during runtime. + +This is only valid when the `hotplug_method` is `virtio-mem` as it does not +make sense for the `acpi` use case. When using ACPI, the memory can't be +resized after it has been extended. + +This option is only valid when `hotplug_size` is specified, and its value can't +exceed the value of `hotplug_size`. + +Value is an unsigned integer of 64 bits. A value of 0 is invalid. + +_Example_ + +``` +--memory size=0,hotplug_method=virtio-mem +--memory-zone id=mem0,size=1G,hotplug_size=1G,hotplugged_size=512M +``` + ## NUMA settings `NumaConfig` or what is known as `--numa` from the CLI perspective has been diff --git a/src/main.rs b/src/main.rs index aab26c1da..62664d7ae 100644 --- a/src/main.rs +++ b/src/main.rs @@ -109,7 +109,8 @@ fn create_app<'a, 'b>( "Memory parameters \ \"size=,mergeable=on|off,shared=on|off,hugepages=on|off,\ hotplug_method=acpi|virtio-mem,\ - hotplug_size=\"", + hotplug_size=,\ + hotplugged_size=\"", ) .default_value(&default_memory) .group("vm-config"), @@ -121,7 +122,8 @@ fn create_app<'a, 'b>( "User defined memory zone parameters \ \"size=,file=,\ shared=on|off,hugepages=on|off,host_numa_node=,\ - id=,hotplug_size=\"", + id=,hotplug_size=,\ + hotplugged_size=\"", ) .takes_value(true) .min_values(1) @@ -539,6 +541,7 @@ mod unit_tests { mergeable: false, hotplug_method: HotplugMethod::Acpi, hotplug_size: None, + hotplugged_size: None, shared: false, hugepages: false, balloon: false, diff --git a/vmm/src/api/openapi/cloud-hypervisor.yaml b/vmm/src/api/openapi/cloud-hypervisor.yaml index ca1a6ee09..138378127 100644 --- a/vmm/src/api/openapi/cloud-hypervisor.yaml +++ b/vmm/src/api/openapi/cloud-hypervisor.yaml @@ -496,6 +496,9 @@ components: hotplug_size: type: integer format: int64 + hotplugged_size: + type: integer + format: int64 MemoryConfig: required: @@ -509,6 +512,9 @@ components: hotplug_size: type: integer format: int64 + hotplugged_size: + type: integer + format: int64 mergeable: type: boolean default: false diff --git a/vmm/src/config.rs b/vmm/src/config.rs index 7ca56af71..c2c496543 100644 --- a/vmm/src/config.rs +++ b/vmm/src/config.rs @@ -381,6 +381,8 @@ pub struct MemoryZoneConfig { pub host_numa_node: Option, #[serde(default)] pub hotplug_size: Option, + #[serde(default)] + pub hotplugged_size: Option, } #[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] @@ -393,6 +395,8 @@ pub struct MemoryConfig { #[serde(default)] pub hotplug_size: Option, #[serde(default)] + pub hotplugged_size: Option, + #[serde(default)] pub shared: bool, #[serde(default)] pub hugepages: bool, @@ -413,6 +417,7 @@ impl MemoryConfig { .add("mergeable") .add("hotplug_method") .add("hotplug_size") + .add("hotplugged_size") .add("shared") .add("hugepages") .add("balloon"); @@ -436,6 +441,10 @@ impl MemoryConfig { .convert::("hotplug_size") .map_err(Error::ParseMemory)? .map(|v| v.0); + let hotplugged_size = parser + .convert::("hotplugged_size") + .map_err(Error::ParseMemory)? + .map(|v| v.0); let shared = parser .convert::("shared") .map_err(Error::ParseMemory)? @@ -463,7 +472,8 @@ impl MemoryConfig { .add("shared") .add("hugepages") .add("host_numa_node") - .add("hotplug_size"); + .add("hotplug_size") + .add("hotplugged_size"); parser.parse(memory_zone).map_err(Error::ParseMemoryZone)?; let id = parser.get("id").ok_or(Error::ParseMemoryZoneIdMissing)?; @@ -490,6 +500,10 @@ impl MemoryConfig { .convert::("hotplug_size") .map_err(Error::ParseMemoryZone)? .map(|v| v.0); + let hotplugged_size = parser + .convert::("hotplugged_size") + .map_err(Error::ParseMemoryZone)? + .map(|v| v.0); zones.push(MemoryZoneConfig { id, @@ -499,6 +513,7 @@ impl MemoryConfig { hugepages, host_numa_node, hotplug_size, + hotplugged_size, }); } Some(zones) @@ -511,6 +526,7 @@ impl MemoryConfig { mergeable, hotplug_method, hotplug_size, + hotplugged_size, shared, hugepages, balloon, @@ -527,6 +543,7 @@ impl Default for MemoryConfig { mergeable: false, hotplug_method: HotplugMethod::Acpi, hotplug_size: None, + hotplugged_size: None, shared: false, hugepages: false, balloon: false, @@ -2118,6 +2135,7 @@ mod tests { mergeable: false, hotplug_method: HotplugMethod::Acpi, hotplug_size: None, + hotplugged_size: None, shared: false, hugepages: false, balloon: false, diff --git a/vmm/src/memory_manager.rs b/vmm/src/memory_manager.rs index 3bdb1ba6c..7d9d9d092 100644 --- a/vmm/src/memory_manager.rs +++ b/vmm/src/memory_manager.rs @@ -440,6 +440,32 @@ impl MemoryManager { return Err(Error::InvalidMemoryParameters); } + if let Some(hotplugged_size) = config.hotplugged_size { + if let Some(hotplug_size) = config.hotplug_size { + if hotplugged_size > hotplug_size { + error!( + "'hotplugged_size' {} can't be bigger than \ + 'hotplug_size' {}", + hotplugged_size, hotplug_size, + ); + return Err(Error::InvalidMemoryParameters); + } + } else { + error!( + "Invalid to define 'hotplugged_size' when there is\ + no 'hotplug_size'" + ); + return Err(Error::InvalidMemoryParameters); + } + if config.hotplug_method == HotplugMethod::Acpi { + error!( + "Invalid to define 'hotplugged_size' with hotplug \ + method 'acpi'" + ); + return Err(Error::InvalidMemoryParameters); + } + } + // Create a single zone from the global memory config. This lets // us reuse the codepath for user defined memory zones. let zones = vec![MemoryZoneConfig { @@ -450,6 +476,7 @@ impl MemoryManager { hugepages: config.hugepages, host_numa_node: None, hotplug_size: config.hotplug_size, + hotplugged_size: config.hotplugged_size, }]; (config.size, zones) @@ -485,6 +512,32 @@ impl MemoryManager { error!("Invalid to set ACPI hotplug method for memory zones"); return Err(Error::InvalidHotplugMethodWithMemoryZones); } + + if let Some(hotplugged_size) = zone.hotplugged_size { + if let Some(hotplug_size) = zone.hotplug_size { + if hotplugged_size > hotplug_size { + error!( + "'hotplugged_size' {} can't be bigger than \ + 'hotplug_size' {}", + hotplugged_size, hotplug_size, + ); + return Err(Error::InvalidMemoryParameters); + } + } else { + error!( + "Invalid to define 'hotplugged_size' when there is\ + no 'hotplug_size' for a memory zone" + ); + return Err(Error::InvalidMemoryParameters); + } + if config.hotplug_method == HotplugMethod::Acpi { + error!( + "Invalid to define 'hotplugged_size' with hotplug \ + method 'acpi'" + ); + return Err(Error::InvalidMemoryParameters); + } + } } (total_ram_size, zones)