mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-06-24 14:32:33 +00:00
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:
parent
7ed9494973
commit
8fb7ab7518
124
src/dragonball/Cargo.lock
generated
124
src/dragonball/Cargo.lock
generated
@ -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"
|
||||
|
@ -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"]
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
419
src/dragonball/src/device_manager/balloon_dev_mgr.rs
Normal file
419
src/dragonball/src/device_manager/balloon_dev_mgr.rs
Normal 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());
|
||||
}
|
||||
}
|
@ -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(),
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user