vmm: Add virtio-balloon support

This commit adds new option balloon to memory config.
Set it to on will open the balloon function.

Signed-off-by: Hui Zhu <teawater@antfin.com>
This commit is contained in:
Hui Zhu 2020-03-20 11:43:37 +08:00 committed by Rob Bradford
parent 0d72aa782f
commit 8b6b97b86f
4 changed files with 79 additions and 1 deletions

View File

@ -502,6 +502,7 @@ mod unit_tests {
hotplug_size: None, hotplug_size: None,
shared: false, shared: false,
hugepages: false, hugepages: false,
balloon: false,
}, },
kernel: Some(KernelConfig { kernel: Some(KernelConfig {
path: PathBuf::from("/path/to/kernel"), path: PathBuf::from("/path/to/kernel"),

View File

@ -338,6 +338,8 @@ pub struct MemoryConfig {
pub shared: bool, pub shared: bool,
#[serde(default)] #[serde(default)]
pub hugepages: bool, pub hugepages: bool,
#[serde(default)]
pub balloon: bool,
} }
impl MemoryConfig { impl MemoryConfig {
@ -350,7 +352,8 @@ impl MemoryConfig {
.add("hotplug_method") .add("hotplug_method")
.add("hotplug_size") .add("hotplug_size")
.add("shared") .add("shared")
.add("hugepages"); .add("hugepages")
.add("balloon");
parser.parse(memory).map_err(Error::ParseMemory)?; parser.parse(memory).map_err(Error::ParseMemory)?;
let size = parser let size = parser
@ -382,6 +385,11 @@ impl MemoryConfig {
.map_err(Error::ParseMemory)? .map_err(Error::ParseMemory)?
.unwrap_or(Toggle(false)) .unwrap_or(Toggle(false))
.0; .0;
let balloon = parser
.convert::<Toggle>("balloon")
.map_err(Error::ParseMemory)?
.unwrap_or(Toggle(false))
.0;
Ok(MemoryConfig { Ok(MemoryConfig {
size, size,
@ -391,6 +399,7 @@ impl MemoryConfig {
hotplug_size, hotplug_size,
shared, shared,
hugepages, hugepages,
balloon,
}) })
} }
} }
@ -405,6 +414,7 @@ impl Default for MemoryConfig {
hotplug_size: None, hotplug_size: None,
shared: false, shared: false,
hugepages: false, hugepages: false,
balloon: false,
} }
} }
} }
@ -1862,6 +1872,7 @@ mod tests {
hotplug_size: None, hotplug_size: None,
shared: false, shared: false,
hugepages: false, hugepages: false,
balloon: false,
}, },
kernel: Some(KernelConfig { kernel: Some(KernelConfig {
path: PathBuf::from("/path/to/kernel"), path: PathBuf::from("/path/to/kernel"),

View File

@ -104,6 +104,7 @@ 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: &str = "_mem";
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";
const RNG_DEVICE_NAME: &str = "_rng"; const RNG_DEVICE_NAME: &str = "_rng";
@ -165,6 +166,9 @@ pub enum DeviceManagerError {
/// Cannot create virtio-iommu device /// Cannot create virtio-iommu device
CreateVirtioIommu(io::Error), CreateVirtioIommu(io::Error),
/// Cannot create virtio-balloon device
CreateVirtioBalloon(io::Error),
/// Failed parsing disk image format /// Failed parsing disk image format
DetectImageType(qcow::Error), DetectImageType(qcow::Error),
@ -1500,6 +1504,9 @@ impl DeviceManager {
devices.append(&mut self.make_virtio_mem_devices()?); devices.append(&mut self.make_virtio_mem_devices()?);
// Add virtio-balloon if required
devices.append(&mut self.make_virtio_balloon_devices()?);
Ok(devices) Ok(devices)
} }
@ -2293,6 +2300,39 @@ impl DeviceManager {
Ok(devices) Ok(devices)
} }
fn make_virtio_balloon_devices(
&mut self,
) -> DeviceManagerResult<Vec<(VirtioDeviceArc, bool, String)>> {
let mut devices = Vec::new();
if self.config.lock().unwrap().memory.balloon {
let id = String::from(BALLOON_DEVICE_NAME);
let virtio_balloon_device = Arc::new(Mutex::new(
virtio_devices::Balloon::new(id.clone())
.map_err(DeviceManagerError::CreateVirtioBalloon)?,
));
self.memory_manager
.lock()
.unwrap()
.set_balloon(virtio_balloon_device.clone());
devices.push((
Arc::clone(&virtio_balloon_device) as VirtioDeviceArc,
false,
id.clone(),
));
self.device_tree
.lock()
.unwrap()
.insert(id.clone(), device_node!(id, virtio_balloon_device));
}
Ok(devices)
}
#[cfg(feature = "pci_support")] #[cfg(feature = "pci_support")]
fn create_kvm_device(vm: &Arc<dyn hypervisor::Vm>) -> DeviceManagerResult<DeviceFd> { fn create_kvm_device(vm: &Arc<dyn hypervisor::Vm>) -> DeviceManagerResult<DeviceFd> {
let mut vfio_dev = hypervisor::kvm::kvm_create_device { let mut vfio_dev = hypervisor::kvm::kvm_create_device {

View File

@ -70,6 +70,7 @@ pub struct MemoryManager {
snapshot: Mutex<Option<GuestMemoryLoadGuard<GuestMemoryMmap>>>, snapshot: Mutex<Option<GuestMemoryLoadGuard<GuestMemoryMmap>>>,
shared: bool, shared: bool,
hugepages: bool, hugepages: bool,
balloon: Option<Arc<Mutex<virtio_devices::Balloon>>>,
} }
#[derive(Debug)] #[derive(Debug)]
@ -122,6 +123,9 @@ pub enum Error {
/// The number of external backing files doesn't match the number of /// The number of external backing files doesn't match the number of
/// memory regions. /// memory regions.
InvalidAmountExternalBackingFiles, InvalidAmountExternalBackingFiles,
/// Failed to virtio-balloon resize
VirtioBalloonResizeFail(virtio_devices::balloon::Error),
} }
const ENABLE_FLAG: usize = 0; const ENABLE_FLAG: usize = 0;
@ -338,6 +342,7 @@ impl MemoryManager {
snapshot: Mutex::new(None), snapshot: Mutex::new(None),
shared: config.shared, shared: config.shared,
hugepages: config.hugepages, hugepages: config.hugepages,
balloon: None,
})); }));
guest_memory.memory().with_regions(|_, region| { guest_memory.memory().with_regions(|_, region| {
@ -645,6 +650,10 @@ impl MemoryManager {
Ok(region) Ok(region)
} }
pub fn set_balloon(&mut self, balloon: Arc<Mutex<virtio_devices::Balloon>>) {
self.balloon = Some(balloon);
}
pub fn guest_memory(&self) -> GuestMemoryAtomic<GuestMemoryMmap> { pub fn guest_memory(&self) -> GuestMemoryAtomic<GuestMemoryMmap> {
self.guest_memory.clone() self.guest_memory.clone()
} }
@ -790,6 +799,23 @@ impl MemoryManager {
Ok(()) Ok(())
} }
pub fn balloon_resize(&mut self, expected_ram: u64) -> Result<(), Error> {
if let Some(balloon) = &self.balloon {
let balloon_size = if expected_ram < self.current_ram {
self.current_ram - expected_ram
} else {
0
};
balloon
.lock()
.unwrap()
.resize(balloon_size)
.map_err(Error::VirtioBalloonResizeFail)?;
}
Ok(())
}
/// In case this function resulted in adding a new memory region to the /// In case this function resulted in adding a new memory region to the
/// guest memory, the new region is returned to the caller. The virtio-mem /// guest memory, the new region is returned to the caller. The virtio-mem
/// use case never adds a new region as the whole hotpluggable memory has /// use case never adds a new region as the whole hotpluggable memory has