mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-06-26 15:32:30 +00:00
dragonball: add virtio-fs device support
Virtio-fs devices are supported. Fixes: #4257 Signed-off-by: wllenyj <wllenyj@linux.alibaba.com>
This commit is contained in:
parent
948381bdbe
commit
11b3f95140
@ -51,6 +51,8 @@ hotplug = ["virtio-vsock"]
|
|||||||
virtio-vsock = ["dbs-virtio-devices/virtio-vsock", "virtio-queue"]
|
virtio-vsock = ["dbs-virtio-devices/virtio-vsock", "virtio-queue"]
|
||||||
virtio-blk = ["dbs-virtio-devices/virtio-blk", "virtio-queue"]
|
virtio-blk = ["dbs-virtio-devices/virtio-blk", "virtio-queue"]
|
||||||
virtio-net = ["dbs-virtio-devices/virtio-net", "virtio-queue"]
|
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"]
|
||||||
|
|
||||||
[patch.'crates-io']
|
[patch.'crates-io']
|
||||||
dbs-device = { git = "https://github.com/openanolis/dragonball-sandbox.git", rev = "7a8e832b53d66994d6a16f0513d69f540583dcd0" }
|
dbs-device = { git = "https://github.com/openanolis/dragonball-sandbox.git", rev = "7a8e832b53d66994d6a16f0513d69f540583dcd0" }
|
||||||
|
@ -21,6 +21,10 @@ use crate::vmm::Vmm;
|
|||||||
use crate::device_manager::blk_dev_mgr::{
|
use crate::device_manager::blk_dev_mgr::{
|
||||||
BlockDeviceConfigInfo, BlockDeviceConfigUpdateInfo, BlockDeviceError, BlockDeviceMgr,
|
BlockDeviceConfigInfo, BlockDeviceConfigUpdateInfo, BlockDeviceError, BlockDeviceMgr,
|
||||||
};
|
};
|
||||||
|
#[cfg(feature = "virtio-fs")]
|
||||||
|
use crate::device_manager::fs_dev_mgr::{
|
||||||
|
FsDeviceConfigInfo, FsDeviceConfigUpdateInfo, FsDeviceError, FsDeviceMgr, FsMountConfigInfo,
|
||||||
|
};
|
||||||
#[cfg(feature = "virtio-net")]
|
#[cfg(feature = "virtio-net")]
|
||||||
use crate::device_manager::virtio_net_dev_mgr::{
|
use crate::device_manager::virtio_net_dev_mgr::{
|
||||||
VirtioNetDeviceConfigInfo, VirtioNetDeviceConfigUpdateInfo, VirtioNetDeviceError,
|
VirtioNetDeviceConfigInfo, VirtioNetDeviceConfigUpdateInfo, VirtioNetDeviceError,
|
||||||
@ -74,6 +78,11 @@ pub enum VmmActionError {
|
|||||||
/// Net device related errors.
|
/// Net device related errors.
|
||||||
#[error("virtio-net device error: {0}")]
|
#[error("virtio-net device error: {0}")]
|
||||||
VirtioNet(#[source] VirtioNetDeviceError),
|
VirtioNet(#[source] VirtioNetDeviceError),
|
||||||
|
|
||||||
|
#[cfg(feature = "virtio-fs")]
|
||||||
|
/// The action `InsertFsDevice` failed either because of bad user input or an internal error.
|
||||||
|
#[error("virtio-fs device: {0}")]
|
||||||
|
FsDevice(#[source] FsDeviceError),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This enum represents the public interface of the VMM. Each action contains various
|
/// This enum represents the public interface of the VMM. Each action contains various
|
||||||
@ -129,6 +138,22 @@ pub enum VmmAction {
|
|||||||
/// Update a network interface, after microVM start. Currently, the only updatable properties
|
/// Update a network interface, after microVM start. Currently, the only updatable properties
|
||||||
/// are the RX and TX rate limiters.
|
/// are the RX and TX rate limiters.
|
||||||
UpdateNetworkInterface(VirtioNetDeviceConfigUpdateInfo),
|
UpdateNetworkInterface(VirtioNetDeviceConfigUpdateInfo),
|
||||||
|
|
||||||
|
#[cfg(feature = "virtio-fs")]
|
||||||
|
/// Add a new shared fs device or update one that already exists using the
|
||||||
|
/// `FsDeviceConfig` as input. This action can only be called before the microVM has
|
||||||
|
/// booted.
|
||||||
|
InsertFsDevice(FsDeviceConfigInfo),
|
||||||
|
|
||||||
|
#[cfg(feature = "virtio-fs")]
|
||||||
|
/// Attach a new virtiofs Backend fs or detach an existing virtiofs Backend fs using the
|
||||||
|
/// `FsMountConfig` as input. This action can only be called _after_ the microVM has
|
||||||
|
/// booted.
|
||||||
|
ManipulateFsBackendFs(FsMountConfigInfo),
|
||||||
|
|
||||||
|
#[cfg(feature = "virtio-fs")]
|
||||||
|
/// Update fs rate limiter, after microVM start.
|
||||||
|
UpdateFsDevice(FsDeviceConfigUpdateInfo),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The enum represents the response sent by the VMM in case of success. The response is either
|
/// The enum represents the response sent by the VMM in case of success. The response is either
|
||||||
@ -218,6 +243,17 @@ impl VmmService {
|
|||||||
VmmAction::UpdateNetworkInterface(netif_update) => {
|
VmmAction::UpdateNetworkInterface(netif_update) => {
|
||||||
self.update_net_rate_limiters(vmm, netif_update)
|
self.update_net_rate_limiters(vmm, netif_update)
|
||||||
}
|
}
|
||||||
|
#[cfg(feature = "virtio-fs")]
|
||||||
|
VmmAction::InsertFsDevice(fs_cfg) => self.add_fs_device(vmm, fs_cfg),
|
||||||
|
|
||||||
|
#[cfg(feature = "virtio-fs")]
|
||||||
|
VmmAction::ManipulateFsBackendFs(fs_mount_cfg) => {
|
||||||
|
self.manipulate_fs_backend_fs(vmm, fs_mount_cfg)
|
||||||
|
}
|
||||||
|
#[cfg(feature = "virtio-fs")]
|
||||||
|
VmmAction::UpdateFsDevice(fs_update_cfg) => {
|
||||||
|
self.update_fs_rate_limiters(vmm, fs_update_cfg)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
debug!("send vmm response: {:?}", response);
|
debug!("send vmm response: {:?}", response);
|
||||||
@ -566,4 +602,63 @@ impl VmmService {
|
|||||||
.map(|_| VmmData::Empty)
|
.map(|_| VmmData::Empty)
|
||||||
.map_err(VmmActionError::VirtioNet)
|
.map_err(VmmActionError::VirtioNet)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "virtio-fs")]
|
||||||
|
fn add_fs_device(&mut self, vmm: &mut Vmm, config: FsDeviceConfigInfo) -> VmmRequestResult {
|
||||||
|
let vm = vmm
|
||||||
|
.get_vm_by_id_mut("")
|
||||||
|
.ok_or(VmmActionError::InvalidVMID)?;
|
||||||
|
let hotplug = vm.is_vm_initialized();
|
||||||
|
if !cfg!(feature = "hotplug") && hotplug {
|
||||||
|
return Err(VmmActionError::FsDevice(
|
||||||
|
FsDeviceError::UpdateNotAllowedPostBoot,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let ctx = vm.create_device_op_context(None).map_err(|e| {
|
||||||
|
info!("create device op context error: {:?}", e);
|
||||||
|
VmmActionError::FsDevice(FsDeviceError::UpdateNotAllowedPostBoot)
|
||||||
|
})?;
|
||||||
|
FsDeviceMgr::insert_device(vm.device_manager_mut(), ctx, config)
|
||||||
|
.map(|_| VmmData::Empty)
|
||||||
|
.map_err(VmmActionError::FsDevice)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "virtio-fs")]
|
||||||
|
fn manipulate_fs_backend_fs(
|
||||||
|
&self,
|
||||||
|
vmm: &mut Vmm,
|
||||||
|
config: FsMountConfigInfo,
|
||||||
|
) -> VmmRequestResult {
|
||||||
|
let vm = vmm
|
||||||
|
.get_vm_by_id_mut("")
|
||||||
|
.ok_or(VmmActionError::InvalidVMID)?;
|
||||||
|
|
||||||
|
if !vm.is_vm_initialized() {
|
||||||
|
return Err(VmmActionError::FsDevice(FsDeviceError::MicroVMNotRunning));
|
||||||
|
}
|
||||||
|
|
||||||
|
FsDeviceMgr::manipulate_backend_fs(vm.device_manager_mut(), config)
|
||||||
|
.map(|_| VmmData::Empty)
|
||||||
|
.map_err(VmmActionError::FsDevice)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "virtio-fs")]
|
||||||
|
fn update_fs_rate_limiters(
|
||||||
|
&self,
|
||||||
|
vmm: &mut Vmm,
|
||||||
|
config: FsDeviceConfigUpdateInfo,
|
||||||
|
) -> VmmRequestResult {
|
||||||
|
let vm = vmm
|
||||||
|
.get_vm_by_id_mut("")
|
||||||
|
.ok_or(VmmActionError::InvalidVMID)?;
|
||||||
|
|
||||||
|
if !vm.is_vm_initialized() {
|
||||||
|
return Err(VmmActionError::FsDevice(FsDeviceError::MicroVMNotRunning));
|
||||||
|
}
|
||||||
|
|
||||||
|
FsDeviceMgr::update_device_ratelimiters(vm.device_manager_mut(), config)
|
||||||
|
.map(|_| VmmData::Empty)
|
||||||
|
.map_err(VmmActionError::FsDevice)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -176,7 +176,7 @@ pub struct BlockDeviceConfigInfo {
|
|||||||
pub no_drop: bool,
|
pub no_drop: bool,
|
||||||
/// Block device multi-queue
|
/// Block device multi-queue
|
||||||
pub num_queues: usize,
|
pub num_queues: usize,
|
||||||
/// Virtio queue size.
|
/// Virtio queue size. Size: byte
|
||||||
pub queue_size: u16,
|
pub queue_size: u16,
|
||||||
/// Rate Limiter for I/O operations.
|
/// Rate Limiter for I/O operations.
|
||||||
pub rate_limiter: Option<RateLimiterConfigInfo>,
|
pub rate_limiter: Option<RateLimiterConfigInfo>,
|
||||||
|
523
src/dragonball/src/device_manager/fs_dev_mgr.rs
Normal file
523
src/dragonball/src/device_manager/fs_dev_mgr.rs
Normal file
@ -0,0 +1,523 @@
|
|||||||
|
// Copyright 2020-2022 Alibaba Cloud. All Rights Reserved.
|
||||||
|
// Copyright 2019 Intel Corporation. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
use std::convert::TryInto;
|
||||||
|
|
||||||
|
use dbs_utils::epoll_manager::EpollManager;
|
||||||
|
use dbs_virtio_devices::{self as virtio, Error as VirtIoError};
|
||||||
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
use slog::{error, info};
|
||||||
|
|
||||||
|
use crate::address_space_manager::GuestAddressSpaceImpl;
|
||||||
|
use crate::config_manager::{
|
||||||
|
get_bucket_update, ConfigItem, DeviceConfigInfo, DeviceConfigInfos, RateLimiterConfigInfo,
|
||||||
|
};
|
||||||
|
use crate::device_manager::{
|
||||||
|
DbsMmioV2Device, DeviceManager, DeviceMgrError, DeviceOpContext, DeviceVirtioRegionHandler,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::DbsVirtioDevice;
|
||||||
|
|
||||||
|
// 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 = true;
|
||||||
|
// Default cache size is 2 Gi since this is a typical VM memory size.
|
||||||
|
const DEFAULT_CACHE_SIZE: u64 = 2 * 1024 * 1024 * 1024;
|
||||||
|
|
||||||
|
/// Errors associated with `FsDeviceConfig`.
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum FsDeviceError {
|
||||||
|
/// Invalid fs, "virtio" or "vhostuser" is allowed.
|
||||||
|
#[error("the fs type is invalid, virtio or vhostuser is allowed")]
|
||||||
|
InvalidFs,
|
||||||
|
|
||||||
|
/// Cannot access address space.
|
||||||
|
#[error("Cannot access address space.")]
|
||||||
|
AddressSpaceNotInitialized,
|
||||||
|
|
||||||
|
/// Cannot convert RateLimterConfigInfo into RateLimiter.
|
||||||
|
#[error("failure while converting RateLimterConfigInfo into RateLimiter: {0}")]
|
||||||
|
RateLimterConfigInfoTryInto(#[source] std::io::Error),
|
||||||
|
|
||||||
|
/// The fs device tag was already used for a different fs.
|
||||||
|
#[error("VirtioFs device tag {0} already exists")]
|
||||||
|
FsDeviceTagAlreadyExists(String),
|
||||||
|
|
||||||
|
/// The fs device path was already used for a different fs.
|
||||||
|
#[error("VirtioFs device tag {0} already exists")]
|
||||||
|
FsDevicePathAlreadyExists(String),
|
||||||
|
|
||||||
|
/// The update is not allowed after booting the microvm.
|
||||||
|
#[error("update operation is not allowed after boot")]
|
||||||
|
UpdateNotAllowedPostBoot,
|
||||||
|
|
||||||
|
/// The attachbackendfs operation fails.
|
||||||
|
#[error("Fs device attach a backend fs failed")]
|
||||||
|
AttachBackendFailed(String),
|
||||||
|
|
||||||
|
/// attach backend fs must be done when vm is running.
|
||||||
|
#[error("vm is not running when attaching a backend fs")]
|
||||||
|
MicroVMNotRunning,
|
||||||
|
|
||||||
|
/// The mount tag doesn't exist.
|
||||||
|
#[error("fs tag'{0}' doesn't exist")]
|
||||||
|
TagNotExists(String),
|
||||||
|
|
||||||
|
/// Failed to send patch message to VirtioFs epoll handler.
|
||||||
|
#[error("could not send patch message to the VirtioFs epoll handler")]
|
||||||
|
VirtioFsEpollHanderSendFail,
|
||||||
|
|
||||||
|
/// Creating a shared-fs device fails (if the vhost-user socket cannot be open.)
|
||||||
|
#[error("cannot create shared-fs device: {0}")]
|
||||||
|
CreateFsDevice(#[source] VirtIoError),
|
||||||
|
|
||||||
|
/// Cannot initialize a shared-fs device or add a device to the MMIO Bus.
|
||||||
|
#[error("failure while registering shared-fs device: {0}")]
|
||||||
|
RegisterFsDevice(#[source] DeviceMgrError),
|
||||||
|
|
||||||
|
/// The device manager errors.
|
||||||
|
#[error("DeviceManager error: {0}")]
|
||||||
|
DeviceManager(#[source] DeviceMgrError),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Configuration information for a vhost-user-fs device.
|
||||||
|
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||||
|
pub struct FsDeviceConfigInfo {
|
||||||
|
/// vhost-user socket path.
|
||||||
|
pub sock_path: String,
|
||||||
|
/// virtiofs mount tag name used inside the guest.
|
||||||
|
/// used as the device name during mount.
|
||||||
|
pub tag: String,
|
||||||
|
/// Number of virtqueues to use.
|
||||||
|
pub num_queues: usize,
|
||||||
|
/// Size of each virtqueue. Unit: byte.
|
||||||
|
pub queue_size: u16,
|
||||||
|
/// DAX cache window size
|
||||||
|
pub cache_size: u64,
|
||||||
|
/// Number of thread pool workers.
|
||||||
|
pub thread_pool_size: u16,
|
||||||
|
/// The caching policy the file system should use (auto, always or never).
|
||||||
|
/// This cache policy is set for virtio-fs, visit https://gitlab.com/virtio-fs/virtiofsd to get further information.
|
||||||
|
pub cache_policy: String,
|
||||||
|
/// Writeback cache
|
||||||
|
pub writeback_cache: bool,
|
||||||
|
/// Enable no_open or not
|
||||||
|
pub no_open: bool,
|
||||||
|
/// Enable xattr or not
|
||||||
|
pub xattr: bool,
|
||||||
|
/// Drop CAP_SYS_RESOURCE or not
|
||||||
|
pub drop_sys_resource: bool,
|
||||||
|
/// virtio fs or vhostuser fs.
|
||||||
|
pub mode: String,
|
||||||
|
/// Enable kill_priv_v2 or not
|
||||||
|
pub fuse_killpriv_v2: bool,
|
||||||
|
/// Enable no_readdir or not
|
||||||
|
pub no_readdir: bool,
|
||||||
|
/// Rate Limiter for I/O operations.
|
||||||
|
pub rate_limiter: Option<RateLimiterConfigInfo>,
|
||||||
|
/// Use shared irq
|
||||||
|
pub use_shared_irq: Option<bool>,
|
||||||
|
/// Use generic irq
|
||||||
|
pub use_generic_irq: Option<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::default::Default for FsDeviceConfigInfo {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
sock_path: String::default(),
|
||||||
|
tag: String::default(),
|
||||||
|
num_queues: 1,
|
||||||
|
queue_size: 1024,
|
||||||
|
cache_size: DEFAULT_CACHE_SIZE,
|
||||||
|
thread_pool_size: 0,
|
||||||
|
cache_policy: Self::default_cache_policy(),
|
||||||
|
writeback_cache: Self::default_writeback_cache(),
|
||||||
|
no_open: Self::default_no_open(),
|
||||||
|
fuse_killpriv_v2: Self::default_fuse_killpriv_v2(),
|
||||||
|
no_readdir: Self::default_no_readdir(),
|
||||||
|
xattr: Self::default_xattr(),
|
||||||
|
drop_sys_resource: Self::default_drop_sys_resource(),
|
||||||
|
mode: Self::default_fs_mode(),
|
||||||
|
rate_limiter: Some(RateLimiterConfigInfo::default()),
|
||||||
|
use_shared_irq: None,
|
||||||
|
use_generic_irq: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FsDeviceConfigInfo {
|
||||||
|
/// The default mode is set to 'virtio' for 'virtio-fs' device.
|
||||||
|
pub fn default_fs_mode() -> String {
|
||||||
|
String::from("virtio")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The default cache policy
|
||||||
|
pub fn default_cache_policy() -> String {
|
||||||
|
"always".to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The default setting of writeback cache
|
||||||
|
pub fn default_writeback_cache() -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The default setting of no_open
|
||||||
|
pub fn default_no_open() -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The default setting of killpriv_v2
|
||||||
|
pub fn default_fuse_killpriv_v2() -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The default setting of xattr
|
||||||
|
pub fn default_xattr() -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The default setting of drop_sys_resource
|
||||||
|
pub fn default_drop_sys_resource() -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The default setting of no_readdir
|
||||||
|
pub fn default_no_readdir() -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The default setting of rate limiter
|
||||||
|
pub fn default_fs_rate_limiter() -> Option<RateLimiterConfigInfo> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Configuration information for virtio-fs.
|
||||||
|
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||||
|
pub struct FsDeviceConfigUpdateInfo {
|
||||||
|
/// virtiofs mount tag name used inside the guest.
|
||||||
|
/// used as the device name during mount.
|
||||||
|
pub tag: String,
|
||||||
|
/// Rate Limiter for I/O operations.
|
||||||
|
pub rate_limiter: Option<RateLimiterConfigInfo>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FsDeviceConfigUpdateInfo {
|
||||||
|
/// Provides a `BucketUpdate` description for the bandwidth rate limiter.
|
||||||
|
pub fn bytes(&self) -> dbs_utils::rate_limiter::BucketUpdate {
|
||||||
|
get_bucket_update!(self, rate_limiter, bandwidth)
|
||||||
|
}
|
||||||
|
/// Provides a `BucketUpdate` description for the ops rate limiter.
|
||||||
|
pub fn ops(&self) -> dbs_utils::rate_limiter::BucketUpdate {
|
||||||
|
get_bucket_update!(self, rate_limiter, ops)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConfigItem for FsDeviceConfigInfo {
|
||||||
|
type Err = FsDeviceError;
|
||||||
|
|
||||||
|
fn id(&self) -> &str {
|
||||||
|
&self.tag
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_conflicts(&self, other: &Self) -> Result<(), FsDeviceError> {
|
||||||
|
if self.tag == other.tag {
|
||||||
|
Err(FsDeviceError::FsDeviceTagAlreadyExists(self.tag.clone()))
|
||||||
|
} else if self.mode.as_str() == "vhostuser" && self.sock_path == other.sock_path {
|
||||||
|
Err(FsDeviceError::FsDevicePathAlreadyExists(
|
||||||
|
self.sock_path.clone(),
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Configuration information of manipulating backend fs for a virtiofs device.
|
||||||
|
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||||
|
pub struct FsMountConfigInfo {
|
||||||
|
/// Mount operations, mount, update, umount
|
||||||
|
pub ops: String,
|
||||||
|
/// The backend fs type to mount.
|
||||||
|
pub fstype: Option<String>,
|
||||||
|
/// the source file/directory the backend fs points to
|
||||||
|
pub source: Option<String>,
|
||||||
|
/// where the backend fs gets mounted
|
||||||
|
pub mountpoint: String,
|
||||||
|
/// backend fs config content in json format
|
||||||
|
pub config: Option<String>,
|
||||||
|
/// virtiofs mount tag name used inside the guest.
|
||||||
|
/// used as the device name during mount.
|
||||||
|
pub tag: String,
|
||||||
|
/// Path to file that contains file lists that should be prefetched by rafs
|
||||||
|
pub prefetch_list_path: Option<String>,
|
||||||
|
/// What size file supports dax
|
||||||
|
pub dax_threshold_size_kb: Option<u64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) type FsDeviceInfo = DeviceConfigInfo<FsDeviceConfigInfo>;
|
||||||
|
|
||||||
|
impl ConfigItem for FsDeviceInfo {
|
||||||
|
type Err = FsDeviceError;
|
||||||
|
fn id(&self) -> &str {
|
||||||
|
&self.config.tag
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_conflicts(&self, other: &Self) -> Result<(), FsDeviceError> {
|
||||||
|
if self.config.tag == other.config.tag {
|
||||||
|
Err(FsDeviceError::FsDeviceTagAlreadyExists(
|
||||||
|
self.config.tag.clone(),
|
||||||
|
))
|
||||||
|
} else if self.config.sock_path == other.config.sock_path {
|
||||||
|
Err(FsDeviceError::FsDevicePathAlreadyExists(
|
||||||
|
self.config.sock_path.clone(),
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wrapper for the collection that holds all the Fs Devices Configs
|
||||||
|
pub struct FsDeviceMgr {
|
||||||
|
/// A list of `FsDeviceConfig` objects.
|
||||||
|
pub(crate) info_list: DeviceConfigInfos<FsDeviceConfigInfo>,
|
||||||
|
pub(crate) use_shared_irq: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FsDeviceMgr {
|
||||||
|
/// Inserts `fs_cfg` in the shared-fs device configuration list.
|
||||||
|
pub fn insert_device(
|
||||||
|
device_mgr: &mut DeviceManager,
|
||||||
|
ctx: DeviceOpContext,
|
||||||
|
fs_cfg: FsDeviceConfigInfo,
|
||||||
|
) -> std::result::Result<(), FsDeviceError> {
|
||||||
|
// It's too complicated to manage life cycle of shared-fs service process for hotplug.
|
||||||
|
if ctx.is_hotplug {
|
||||||
|
error!(
|
||||||
|
ctx.logger(),
|
||||||
|
"no support of shared-fs device hotplug";
|
||||||
|
"subsystem" => "shared-fs",
|
||||||
|
"tag" => &fs_cfg.tag,
|
||||||
|
);
|
||||||
|
return Err(FsDeviceError::UpdateNotAllowedPostBoot);
|
||||||
|
}
|
||||||
|
|
||||||
|
info!(
|
||||||
|
ctx.logger(),
|
||||||
|
"add shared-fs device configuration";
|
||||||
|
"subsystem" => "shared-fs",
|
||||||
|
"tag" => &fs_cfg.tag,
|
||||||
|
);
|
||||||
|
device_mgr
|
||||||
|
.fs_manager
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.info_list
|
||||||
|
.insert_or_update(&fs_cfg)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Attaches all vhost-user-fs devices from the FsDevicesConfig.
|
||||||
|
pub fn attach_devices(
|
||||||
|
&mut self,
|
||||||
|
ctx: &mut DeviceOpContext,
|
||||||
|
) -> std::result::Result<(), FsDeviceError> {
|
||||||
|
let epoll_mgr = ctx
|
||||||
|
.epoll_mgr
|
||||||
|
.clone()
|
||||||
|
.ok_or(FsDeviceError::CreateFsDevice(virtio::Error::InvalidInput))?;
|
||||||
|
|
||||||
|
for info in self.info_list.iter_mut() {
|
||||||
|
let device = Self::create_fs_device(&info.config, ctx, epoll_mgr.clone())?;
|
||||||
|
let mmio_device = DeviceManager::create_mmio_virtio_device(
|
||||||
|
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(FsDeviceError::RegisterFsDevice)?;
|
||||||
|
|
||||||
|
info.set_device(mmio_device);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_fs_device(
|
||||||
|
config: &FsDeviceConfigInfo,
|
||||||
|
ctx: &mut DeviceOpContext,
|
||||||
|
epoll_mgr: EpollManager,
|
||||||
|
) -> std::result::Result<DbsVirtioDevice, FsDeviceError> {
|
||||||
|
match config.mode.as_str() {
|
||||||
|
"virtio" => Self::attach_virtio_fs_devices(config, ctx, epoll_mgr),
|
||||||
|
_ => Err(FsDeviceError::CreateFsDevice(virtio::Error::InvalidInput)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn attach_virtio_fs_devices(
|
||||||
|
config: &FsDeviceConfigInfo,
|
||||||
|
ctx: &mut DeviceOpContext,
|
||||||
|
epoll_mgr: EpollManager,
|
||||||
|
) -> std::result::Result<DbsVirtioDevice, FsDeviceError> {
|
||||||
|
info!(
|
||||||
|
ctx.logger(),
|
||||||
|
"add virtio-fs device configuration";
|
||||||
|
"subsystem" => "virito-fs",
|
||||||
|
"tag" => &config.tag,
|
||||||
|
"dax_window_size" => &config.cache_size,
|
||||||
|
);
|
||||||
|
|
||||||
|
let limiter = if let Some(rlc) = config.rate_limiter.clone() {
|
||||||
|
Some(
|
||||||
|
rlc.try_into()
|
||||||
|
.map_err(FsDeviceError::RateLimterConfigInfoTryInto)?,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
let vm_as = ctx.get_vm_as().map_err(|e| {
|
||||||
|
error!(ctx.logger(), "virtio-fs get vm_as error: {:?}", e;
|
||||||
|
"subsystem" => "virito-fs");
|
||||||
|
FsDeviceError::DeviceManager(e)
|
||||||
|
})?;
|
||||||
|
let address_space = match ctx.address_space.as_ref() {
|
||||||
|
Some(address_space) => address_space.clone(),
|
||||||
|
None => {
|
||||||
|
error!(ctx.logger(), "virtio-fs get address_space error"; "subsystem" => "virito-fs");
|
||||||
|
return Err(FsDeviceError::AddressSpaceNotInitialized);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let handler = DeviceVirtioRegionHandler {
|
||||||
|
vm_as,
|
||||||
|
address_space,
|
||||||
|
};
|
||||||
|
|
||||||
|
let device = Box::new(
|
||||||
|
virtio::fs::VirtioFs::new(
|
||||||
|
&config.tag,
|
||||||
|
config.num_queues,
|
||||||
|
config.queue_size,
|
||||||
|
config.cache_size,
|
||||||
|
&config.cache_policy,
|
||||||
|
config.thread_pool_size,
|
||||||
|
config.writeback_cache,
|
||||||
|
config.no_open,
|
||||||
|
config.fuse_killpriv_v2,
|
||||||
|
config.xattr,
|
||||||
|
config.drop_sys_resource,
|
||||||
|
config.no_readdir,
|
||||||
|
Box::new(handler),
|
||||||
|
epoll_mgr,
|
||||||
|
limiter,
|
||||||
|
)
|
||||||
|
.map_err(FsDeviceError::CreateFsDevice)?,
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(device)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Attach a backend fs to a VirtioFs device or detach a backend
|
||||||
|
/// fs from a Virtiofs device
|
||||||
|
pub fn manipulate_backend_fs(
|
||||||
|
device_mgr: &mut DeviceManager,
|
||||||
|
config: FsMountConfigInfo,
|
||||||
|
) -> std::result::Result<(), FsDeviceError> {
|
||||||
|
let mut found = false;
|
||||||
|
|
||||||
|
let mgr = &mut device_mgr.fs_manager.lock().unwrap();
|
||||||
|
for info in mgr
|
||||||
|
.info_list
|
||||||
|
.iter()
|
||||||
|
.filter(|info| info.config.tag.as_str() == config.tag.as_str())
|
||||||
|
{
|
||||||
|
found = true;
|
||||||
|
if let Some(device) = info.device.as_ref() {
|
||||||
|
if let Some(mmio_dev) = device.as_any().downcast_ref::<DbsMmioV2Device>() {
|
||||||
|
let mut guard = mmio_dev.state();
|
||||||
|
let inner_dev = guard.get_inner_device_mut();
|
||||||
|
if let Some(virtio_fs_dev) = inner_dev
|
||||||
|
.as_any_mut()
|
||||||
|
.downcast_mut::<virtio::fs::VirtioFs<GuestAddressSpaceImpl>>()
|
||||||
|
{
|
||||||
|
return virtio_fs_dev
|
||||||
|
.manipulate_backend_fs(
|
||||||
|
config.source,
|
||||||
|
config.fstype,
|
||||||
|
&config.mountpoint,
|
||||||
|
config.config,
|
||||||
|
&config.ops,
|
||||||
|
config.prefetch_list_path,
|
||||||
|
config.dax_threshold_size_kb,
|
||||||
|
)
|
||||||
|
.map(|_p| ())
|
||||||
|
.map_err(|e| FsDeviceError::AttachBackendFailed(e.to_string()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
Err(FsDeviceError::AttachBackendFailed(
|
||||||
|
"fs tag not found".to_string(),
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the index of the device with the specified `tag` if it exists in the list.
|
||||||
|
pub fn get_index_of_tag(&self, tag: &str) -> Option<usize> {
|
||||||
|
self.info_list
|
||||||
|
.iter()
|
||||||
|
.position(|info| info.config.id().eq(tag))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Update the ratelimiter settings of a virtio fs device.
|
||||||
|
pub fn update_device_ratelimiters(
|
||||||
|
device_mgr: &mut DeviceManager,
|
||||||
|
new_cfg: FsDeviceConfigUpdateInfo,
|
||||||
|
) -> std::result::Result<(), FsDeviceError> {
|
||||||
|
let mgr = &mut device_mgr.fs_manager.lock().unwrap();
|
||||||
|
match mgr.get_index_of_tag(&new_cfg.tag) {
|
||||||
|
Some(index) => {
|
||||||
|
let config = &mut mgr.info_list[index].config;
|
||||||
|
config.rate_limiter = new_cfg.rate_limiter.clone();
|
||||||
|
let device = mgr.info_list[index]
|
||||||
|
.device
|
||||||
|
.as_mut()
|
||||||
|
.ok_or_else(|| FsDeviceError::TagNotExists("".to_owned()))?;
|
||||||
|
|
||||||
|
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(fs_dev) = inner_dev
|
||||||
|
.as_any()
|
||||||
|
.downcast_ref::<virtio::fs::VirtioFs<GuestAddressSpaceImpl>>()
|
||||||
|
{
|
||||||
|
return fs_dev
|
||||||
|
.set_patch_rate_limiters(new_cfg.bytes(), new_cfg.ops())
|
||||||
|
.map(|_p| ())
|
||||||
|
.map_err(|_e| FsDeviceError::VirtioFsEpollHanderSendFail);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
None => Err(FsDeviceError::TagNotExists(new_cfg.tag)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for FsDeviceMgr {
|
||||||
|
/// Create a new `FsDeviceMgr` object..
|
||||||
|
fn default() -> Self {
|
||||||
|
FsDeviceMgr {
|
||||||
|
info_list: DeviceConfigInfos::new(),
|
||||||
|
use_shared_irq: USE_SHARED_IRQ,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
110
src/dragonball/src/device_manager/memory_region_handler.rs
Normal file
110
src/dragonball/src/device_manager/memory_region_handler.rs
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
// Copyright 2022 Alibaba, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
use std::io;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use dbs_address_space::{AddressSpace, AddressSpaceRegion, AddressSpaceRegionType};
|
||||||
|
use dbs_virtio_devices::{Error as VirtIoError, VirtioRegionHandler};
|
||||||
|
use log::{debug, error};
|
||||||
|
use vm_memory::{FileOffset, GuestAddressSpace, GuestMemoryRegion, GuestRegionMmap};
|
||||||
|
|
||||||
|
use crate::address_space_manager::GuestAddressSpaceImpl;
|
||||||
|
|
||||||
|
/// This struct implements the VirtioRegionHandler trait, which inserts the memory
|
||||||
|
/// region of the virtio device into vm_as and address_space.
|
||||||
|
///
|
||||||
|
/// * After region is inserted into the vm_as, the virtio device can read guest memory
|
||||||
|
/// data using vm_as.get_slice with GuestAddress.
|
||||||
|
///
|
||||||
|
/// * Insert virtio memory into address_space so that the correct guest last address can
|
||||||
|
/// be found when initializing the e820 table. The e820 table is a table that describes
|
||||||
|
/// guest memory prepared before the guest startup. we need to config the correct guest
|
||||||
|
/// memory address and length in the table. The virtio device memory belongs to the MMIO
|
||||||
|
/// space and does not belong to the Guest Memory space. Therefore, it cannot be configured
|
||||||
|
/// into the e820 table. When creating AddressSpaceRegion we use
|
||||||
|
/// AddressSpaceRegionType::ReservedMemory type, in this way, address_space will know that
|
||||||
|
/// this region a special memory, it will don't put the this memory in e820 table.
|
||||||
|
///
|
||||||
|
/// This function relies on the atomic-guest-memory feature. Without this feature enabled, memory
|
||||||
|
/// regions cannot be inserted into vm_as. Because the insert_region interface of vm_as does
|
||||||
|
/// not insert regions in place, but returns an array of inserted regions. We need to manually
|
||||||
|
/// replace this array of regions with vm_as, and that's what atomic-guest-memory feature does.
|
||||||
|
/// So we rely on the atomic-guest-memory feature here
|
||||||
|
pub struct DeviceVirtioRegionHandler {
|
||||||
|
pub(crate) vm_as: GuestAddressSpaceImpl,
|
||||||
|
pub(crate) address_space: AddressSpace,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DeviceVirtioRegionHandler {
|
||||||
|
fn insert_address_space(
|
||||||
|
&mut self,
|
||||||
|
region: Arc<GuestRegionMmap>,
|
||||||
|
) -> std::result::Result<(), VirtIoError> {
|
||||||
|
let file_offset = match region.file_offset() {
|
||||||
|
// TODO: use from_arc
|
||||||
|
Some(f) => Some(FileOffset::new(f.file().try_clone()?, 0)),
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let as_region = Arc::new(AddressSpaceRegion::build(
|
||||||
|
AddressSpaceRegionType::DAXMemory,
|
||||||
|
region.start_addr(),
|
||||||
|
region.size() as u64,
|
||||||
|
None,
|
||||||
|
file_offset,
|
||||||
|
region.flags(),
|
||||||
|
false,
|
||||||
|
));
|
||||||
|
|
||||||
|
self.address_space.insert_region(as_region).map_err(|e| {
|
||||||
|
error!("inserting address apace error: {}", e);
|
||||||
|
// dbs-virtio-devices should not depend on dbs-address-space.
|
||||||
|
// So here io::Error is used instead of AddressSpaceError directly.
|
||||||
|
VirtIoError::IOError(io::Error::new(
|
||||||
|
io::ErrorKind::Other,
|
||||||
|
format!(
|
||||||
|
"invalid address space region ({0:#x}, {1:#x})",
|
||||||
|
region.start_addr().0,
|
||||||
|
region.len()
|
||||||
|
),
|
||||||
|
))
|
||||||
|
})?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn insert_vm_as(
|
||||||
|
&mut self,
|
||||||
|
region: Arc<GuestRegionMmap>,
|
||||||
|
) -> std::result::Result<(), VirtIoError> {
|
||||||
|
let vm_as_new = self.vm_as.memory().insert_region(region).map_err(|e| {
|
||||||
|
error!(
|
||||||
|
"DeviceVirtioRegionHandler failed to insert guest memory region: {:?}.",
|
||||||
|
e
|
||||||
|
);
|
||||||
|
VirtIoError::InsertMmap(e)
|
||||||
|
})?;
|
||||||
|
// Do not expect poisoned lock here, so safe to unwrap().
|
||||||
|
self.vm_as.lock().unwrap().replace(vm_as_new);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VirtioRegionHandler for DeviceVirtioRegionHandler {
|
||||||
|
fn insert_region(
|
||||||
|
&mut self,
|
||||||
|
region: Arc<GuestRegionMmap>,
|
||||||
|
) -> std::result::Result<(), VirtIoError> {
|
||||||
|
debug!(
|
||||||
|
"add geust memory region to address_space/vm_as, new region: {:?}",
|
||||||
|
region
|
||||||
|
);
|
||||||
|
|
||||||
|
self.insert_address_space(region.clone())?;
|
||||||
|
self.insert_vm_as(region)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
@ -71,6 +71,16 @@ pub mod virtio_net_dev_mgr;
|
|||||||
#[cfg(feature = "virtio-net")]
|
#[cfg(feature = "virtio-net")]
|
||||||
use self::virtio_net_dev_mgr::VirtioNetDeviceMgr;
|
use self::virtio_net_dev_mgr::VirtioNetDeviceMgr;
|
||||||
|
|
||||||
|
#[cfg(feature = "virtio-fs")]
|
||||||
|
/// virtio-block device manager
|
||||||
|
pub mod fs_dev_mgr;
|
||||||
|
#[cfg(feature = "virtio-fs")]
|
||||||
|
use self::fs_dev_mgr::FsDeviceMgr;
|
||||||
|
#[cfg(feature = "virtio-fs")]
|
||||||
|
mod memory_region_handler;
|
||||||
|
#[cfg(feature = "virtio-fs")]
|
||||||
|
pub use self::memory_region_handler::*;
|
||||||
|
|
||||||
macro_rules! info(
|
macro_rules! info(
|
||||||
($l:expr, $($args:tt)+) => {
|
($l:expr, $($args:tt)+) => {
|
||||||
slog::info!($l, $($args)+; slog::o!("subsystem" => "device_manager"))
|
slog::info!($l, $($args)+; slog::o!("subsystem" => "device_manager"))
|
||||||
@ -435,6 +445,9 @@ pub struct DeviceManager {
|
|||||||
|
|
||||||
#[cfg(feature = "virtio-net")]
|
#[cfg(feature = "virtio-net")]
|
||||||
pub(crate) virtio_net_manager: VirtioNetDeviceMgr,
|
pub(crate) virtio_net_manager: VirtioNetDeviceMgr,
|
||||||
|
|
||||||
|
#[cfg(feature = "virtio-fs")]
|
||||||
|
fs_manager: Arc<Mutex<FsDeviceMgr>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DeviceManager {
|
impl DeviceManager {
|
||||||
@ -463,6 +476,8 @@ impl DeviceManager {
|
|||||||
block_manager: BlockDeviceMgr::default(),
|
block_manager: BlockDeviceMgr::default(),
|
||||||
#[cfg(feature = "virtio-net")]
|
#[cfg(feature = "virtio-net")]
|
||||||
virtio_net_manager: VirtioNetDeviceMgr::default(),
|
virtio_net_manager: VirtioNetDeviceMgr::default(),
|
||||||
|
#[cfg(feature = "virtio-fs")]
|
||||||
|
fs_manager: Arc::new(Mutex::new(FsDeviceMgr::default())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -588,6 +603,14 @@ impl DeviceManager {
|
|||||||
.attach_devices(&mut ctx)
|
.attach_devices(&mut ctx)
|
||||||
.map_err(StartMicrovmError::BlockDeviceError)?;
|
.map_err(StartMicrovmError::BlockDeviceError)?;
|
||||||
|
|
||||||
|
#[cfg(feature = "virtio-fs")]
|
||||||
|
{
|
||||||
|
let mut fs_manager = self.fs_manager.lock().unwrap();
|
||||||
|
fs_manager
|
||||||
|
.attach_devices(&mut ctx)
|
||||||
|
.map_err(StartMicrovmError::FsDeviceError)?;
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "virtio-net")]
|
#[cfg(feature = "virtio-net")]
|
||||||
self.virtio_net_manager
|
self.virtio_net_manager
|
||||||
.attach_devices(&mut ctx)
|
.attach_devices(&mut ctx)
|
||||||
|
@ -168,6 +168,11 @@ pub enum StartMicroVmError {
|
|||||||
/// Virtio-net errors.
|
/// Virtio-net errors.
|
||||||
#[error("virtio-net errors: {0}")]
|
#[error("virtio-net errors: {0}")]
|
||||||
VirtioNetDeviceError(#[source] device_manager::virtio_net_dev_mgr::VirtioNetDeviceError),
|
VirtioNetDeviceError(#[source] device_manager::virtio_net_dev_mgr::VirtioNetDeviceError),
|
||||||
|
|
||||||
|
#[cfg(feature = "virtio-fs")]
|
||||||
|
/// Virtio-fs errors.
|
||||||
|
#[error("virtio-fs errors: {0}")]
|
||||||
|
FsDeviceError(#[source] device_manager::fs_dev_mgr::FsDeviceError),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Errors associated with starting the instance.
|
/// Errors associated with starting the instance.
|
||||||
|
Loading…
Reference in New Issue
Block a user