dragonball: introduce virtio-balloon device

We introduce virtio-balloon device to support memory resize.
virtio-balloon device could reclaim memory from guest to host.

Fixes: #6719

Signed-off-by: Helin Guo <helinguo@linux.alibaba.com>
This commit is contained in:
Helin Guo 2023-01-29 16:18:06 +08:00
parent 7ed9494973
commit 8fb7ab7518
7 changed files with 632 additions and 30 deletions

View File

@ -180,9 +180,9 @@ dependencies = [
[[package]]
name = "crossbeam-channel"
version = "0.5.7"
version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf2b3e8478797446514c91ef04bafcb59faba183e621ad488df88983cc14128c"
checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200"
dependencies = [
"cfg-if",
"crossbeam-utils",
@ -445,13 +445,13 @@ dependencies = [
[[package]]
name = "errno"
version = "0.2.8"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1"
checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a"
dependencies = [
"errno-dragonfly",
"libc",
"winapi",
"windows-sys 0.48.0",
]
[[package]]
@ -483,7 +483,7 @@ dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"windows-sys",
"windows-sys 0.45.0",
]
[[package]]
@ -619,9 +619,9 @@ dependencies = [
[[package]]
name = "getrandom"
version = "0.2.8"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4"
dependencies = [
"cfg-if",
"libc",
@ -671,7 +671,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1abeb7a0dd0f8181267ff8adc397075586500b81b28a73e8a0208b00fc170fb3"
dependencies = [
"libc",
"windows-sys",
"windows-sys 0.45.0",
]
[[package]]
@ -842,7 +842,7 @@ dependencies = [
"libc",
"log",
"wasi",
"windows-sys",
"windows-sys 0.45.0",
]
[[package]]
@ -1045,7 +1045,7 @@ dependencies = [
"libc",
"redox_syscall",
"smallvec",
"windows-sys",
"windows-sys 0.45.0",
]
[[package]]
@ -1121,16 +1121,16 @@ checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342"
[[package]]
name = "rustix"
version = "0.36.8"
version = "0.36.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f43abb88211988493c1abb44a70efa56ff0ce98f233b7b276146f1f3f7ba9644"
checksum = "14e4d67015953998ad0eb82887a0eb0129e18a7e2f3b7b0f6c422fddcd503d62"
dependencies = [
"bitflags",
"errno",
"io-lifetimes",
"libc",
"linux-raw-sys",
"windows-sys",
"windows-sys 0.45.0",
]
[[package]]
@ -1168,18 +1168,18 @@ dependencies = [
[[package]]
name = "serde"
version = "1.0.152"
version = "1.0.156"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb"
checksum = "314b5b092c0ade17c00142951e50ced110ec27cea304b1037c6969246c2469a4"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.152"
version = "1.0.156"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e"
checksum = "d7e29c4601e36bcec74a223228dce795f4cd3616341a4af93520ca1a837c087d"
dependencies = [
"proc-macro2",
"quote",
@ -1188,9 +1188,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.93"
version = "1.0.96"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cad406b69c91885b5107daf2c29572f6c8cdb3c66826821e286c533490c0bc76"
checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1"
dependencies = [
"itoa",
"ryu",
@ -1423,7 +1423,7 @@ dependencies = [
"pin-project-lite",
"socket2",
"tokio-macros",
"windows-sys",
"windows-sys 0.45.0",
]
[[package]]
@ -1611,7 +1611,16 @@ version = "0.45.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
dependencies = [
"windows-targets",
"windows-targets 0.42.1",
]
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets 0.48.0",
]
[[package]]
@ -1620,13 +1629,28 @@ version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
"windows_aarch64_gnullvm 0.42.1",
"windows_aarch64_msvc 0.42.1",
"windows_i686_gnu 0.42.1",
"windows_i686_msvc 0.42.1",
"windows_x86_64_gnu 0.42.1",
"windows_x86_64_gnullvm 0.42.1",
"windows_x86_64_msvc 0.42.1",
]
[[package]]
name = "windows-targets"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
dependencies = [
"windows_aarch64_gnullvm 0.48.0",
"windows_aarch64_msvc 0.48.0",
"windows_i686_gnu 0.48.0",
"windows_i686_msvc 0.48.0",
"windows_x86_64_gnu 0.48.0",
"windows_x86_64_gnullvm 0.48.0",
"windows_x86_64_msvc 0.48.0",
]
[[package]]
@ -1635,42 +1659,84 @@ version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
[[package]]
name = "windows_i686_gnu"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640"
[[package]]
name = "windows_i686_gnu"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
[[package]]
name = "windows_i686_msvc"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605"
[[package]]
name = "windows_i686_msvc"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
[[package]]
name = "xattr"
version = "0.2.3"

View File

@ -56,3 +56,4 @@ virtio-net = ["dbs-virtio-devices/virtio-net", "virtio-queue"]
# virtio-fs only work on atomic-guest-memory
virtio-fs = ["dbs-virtio-devices/virtio-fs", "virtio-queue", "atomic-guest-memory"]
virtio-mem = ["dbs-virtio-devices/virtio-mem", "virtio-queue", "atomic-guest-memory"]
virtio-balloon = ["dbs-virtio-devices/virtio-balloon", "virtio-queue"]

View File

@ -19,6 +19,8 @@ use crate::vmm::Vmm;
use self::VmConfigError::*;
use self::VmmActionError::MachineConfig;
#[cfg(feature = "virtio-balloon")]
pub use crate::device_manager::balloon_dev_mgr::{BalloonDeviceConfigInfo, BalloonDeviceError};
#[cfg(feature = "virtio-blk")]
pub use crate::device_manager::blk_dev_mgr::{
BlockDeviceConfigInfo, BlockDeviceConfigUpdateInfo, BlockDeviceError, BlockDeviceMgr,
@ -36,7 +38,6 @@ pub use crate::device_manager::virtio_net_dev_mgr::{
};
#[cfg(feature = "virtio-vsock")]
pub use crate::device_manager::vsock_dev_mgr::{VsockDeviceConfigInfo, VsockDeviceError};
#[cfg(feature = "hotplug")]
pub use crate::vcpu::{VcpuResizeError, VcpuResizeInfo};
@ -108,6 +109,11 @@ pub enum VmmActionError {
/// Mem device related errors.
#[error("virtio-mem device error: {0}")]
Mem(#[source] MemDeviceError),
#[cfg(feature = "virtio-balloon")]
/// Balloon device related errors.
#[error("virtio-balloon device error: {0}")]
Balloon(#[source] BalloonDeviceError),
}
/// This enum represents the public interface of the VMM. Each action contains various
@ -187,6 +193,11 @@ pub enum VmmAction {
#[cfg(feature = "virtio-mem")]
/// Add a new mem device or update one that already exists using the `MemDeviceConfig` as input.
InsertMemDevice(MemDeviceConfigInfo),
#[cfg(feature = "virtio-balloon")]
/// Add a new balloon device or update one that already exists using the `BalloonDeviceConfig`
/// as input.
InsertBalloonDevice(BalloonDeviceConfigInfo),
}
/// The enum represents the response sent by the VMM in case of success. The response is either
@ -291,6 +302,10 @@ impl VmmService {
VmmAction::ResizeVcpu(vcpu_resize_cfg) => self.resize_vcpu(vmm, vcpu_resize_cfg),
#[cfg(feature = "virtio-mem")]
VmmAction::InsertMemDevice(mem_cfg) => self.add_mem_device(vmm, event_mgr, mem_cfg),
#[cfg(feature = "virtio-balloon")]
VmmAction::InsertBalloonDevice(balloon_cfg) => {
self.add_balloon_device(vmm, event_mgr, balloon_cfg)
}
};
debug!("send vmm response: {:?}", response);
@ -691,6 +706,36 @@ impl VmmService {
.map(|_| VmmData::Empty)
.map_err(VmmActionError::Mem)
}
#[cfg(feature = "virtio-balloon")]
fn add_balloon_device(
&mut self,
vmm: &mut Vmm,
event_mgr: &mut EventManager,
config: BalloonDeviceConfigInfo,
) -> VmmRequestResult {
let vm = vmm.get_vm_mut().ok_or(VmmActionError::InvalidVMID)?;
if config.size_mib != 0 {
info!("add_balloon_device: wait prealloc");
vm.stop_prealloc().map_err(VmmActionError::StartMicroVm)?;
}
let ctx = vm
.create_device_op_context(Some(event_mgr.epoll_manager()))
.map_err(|e| {
if let StartMicroVmError::UpcallServerNotReady = e {
VmmActionError::UpcallServerNotReady
} else {
VmmActionError::StartMicroVm(e)
}
})?;
vm.device_manager_mut()
.balloon_manager
.insert_or_update_device(ctx, config)
.map(|_| VmmData::Empty)
.map_err(VmmActionError::Balloon)
}
}
fn handle_cpu_topology(
@ -1539,4 +1584,44 @@ mod tests {
t.check_request();
}
}
#[cfg(feature = "virtio-balloon")]
#[test]
fn test_vmm_action_insert_balloon_device() {
skip_if_not_root!();
let tests = &mut [
// hotplug unready
TestData::new(
VmmAction::InsertBalloonDevice(BalloonDeviceConfigInfo::default()),
InstanceState::Running,
&|result| {
assert!(matches!(
result,
Err(VmmActionError::StartMicroVm(
StartMicroVmError::UpcallMissVsock
))
));
let err_string = format!("{}", result.unwrap_err());
let expected_err = String::from(
"failed to boot the VM: \
the upcall client needs a virtio-vsock device for communication",
);
assert_eq!(err_string, expected_err);
},
),
// success
TestData::new(
VmmAction::InsertBalloonDevice(BalloonDeviceConfigInfo::default()),
InstanceState::Uninitialized,
&|result| {
assert!(result.is_ok());
},
),
];
for t in tests.iter_mut() {
t.check_request();
}
}
}

View File

@ -0,0 +1,419 @@
// Copyright 2020 Alibaba Cloud. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
use dbs_virtio_devices as virtio;
use serde_derive::{Deserialize, Serialize};
use slog::{error, info};
use virtio::balloon::{Balloon, BalloonConfig};
use virtio::Error as VirtIoError;
use crate::address_space_manager::GuestAddressSpaceImpl;
use crate::config_manager::{ConfigItem, DeviceConfigInfo, DeviceConfigInfos};
use crate::device_manager::DbsMmioV2Device;
use crate::device_manager::{DeviceManager, DeviceMgrError, DeviceOpContext};
// The flag of whether to use the shared irq.
const USE_SHARED_IRQ: bool = true;
// The flag of whether to use the generic irq.
const USE_GENERIC_IRQ: bool = false;
/// Errors associated with `BalloonDeviceConfig`.
#[derive(Debug, thiserror::Error)]
pub enum BalloonDeviceError {
/// The balloon device was already used.
#[error("the virtio-balloon ID was already added to a different device")]
BalloonDeviceAlreadyExists,
/// Cannot perform the requested operation after booting the microVM.
#[error("the update operation is not allowed after boot")]
UpdateNotAllowedPostBoot,
/// guest memory error
#[error("failed to access guest memory, {0}")]
GuestMemoryError(#[source] vm_memory::mmap::Error),
/// create balloon device error
#[error("failed to create virtio-balloon device, {0}")]
CreateBalloonDevice(#[source] virtio::Error),
/// hotplug balloon device error
#[error("cannot hotplug virtio-balloon device, {0}")]
HotplugDeviceFailed(#[source] DeviceMgrError),
/// create mmio device error
#[error("cannot create virtio-balloon mmio device, {0}")]
CreateMmioDevice(#[source] DeviceMgrError),
/// Cannot initialize a balloon device or add a device to the MMIO Bus.
#[error("failure while registering balloon device: {0}")]
RegisterBalloonDevice(#[source] DeviceMgrError),
/// resize balloon device error
#[error("failure while resizing virtio-balloon device, {0}")]
ResizeFailed(#[source] VirtIoError),
/// The balloon device id doesn't exist.
#[error("invalid balloon device id '{0}'")]
InvalidDeviceId(String),
/// balloon device does not exist
#[error("balloon device does not exist")]
NotExist,
/// The device manager errors.
#[error("DeviceManager error: {0}")]
DeviceManager(#[source] DeviceMgrError),
}
/// Configuration information for a virtio-balloon device.
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
pub struct BalloonDeviceConfigInfo {
/// Unique identifier of the balloon device
pub balloon_id: String,
/// Resize balloon size in mib
pub size_mib: u64,
/// Use shared irq
pub use_shared_irq: Option<bool>,
/// Use generic irq
pub use_generic_irq: Option<bool>,
/// VIRTIO_BALLOON_F_DEFLATE_ON_OOM
pub f_deflate_on_oom: bool,
/// VIRTIO_BALLOON_F_REPORTING
pub f_reporting: bool,
}
impl ConfigItem for BalloonDeviceConfigInfo {
type Err = BalloonDeviceError;
fn id(&self) -> &str {
&self.balloon_id
}
fn check_conflicts(&self, other: &Self) -> Result<(), BalloonDeviceError> {
if self.balloon_id.as_str() == other.balloon_id.as_str() {
Err(BalloonDeviceError::BalloonDeviceAlreadyExists)
} else {
Ok(())
}
}
}
/// Balloon Device Info
pub type BalloonDeviceInfo = DeviceConfigInfo<BalloonDeviceConfigInfo>;
impl ConfigItem for BalloonDeviceInfo {
type Err = BalloonDeviceError;
fn id(&self) -> &str {
&self.config.balloon_id
}
fn check_conflicts(&self, other: &Self) -> Result<(), BalloonDeviceError> {
if self.config.balloon_id.as_str() == other.config.balloon_id.as_str() {
Err(BalloonDeviceError::BalloonDeviceAlreadyExists)
} else {
Ok(())
}
}
}
/// Wrapper for the collection that holds all the Balloon Devices Configs
#[derive(Clone)]
pub struct BalloonDeviceMgr {
/// A list of `BalloonDeviceConfig` objects.
info_list: DeviceConfigInfos<BalloonDeviceConfigInfo>,
pub(crate) use_shared_irq: bool,
}
impl BalloonDeviceMgr {
/// Inserts `balloon_cfg` in the virtio-balloon device configuration list.
/// If an entry with the same id already exists, it will attempt to update
/// the existing entry.
pub fn insert_or_update_device(
&mut self,
mut ctx: DeviceOpContext,
balloon_cfg: BalloonDeviceConfigInfo,
) -> std::result::Result<(), BalloonDeviceError> {
if !cfg!(feature = "hotplug") && ctx.is_hotplug {
error!(ctx.logger(), "hotplug feature has been disabled.";
"subsystem" => "balloon_dev_mgr",);
return Err(BalloonDeviceError::UpdateNotAllowedPostBoot);
}
let epoll_mgr = ctx
.get_epoll_mgr()
.map_err(BalloonDeviceError::DeviceManager)?;
// If the id of the drive already exists in the list, the operation is update.
if let Some(index) = self.get_index_of_balloon_dev(&balloon_cfg.balloon_id) {
// Update an existing balloon device
if ctx.is_hotplug {
info!(ctx.logger(), "resize virtio balloon size to {:?}", balloon_cfg.size_mib; "subsystem" => "balloon_dev_mgr");
self.update_balloon_size(index, balloon_cfg.size_mib)?;
}
self.info_list.insert_or_update(&balloon_cfg)?;
} else {
// Create a new balloon device
if !self.info_list.is_empty() {
error!(ctx.logger(), "only support one balloon device!"; "subsystem" => "balloon_dev_mgr");
return Err(BalloonDeviceError::BalloonDeviceAlreadyExists);
}
if !ctx.is_hotplug {
self.info_list.insert_or_update(&balloon_cfg)?;
return Ok(());
}
info!(ctx.logger(), "hotplug balloon device: {}", balloon_cfg.balloon_id; "subsystem" => "balloon_dev_mgr");
let device = Box::new(
virtio::balloon::Balloon::new(
epoll_mgr,
BalloonConfig {
f_deflate_on_oom: balloon_cfg.f_deflate_on_oom,
f_reporting: balloon_cfg.f_reporting,
},
)
.map_err(BalloonDeviceError::CreateBalloonDevice)?,
);
let mmio_dev =
DeviceManager::create_mmio_virtio_device_with_device_change_notification(
device,
&mut ctx,
balloon_cfg.use_shared_irq.unwrap_or(self.use_shared_irq),
balloon_cfg.use_generic_irq.unwrap_or(USE_GENERIC_IRQ),
)
.map_err(BalloonDeviceError::CreateMmioDevice)?;
ctx.insert_hotplug_mmio_device(&mmio_dev, None)
.map_err(|e| {
error!(
ctx.logger(),
"hotplug balloon device {} error: {}",
&balloon_cfg.balloon_id, e;
"subsystem" => "balloon_dev_mgr"
);
BalloonDeviceError::HotplugDeviceFailed(e)
})?;
let index = self.info_list.insert_or_update(&balloon_cfg)?;
self.info_list[index].set_device(mmio_dev);
}
Ok(())
}
/// Attaches all virtio-balloon devices from the BalloonDevicesConfig.
pub fn attach_devices(
&mut self,
ctx: &mut DeviceOpContext,
) -> std::result::Result<(), BalloonDeviceError> {
let epoll_mgr = ctx
.get_epoll_mgr()
.map_err(BalloonDeviceError::DeviceManager)?;
for info in self.info_list.iter_mut() {
info!(ctx.logger(), "attach balloon device: {}", info.config.balloon_id; "subsystem" => "balloon_dev_mgr");
let device = Balloon::new(
epoll_mgr.clone(),
BalloonConfig {
f_deflate_on_oom: info.config.f_deflate_on_oom,
f_reporting: info.config.f_reporting,
},
)
.map_err(BalloonDeviceError::CreateBalloonDevice)?;
let mmio_dev =
DeviceManager::create_mmio_virtio_device_with_device_change_notification(
Box::new(device),
ctx,
info.config.use_shared_irq.unwrap_or(self.use_shared_irq),
info.config.use_generic_irq.unwrap_or(USE_GENERIC_IRQ),
)
.map_err(BalloonDeviceError::RegisterBalloonDevice)?;
info.set_device(mmio_dev);
}
Ok(())
}
fn update_balloon_size(
&self,
index: usize,
size_mib: u64,
) -> std::result::Result<(), BalloonDeviceError> {
let device = self.info_list[index]
.device
.as_ref()
.ok_or_else(|| BalloonDeviceError::NotExist)?;
if let Some(mmio_dev) = device.as_any().downcast_ref::<DbsMmioV2Device>() {
let guard = mmio_dev.state();
let inner_dev = guard.get_inner_device();
if let Some(balloon_dev) = inner_dev
.as_any()
.downcast_ref::<Balloon<GuestAddressSpaceImpl>>()
{
return balloon_dev
.set_size(size_mib)
.map_err(BalloonDeviceError::ResizeFailed);
}
}
Ok(())
}
fn get_index_of_balloon_dev(&self, balloon_id: &str) -> Option<usize> {
self.info_list
.iter()
.position(|info| info.config.balloon_id.eq(balloon_id))
}
}
impl Default for BalloonDeviceMgr {
/// Create a new `BalloonDeviceMgr` object..
fn default() -> Self {
BalloonDeviceMgr {
info_list: DeviceConfigInfos::new(),
use_shared_irq: USE_SHARED_IRQ,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_utils::tests::create_vm_for_test;
impl Default for BalloonDeviceConfigInfo {
fn default() -> Self {
BalloonDeviceConfigInfo {
balloon_id: "".to_string(),
size_mib: 0,
use_generic_irq: None,
use_shared_irq: None,
f_deflate_on_oom: false,
f_reporting: false,
}
}
}
#[test]
fn test_balloon_config_check_conflicts() {
let config = BalloonDeviceConfigInfo::default();
let mut config2 = BalloonDeviceConfigInfo::default();
assert!(config.check_conflicts(&config2).is_err());
config2.balloon_id = "dummy_balloon".to_string();
assert!(config.check_conflicts(&config2).is_ok());
}
#[test]
fn test_create_balloon_devices_configs() {
let mgr = BalloonDeviceMgr::default();
assert_eq!(mgr.info_list.len(), 0);
assert_eq!(mgr.get_index_of_balloon_dev(""), None);
}
#[test]
fn test_balloon_insert_or_update_device() {
//Init vm for test.
let mut vm = create_vm_for_test();
// Test for standard config
let device_op_ctx = DeviceOpContext::new(
Some(vm.epoll_manager().clone()),
vm.device_manager(),
Some(vm.vm_as().unwrap().clone()),
None,
false,
Some(vm.vm_config().clone()),
vm.shared_info().clone(),
);
let dummy_balloon_device = BalloonDeviceConfigInfo::default();
vm.device_manager_mut()
.balloon_manager
.insert_or_update_device(device_op_ctx, dummy_balloon_device)
.unwrap();
assert_eq!(vm.device_manager().balloon_manager.info_list.len(), 1);
}
#[test]
fn test_balloon_attach_device() {
//Init vm and insert balloon config for test.
let mut vm = create_vm_for_test();
let device_op_ctx = DeviceOpContext::new(
Some(vm.epoll_manager().clone()),
vm.device_manager(),
Some(vm.vm_as().unwrap().clone()),
None,
false,
Some(vm.vm_config().clone()),
vm.shared_info().clone(),
);
let dummy_balloon_device = BalloonDeviceConfigInfo::default();
vm.device_manager_mut()
.balloon_manager
.insert_or_update_device(device_op_ctx, dummy_balloon_device)
.unwrap();
assert_eq!(vm.device_manager().balloon_manager.info_list.len(), 1);
// Test for standard config
let mut device_op_ctx = DeviceOpContext::new(
Some(vm.epoll_manager().clone()),
vm.device_manager(),
Some(vm.vm_as().unwrap().clone()),
None,
false,
Some(vm.vm_config().clone()),
vm.shared_info().clone(),
);
assert!(vm
.device_manager_mut()
.balloon_manager
.attach_devices(&mut device_op_ctx)
.is_ok());
assert_eq!(vm.device_manager().balloon_manager.info_list.len(), 1);
}
#[test]
fn test_balloon_update_device() {
//Init vm for test.
let mut vm = create_vm_for_test();
let device_op_ctx = DeviceOpContext::new(
Some(vm.epoll_manager().clone()),
vm.device_manager(),
Some(vm.vm_as().unwrap().clone()),
None,
false,
Some(vm.vm_config().clone()),
vm.shared_info().clone(),
);
let dummy_balloon_device = BalloonDeviceConfigInfo::default();
vm.device_manager_mut()
.balloon_manager
.insert_or_update_device(device_op_ctx, dummy_balloon_device)
.unwrap();
assert_eq!(vm.device_manager().balloon_manager.info_list.len(), 1);
let mut device_op_ctx = DeviceOpContext::new(
Some(vm.epoll_manager().clone()),
vm.device_manager(),
Some(vm.vm_as().unwrap().clone()),
None,
false,
Some(vm.vm_config().clone()),
vm.shared_info().clone(),
);
assert!(vm
.device_manager_mut()
.balloon_manager
.attach_devices(&mut device_op_ctx)
.is_ok());
assert_eq!(vm.device_manager().balloon_manager.info_list.len(), 1);
assert!(vm
.device_manager()
.balloon_manager
.update_balloon_size(0, 200)
.is_ok());
}
}

View File

@ -96,6 +96,12 @@ pub mod mem_dev_mgr;
#[cfg(feature = "virtio-mem")]
use self::mem_dev_mgr::MemDeviceMgr;
#[cfg(feature = "virtio-balloon")]
/// Device manager for virtio-balloon devices.
pub mod balloon_dev_mgr;
#[cfg(feature = "virtio-balloon")]
use self::balloon_dev_mgr::BalloonDeviceMgr;
macro_rules! info(
($l:expr, $($args:tt)+) => {
slog::info!($l, $($args)+; slog::o!("subsystem" => "device_manager"))
@ -528,6 +534,9 @@ pub struct DeviceManager {
#[cfg(feature = "virtio-mem")]
pub(crate) mem_manager: MemDeviceMgr,
#[cfg(feature = "virtio-balloon")]
pub(crate) balloon_manager: BalloonDeviceMgr,
}
impl DeviceManager {
@ -562,6 +571,8 @@ impl DeviceManager {
fs_manager: Arc::new(Mutex::new(FsDeviceMgr::default())),
#[cfg(feature = "virtio-mem")]
mem_manager: MemDeviceMgr::default(),
#[cfg(feature = "virtio-balloon")]
balloon_manager: BalloonDeviceMgr::default(),
}
}
@ -1129,6 +1140,8 @@ mod tests {
vsock_manager: VsockDeviceMgr::default(),
#[cfg(feature = "virtio-mem")]
mem_manager: MemDeviceMgr::default(),
#[cfg(feature = "virtio-balloon")]
balloon_manager: BalloonDeviceMgr::default(),
#[cfg(target_arch = "aarch64")]
mmio_device_info: HashMap::new(),

View File

@ -188,6 +188,11 @@ pub enum StartMicroVmError {
/// Virtio-fs errors.
#[error("virtio-fs errors: {0}")]
FsDeviceError(#[source] device_manager::fs_dev_mgr::FsDeviceError),
#[cfg(feature = "virtio-balloon")]
/// Virtio-balloon errors.
#[error("virtio-balloon errors: {0}")]
BalloonDeviceError(#[source] device_manager::balloon_dev_mgr::BalloonDeviceError),
}
/// Errors associated with starting the instance.

View File

@ -386,6 +386,19 @@ impl Vm {
(dragonball_version, instance_id)
}
pub(crate) fn stop_prealloc(&mut self) -> std::result::Result<(), StartMicroVmError> {
if self.address_space.is_initialized() {
return self
.address_space
.wait_prealloc(true)
.map_err(StartMicroVmError::AddressManagerError);
}
Err(StartMicroVmError::AddressManagerError(
AddressManagerError::GuestMemoryNotInitialized,
))
}
}
impl Vm {