From 4b6d62ca51e97be5b5ea3021749f91971d4cc361 Mon Sep 17 00:00:00 2001 From: Alex Lyn Date: Sun, 12 Apr 2026 16:21:02 +0200 Subject: [PATCH] runtime-rs: Add BlockDeviceModern driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a modern block device driver using the Arc pattern for interior mutability, matching the VfioDeviceModern approach. The driver implements the Device trait with attach/detach/hotplug lifecycle management, and supports BlockConfigModern with logical and physical sector size fields. Add the DeviceType::BlockModern enum variant so the driver compiles. The device_manager and hypervisor cold-plug wiring follow in subsequent commits. Signed-off-by: Alex Lyn Signed-off-by: Fabiano FidĂȘncio --- .../hypervisor/src/device/device_manager.rs | 3 +- .../hypervisor/src/device/driver/mod.rs | 2 + .../src/device/driver/virtio_blk.rs | 1 - .../src/device/driver/virtio_blk_modern.rs | 216 ++++++++++++++++++ .../crates/hypervisor/src/device/mod.rs | 2 + 5 files changed, 222 insertions(+), 2 deletions(-) create mode 100644 src/runtime-rs/crates/hypervisor/src/device/driver/virtio_blk_modern.rs diff --git a/src/runtime-rs/crates/hypervisor/src/device/device_manager.rs b/src/runtime-rs/crates/hypervisor/src/device/device_manager.rs index e2e16fd9fe..7511f350c1 100644 --- a/src/runtime-rs/crates/hypervisor/src/device/device_manager.rs +++ b/src/runtime-rs/crates/hypervisor/src/device/device_manager.rs @@ -255,7 +255,8 @@ impl DeviceManager { | DeviceType::Vsock(_) | DeviceType::Protection(_) | DeviceType::PortDevice(_) - | DeviceType::VfioModern(_) => { + | DeviceType::VfioModern(_) + | DeviceType::BlockModern(_) => { continue; } } diff --git a/src/runtime-rs/crates/hypervisor/src/device/driver/mod.rs b/src/runtime-rs/crates/hypervisor/src/device/driver/mod.rs index 277a4420a4..4e6496988a 100644 --- a/src/runtime-rs/crates/hypervisor/src/device/driver/mod.rs +++ b/src/runtime-rs/crates/hypervisor/src/device/driver/mod.rs @@ -12,6 +12,7 @@ mod vhost_user; pub mod vhost_user_blk; mod vhost_user_net; mod virtio_blk; +pub mod virtio_blk_modern; mod virtio_fs; mod virtio_net; mod virtio_vsock; @@ -30,6 +31,7 @@ pub use virtio_blk::{ KATA_MMIO_BLK_DEV_TYPE, KATA_NVDIMM_DEV_TYPE, KATA_SCSI_DEV_TYPE, VIRTIO_BLOCK_CCW, VIRTIO_BLOCK_MMIO, VIRTIO_BLOCK_PCI, VIRTIO_PMEM, }; +pub use virtio_blk_modern::{BlockConfigModern, BlockDeviceModern, BlockDeviceModernHandle}; pub use virtio_fs::{ ShareFsConfig, ShareFsDevice, ShareFsMountConfig, ShareFsMountOperation, ShareFsMountType, }; diff --git a/src/runtime-rs/crates/hypervisor/src/device/driver/virtio_blk.rs b/src/runtime-rs/crates/hypervisor/src/device/driver/virtio_blk.rs index 0a56568560..21a30e6c04 100644 --- a/src/runtime-rs/crates/hypervisor/src/device/driver/virtio_blk.rs +++ b/src/runtime-rs/crates/hypervisor/src/device/driver/virtio_blk.rs @@ -156,7 +156,6 @@ impl Device for BlockDevice { match h.add_device(DeviceType::Block(self.clone())).await { Ok(dev) => { - // Update device info with the one received from device attach if let DeviceType::Block(blk) = dev { self.config = blk.config; } diff --git a/src/runtime-rs/crates/hypervisor/src/device/driver/virtio_blk_modern.rs b/src/runtime-rs/crates/hypervisor/src/device/driver/virtio_blk_modern.rs new file mode 100644 index 0000000000..1cd8152435 --- /dev/null +++ b/src/runtime-rs/crates/hypervisor/src/device/driver/virtio_blk_modern.rs @@ -0,0 +1,216 @@ +// Copyright (c) 2022-2023 Alibaba Cloud +// Copyright (c) 2022-2023 Ant Group +// +// SPDX-License-Identifier: Apache-2.0 +// + +use std::sync::Arc; +use tokio::sync::Mutex; + +use crate::device::pci_path::PciPath; +use crate::device::topology::PCIeTopology; +use crate::device::util::do_decrease_count; +use crate::device::util::do_increase_count; +use crate::device::Device; +use crate::device::DeviceType; +use crate::Hypervisor as hypervisor; +use anyhow::{Context, Result}; +use async_trait::async_trait; + +#[derive(Clone, Copy, Debug, Default)] +pub enum BlockDeviceAio { + // IoUring is the Linux io_uring I/O implementation. + #[default] + IoUring, + + // Native is the native Linux AIO implementation. + Native, + + // Threads is the pthread asynchronous I/O implementation. + Threads, +} + +impl BlockDeviceAio { + pub fn new(aio: &str) -> Self { + match aio { + "native" => BlockDeviceAio::Native, + "threads" => BlockDeviceAio::Threads, + _ => BlockDeviceAio::IoUring, + } + } +} + +impl std::fmt::Display for BlockDeviceAio { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let to_string = match *self { + BlockDeviceAio::Native => "native".to_string(), + BlockDeviceAio::Threads => "threads".to_string(), + _ => "iouring".to_string(), + }; + write!(f, "{to_string}") + } +} + +#[derive(Debug, Clone, Default)] +pub struct BlockConfigModern { + /// Path of the drive. + pub path_on_host: String, + + /// If set to true, the drive is opened in read-only mode. Otherwise, the + /// drive is opened as read-write. + pub is_readonly: bool, + + /// Don't close `path_on_host` file when dropping the device. + pub no_drop: bool, + + /// Specifies cache-related options for block devices. + /// Denotes whether use of O_DIRECT (bypass the host page cache) is enabled. + /// If not set, use configurarion block_device_cache_direct. + pub is_direct: Option, + + /// device index + pub index: u64, + + /// blkdev_aio defines the type of asynchronous I/O the block device should use. + pub blkdev_aio: BlockDeviceAio, + + /// driver type for block device + pub driver_option: String, + + /// device path in guest + pub virt_path: String, + + /// pci path is the slot at which the drive is attached + pub pci_path: Option, + + /// scsi_addr of the block device, in case the device is attached using SCSI driver + /// scsi_addr is of the format SCSI-Id:LUN + pub scsi_addr: Option, + + /// device attach count + pub attach_count: u64, + + /// device major number + pub major: i64, + + /// device minor number + pub minor: i64, + + /// virtio queue size. size: byte + pub queue_size: u32, + + /// block device multi-queue + pub num_queues: usize, + + /// Logical sector size in bytes reported to the guest. 0 means use hypervisor default. + pub logical_sector_size: u32, + + /// Physical sector size in bytes reported to the guest. 0 means use hypervisor default. + pub physical_sector_size: u32, +} + +#[derive(Debug, Clone, Default)] +pub struct BlockDeviceModern { + pub device_id: String, + pub attach_count: u64, + pub config: BlockConfigModern, +} + +#[derive(Debug, Clone)] +pub struct BlockDeviceModernHandle { + inner: Arc>, +} + +impl BlockDeviceModernHandle { + pub fn new(device_id: String, config: BlockConfigModern) -> Self { + Self { + inner: Arc::new(Mutex::new(BlockDeviceModern { + device_id, + attach_count: 0, + config, + })), + } + } + + pub fn arc(&self) -> Arc> { + self.inner.clone() + } + + pub async fn snapshot_config(&self) -> BlockConfigModern { + self.inner.lock().await.config.clone() + } + + pub async fn device_id(&self) -> String { + self.inner.lock().await.device_id.clone() + } + + pub async fn attach_count(&self) -> u64 { + self.inner.lock().await.attach_count + } +} + +#[async_trait] +impl Device for BlockDeviceModernHandle { + async fn attach( + &mut self, + _pcie_topo: &mut Option<&mut PCIeTopology>, + h: &dyn hypervisor, + ) -> Result<()> { + // increase attach count, skip attach the device if the device is already attached + if self + .increase_attach_count() + .await + .context("failed to increase attach count")? + { + return Ok(()); + } + + if let Err(e) = h.add_device(DeviceType::BlockModern(self.arc())).await { + error!(sl!(), "failed to attach vfio device: {:?}", e); + self.decrease_attach_count().await?; + + return Err(e); + } + + Ok(()) + } + + async fn detach( + &mut self, + _pcie_topo: &mut Option<&mut PCIeTopology>, + h: &dyn hypervisor, + ) -> Result> { + // get the count of device detached, skip detach once it reaches the 0 + if self + .decrease_attach_count() + .await + .context("failed to decrease attach count")? + { + return Ok(None); + } + if let Err(e) = h.remove_device(DeviceType::BlockModern(self.arc())).await { + self.increase_attach_count().await?; + return Err(e); + } + Ok(Some(self.snapshot_config().await.index)) + } + + async fn update(&mut self, _h: &dyn hypervisor) -> Result<()> { + // There's no need to do update for virtio-blk + Ok(()) + } + + async fn get_device_info(&self) -> DeviceType { + DeviceType::BlockModern(self.inner.clone()) + } + + async fn increase_attach_count(&mut self) -> Result { + let mut guard = self.inner.lock().await; + do_increase_count(&mut guard.attach_count) + } + + async fn decrease_attach_count(&mut self) -> Result { + let mut guard = self.inner.lock().await; + do_decrease_count(&mut guard.attach_count) + } +} diff --git a/src/runtime-rs/crates/hypervisor/src/device/mod.rs b/src/runtime-rs/crates/hypervisor/src/device/mod.rs index bd819e02be..b3067fffeb 100644 --- a/src/runtime-rs/crates/hypervisor/src/device/mod.rs +++ b/src/runtime-rs/crates/hypervisor/src/device/mod.rs @@ -11,6 +11,7 @@ use tokio::sync::Mutex; use crate::device::driver::vhost_user_blk::VhostUserBlkDevice; use crate::device::driver::vfio_device::VfioDeviceModern; +use crate::device::driver::virtio_blk_modern::BlockDeviceModern; use crate::{ BlockConfig, BlockDevice, HybridVsockConfig, HybridVsockDevice, Hypervisor as hypervisor, NetworkConfig, NetworkDevice, PCIePortDevice, PortDeviceConfig, ProtectionDevice, @@ -57,6 +58,7 @@ pub enum DeviceType { Protection(ProtectionDevice), PortDevice(PCIePortDevice), VfioModern(Arc>), + BlockModern(Arc>), } impl fmt::Display for DeviceType {