runtime-rs: Add BlockDeviceModern driver

Add a modern block device driver using the Arc<Mutex> 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 <alex.lyn@antgroup.com>
Signed-off-by: Fabiano Fidêncio <ffidencio@nvidia.com>
This commit is contained in:
Alex Lyn
2026-04-12 16:21:02 +02:00
committed by Fabiano Fidêncio
parent 443dd81f92
commit 4b6d62ca51
5 changed files with 222 additions and 2 deletions

View File

@@ -255,7 +255,8 @@ impl DeviceManager {
| DeviceType::Vsock(_)
| DeviceType::Protection(_)
| DeviceType::PortDevice(_)
| DeviceType::VfioModern(_) => {
| DeviceType::VfioModern(_)
| DeviceType::BlockModern(_) => {
continue;
}
}

View File

@@ -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,
};

View File

@@ -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;
}

View File

@@ -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<bool>,
/// 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<PciPath>,
/// 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<String>,
/// 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<Mutex<BlockDeviceModern>>,
}
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<Mutex<BlockDeviceModern>> {
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<Option<u64>> {
// 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<bool> {
let mut guard = self.inner.lock().await;
do_increase_count(&mut guard.attach_count)
}
async fn decrease_attach_count(&mut self) -> Result<bool> {
let mut guard = self.inner.lock().await;
do_decrease_count(&mut guard.attach_count)
}
}

View File

@@ -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<Mutex<VfioDeviceModern>>),
BlockModern(Arc<Mutex<BlockDeviceModern>>),
}
impl fmt::Display for DeviceType {