agent: Move virtio-block device handlers to block_device_handler

Move virtio-block device handlers to block_device_handler to simplify
the code.

Signed-off-by: ChengyuZhu6 <chengyu.zhu@intel.com>
This commit is contained in:
ChengyuZhu6
2024-08-27 06:05:50 +08:00
parent 4e33665be8
commit bbf934161b
2 changed files with 210 additions and 176 deletions

View File

@@ -29,8 +29,8 @@ use protocols::agent::Device;
use tracing::instrument;
use kata_types::device::{
DRIVER_BLK_CCW_TYPE, DRIVER_BLK_MMIO_TYPE, DRIVER_BLK_PCI_TYPE, DRIVER_NVDIMM_TYPE,
DRIVER_SCSI_TYPE, DRIVER_VFIO_AP_TYPE, DRIVER_VFIO_PCI_GK_TYPE, DRIVER_VFIO_PCI_TYPE,
DRIVER_NVDIMM_TYPE, DRIVER_SCSI_TYPE, DRIVER_VFIO_AP_TYPE, DRIVER_VFIO_PCI_GK_TYPE,
DRIVER_VFIO_PCI_TYPE,
};
// Convenience function to obtain the scope logger.
@@ -43,7 +43,6 @@ const BLOCK: &str = "block";
cfg_if! {
if #[cfg(target_arch = "s390x")] {
use crate::ap;
use crate::ccw;
}
}
@@ -206,82 +205,6 @@ pub async fn get_scsi_device_name(
Ok(format!("{}/{}", SYSTEM_DEV_PATH, &uev.devname))
}
#[derive(Debug)]
struct VirtioBlkPciMatcher {
rex: Regex,
}
impl VirtioBlkPciMatcher {
fn new(relpath: &str) -> VirtioBlkPciMatcher {
let root_bus = create_pci_root_bus_path();
let re = format!(r"^{}{}/virtio[0-9]+/block/", root_bus, relpath);
VirtioBlkPciMatcher {
rex: Regex::new(&re).expect("BUG: failed to compile VirtioBlkPciMatcher regex"),
}
}
}
impl UeventMatcher for VirtioBlkPciMatcher {
fn is_match(&self, uev: &Uevent) -> bool {
uev.subsystem == BLOCK && self.rex.is_match(&uev.devpath) && !uev.devname.is_empty()
}
}
#[instrument]
pub async fn get_virtio_blk_pci_device_name(
sandbox: &Arc<Mutex<Sandbox>>,
pcipath: &pci::Path,
) -> Result<String> {
let root_bus_sysfs = format!("{}{}", SYSFS_DIR, create_pci_root_bus_path());
let sysfs_rel_path = pcipath_to_sysfs(&root_bus_sysfs, pcipath)?;
let matcher = VirtioBlkPciMatcher::new(&sysfs_rel_path);
let uev = wait_for_uevent(sandbox, matcher).await?;
Ok(format!("{}/{}", SYSTEM_DEV_PATH, &uev.devname))
}
#[cfg(target_arch = "s390x")]
#[derive(Debug)]
struct VirtioBlkCCWMatcher {
rex: Regex,
}
#[cfg(target_arch = "s390x")]
impl VirtioBlkCCWMatcher {
fn new(root_bus_path: &str, device: &ccw::Device) -> Self {
let re = format!(
r"^{}/0\.[0-3]\.[0-9a-f]{{1,4}}/{}/virtio[0-9]+/block/",
root_bus_path, device
);
VirtioBlkCCWMatcher {
rex: Regex::new(&re).expect("BUG: failed to compile VirtioBlkCCWMatcher regex"),
}
}
}
#[cfg(target_arch = "s390x")]
impl UeventMatcher for VirtioBlkCCWMatcher {
fn is_match(&self, uev: &Uevent) -> bool {
uev.action == "add" && self.rex.is_match(&uev.devpath) && !uev.devname.is_empty()
}
}
#[cfg(target_arch = "s390x")]
#[instrument]
pub async fn get_virtio_blk_ccw_device_name(
sandbox: &Arc<Mutex<Sandbox>>,
device: &ccw::Device,
) -> Result<String> {
let matcher = VirtioBlkCCWMatcher::new(CCW_ROOT_BUS_PATH, device);
let uev = wait_for_uevent(sandbox, matcher).await?;
let devname = uev.devname;
return match Path::new(SYSTEM_DEV_PATH).join(&devname).to_str() {
Some(path) => Ok(String::from(path)),
None => Err(anyhow!("CCW device name {} is not valid UTF-8", &devname)),
};
}
#[derive(Debug)]
struct PmemBlockMatcher {
suffix: String,
@@ -486,48 +409,6 @@ async fn wait_for_ap_device(sandbox: &Arc<Mutex<Sandbox>>, address: ap::Address)
Ok(())
}
#[derive(Debug)]
struct MmioBlockMatcher {
suffix: String,
}
impl MmioBlockMatcher {
fn new(devname: &str) -> MmioBlockMatcher {
MmioBlockMatcher {
suffix: format!(r"/block/{}", devname),
}
}
}
impl UeventMatcher for MmioBlockMatcher {
fn is_match(&self, uev: &Uevent) -> bool {
uev.subsystem == BLOCK && uev.devpath.ends_with(&self.suffix) && !uev.devname.is_empty()
}
}
#[instrument]
pub async fn get_virtio_mmio_device_name(
sandbox: &Arc<Mutex<Sandbox>>,
devpath: &str,
) -> Result<()> {
let devname = devpath
.strip_prefix("/dev/")
.ok_or_else(|| anyhow!("Storage source '{}' must start with /dev/", devpath))?;
let matcher = MmioBlockMatcher::new(devname);
let uev = wait_for_uevent(sandbox, matcher)
.await
.context("failed to wait for uevent")?;
if uev.devname != devname {
return Err(anyhow!(
"Unexpected device name {} for mmio device (expected {})",
uev.devname,
devname
));
}
Ok(())
}
/// Scan SCSI bus for the given SCSI address(SCSI-Id and LUN)
#[instrument]
fn scan_scsi_bus(scsi_addr: &str) -> Result<()> {
@@ -820,61 +701,6 @@ pub fn update_env_pci(
Ok(())
}
// device.Id should be the predicted device name (vda, vdb, ...)
// device.VmPath already provides a way to send it in
#[instrument]
async fn virtiommio_blk_device_handler(
device: &Device,
sandbox: &Arc<Mutex<Sandbox>>,
) -> Result<SpecUpdate> {
if device.vm_path.is_empty() {
return Err(anyhow!("Invalid path for virtio mmio blk device"));
}
if !Path::new(&device.vm_path).exists() {
get_virtio_mmio_device_name(sandbox, &device.vm_path.to_string())
.await
.context("failed to get mmio device name")?;
}
Ok(DeviceInfo::new(device.vm_path(), true)
.context("New device info")?
.into())
}
// device.Id should be a PCI path string
#[instrument]
async fn virtio_blk_device_handler(
device: &Device,
sandbox: &Arc<Mutex<Sandbox>>,
) -> Result<SpecUpdate> {
let pcipath = pci::Path::from_str(&device.id)?;
let vm_path = get_virtio_blk_pci_device_name(sandbox, &pcipath).await?;
Ok(DeviceInfo::new(&vm_path, true)
.context("New device info")?
.into())
}
// device.id should be a CCW path string
#[cfg(target_arch = "s390x")]
#[instrument]
async fn virtio_blk_ccw_device_handler(
device: &Device,
sandbox: &Arc<Mutex<Sandbox>>,
) -> Result<SpecUpdate> {
let ccw_device = ccw::Device::from_str(&device.id)?;
let vm_path = get_virtio_blk_ccw_device_name(sandbox, &ccw_device).await?;
Ok(DeviceInfo::new(&vm_path, true)?.into())
}
#[cfg(not(target_arch = "s390x"))]
#[instrument]
async fn virtio_blk_ccw_device_handler(_: &Device, _: &Arc<Mutex<Sandbox>>) -> Result<SpecUpdate> {
Err(anyhow!("CCW is only supported on s390x"))
}
// device.Id should be the SCSI address of the disk in the format "scsiID:lunID"
#[instrument]
async fn virtio_scsi_device_handler(

View File

@@ -0,0 +1,208 @@
// Copyright (c) 2019 Ant Financial
// Copyright (c) 2024 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
//
#[cfg(target_arch = "s390x")]
use crate::ccw;
use crate::device::{
pcipath_to_sysfs, DeviceContext, DeviceHandler, DeviceInfo, SpecUpdate, BLOCK,
};
#[cfg(target_arch = "s390x")]
use crate::linux_abi::CCW_ROOT_BUS_PATH;
use crate::linux_abi::{create_pci_root_bus_path, SYSFS_DIR, SYSTEM_DEV_PATH};
use crate::pci;
use crate::sandbox::Sandbox;
use crate::uevent::{wait_for_uevent, Uevent, UeventMatcher};
use anyhow::{anyhow, Context, Result};
use protocols::agent::Device;
use regex::Regex;
use std::path::Path;
use std::str::FromStr;
use std::sync::Arc;
use tokio::sync::Mutex;
use tracing::instrument;
#[derive(Debug)]
pub struct VirtioBlkPciDeviceHandler {}
#[derive(Debug)]
pub struct VirtioBlkCcwDeviceHandler {}
#[derive(Debug)]
pub struct VirtioBlkMmioDeviceHandler {}
#[async_trait::async_trait]
impl DeviceHandler for VirtioBlkPciDeviceHandler {
#[instrument]
async fn device_handler(&self, device: &Device, ctx: &mut DeviceContext) -> Result<SpecUpdate> {
let pcipath = pci::Path::from_str(&device.id)?;
let vm_path = get_virtio_blk_pci_device_name(ctx.sandbox, &pcipath).await?;
Ok(DeviceInfo::new(&vm_path, true)
.context("New device info")?
.into())
}
}
#[async_trait::async_trait]
impl DeviceHandler for VirtioBlkCcwDeviceHandler {
#[cfg(target_arch = "s390x")]
#[instrument]
async fn device_handler(&self, device: &Device, ctx: &mut DeviceContext) -> Result<SpecUpdate> {
let ccw_device = ccw::Device::from_str(&device.id)?;
let vm_path = get_virtio_blk_ccw_device_name(ctx.sandbox, &ccw_device).await?;
Ok(DeviceInfo::new(&vm_path, true)
.context("New device info")?
.into())
}
#[cfg(not(target_arch = "s390x"))]
async fn device_handler(
&self,
_device: &Device,
_ctx: &mut DeviceContext,
) -> Result<SpecUpdate> {
Err(anyhow!("CCW is only supported on s390x"))
}
}
#[async_trait::async_trait]
impl DeviceHandler for VirtioBlkMmioDeviceHandler {
#[instrument]
async fn device_handler(&self, device: &Device, ctx: &mut DeviceContext) -> Result<SpecUpdate> {
if device.vm_path.is_empty() {
return Err(anyhow!("Invalid path for virtio mmio blk device"));
}
if !Path::new(&device.vm_path).exists() {
get_virtio_blk_mmio_device_name(ctx.sandbox, &device.vm_path.to_string())
.await
.context("failed to get mmio device name")?;
}
Ok(DeviceInfo::new(device.vm_path(), true)
.context("New device info")?
.into())
}
}
#[instrument]
pub async fn get_virtio_blk_pci_device_name(
sandbox: &Arc<Mutex<Sandbox>>,
pcipath: &pci::Path,
) -> Result<String> {
let root_bus_sysfs = format!("{}{}", SYSFS_DIR, create_pci_root_bus_path());
let sysfs_rel_path = pcipath_to_sysfs(&root_bus_sysfs, pcipath)?;
let matcher = VirtioBlkPciMatcher::new(&sysfs_rel_path);
let uev = wait_for_uevent(sandbox, matcher).await?;
Ok(format!("{}/{}", SYSTEM_DEV_PATH, &uev.devname))
}
#[instrument]
pub async fn get_virtio_blk_mmio_device_name(
sandbox: &Arc<Mutex<Sandbox>>,
devpath: &str,
) -> Result<()> {
let devname = devpath
.strip_prefix("/dev/")
.ok_or_else(|| anyhow!("Storage source '{}' must start with /dev/", devpath))?;
let matcher = VirtioBlkMmioMatcher::new(devname);
let uev = wait_for_uevent(sandbox, matcher)
.await
.context("failed to wait for uevent")?;
if uev.devname != devname {
return Err(anyhow!(
"Unexpected device name {} for mmio device (expected {})",
uev.devname,
devname
));
}
Ok(())
}
#[cfg(target_arch = "s390x")]
#[instrument]
pub async fn get_virtio_blk_ccw_device_name(
sandbox: &Arc<Mutex<Sandbox>>,
device: &ccw::Device,
) -> Result<String> {
let matcher = VirtioBlkCCWMatcher::new(CCW_ROOT_BUS_PATH, device);
let uev = wait_for_uevent(sandbox, matcher).await?;
let devname = uev.devname;
Path::new(SYSTEM_DEV_PATH)
.join(&devname)
.to_str()
.map(String::from)
.ok_or_else(|| anyhow!("CCW device name {} is not valid UTF-8", &devname))
}
#[derive(Debug)]
pub struct VirtioBlkPciMatcher {
rex: Regex,
}
impl VirtioBlkPciMatcher {
pub fn new(relpath: &str) -> VirtioBlkPciMatcher {
let root_bus = create_pci_root_bus_path();
let re = format!(r"^{}{}/virtio[0-9]+/block/", root_bus, relpath);
VirtioBlkPciMatcher {
rex: Regex::new(&re).expect("BUG: failed to compile VirtioBlkPciMatcher regex"),
}
}
}
impl UeventMatcher for VirtioBlkPciMatcher {
fn is_match(&self, uev: &Uevent) -> bool {
uev.subsystem == BLOCK && self.rex.is_match(&uev.devpath) && !uev.devname.is_empty()
}
}
#[derive(Debug)]
pub struct VirtioBlkMmioMatcher {
suffix: String,
}
impl VirtioBlkMmioMatcher {
pub fn new(devname: &str) -> VirtioBlkMmioMatcher {
VirtioBlkMmioMatcher {
suffix: format!(r"/block/{}", devname),
}
}
}
impl UeventMatcher for VirtioBlkMmioMatcher {
fn is_match(&self, uev: &Uevent) -> bool {
uev.subsystem == BLOCK && uev.devpath.ends_with(&self.suffix) && !uev.devname.is_empty()
}
}
#[cfg(target_arch = "s390x")]
#[derive(Debug)]
pub struct VirtioBlkCCWMatcher {
rex: Regex,
}
#[cfg(target_arch = "s390x")]
impl VirtioBlkCCWMatcher {
pub fn new(root_bus_path: &str, device: &ccw::Device) -> Self {
let re = format!(
r"^{}/0\.[0-3]\.[0-9a-f]{{1,4}}/{}/virtio[0-9]+/block/",
root_bus_path, device
);
VirtioBlkCCWMatcher {
rex: Regex::new(&re).expect("BUG: failed to compile VirtioBlkCCWMatcher regex"),
}
}
}
#[cfg(target_arch = "s390x")]
impl UeventMatcher for VirtioBlkCCWMatcher {
fn is_match(&self, uev: &Uevent) -> bool {
uev.action == "add" && self.rex.is_match(&uev.devpath) && !uev.devname.is_empty()
}
}