diff --git a/src/agent/src/device.rs b/src/agent/src/device.rs index 3dd6244301..37fd65c061 100644 --- a/src/agent/src/device.rs +++ b/src/agent/src/device.rs @@ -28,9 +28,7 @@ use oci_spec::runtime as oci; use protocols::agent::Device; use tracing::instrument; -use kata_types::device::{ - DRIVER_SCSI_TYPE, DRIVER_VFIO_AP_TYPE, DRIVER_VFIO_PCI_GK_TYPE, DRIVER_VFIO_PCI_TYPE, -}; +use kata_types::device::{DRIVER_VFIO_AP_TYPE, DRIVER_VFIO_PCI_GK_TYPE, DRIVER_VFIO_PCI_TYPE}; // Convenience function to obtain the scope logger. fn sl() -> slog::Logger { @@ -171,39 +169,6 @@ pub fn pcipath_to_sysfs(root_bus_sysfs: &str, pcipath: &pci::Path) -> Result ScsiBlockMatcher { - let search = format!(r"/0:0:{}/block/", scsi_addr); - - ScsiBlockMatcher { search } - } -} - -impl UeventMatcher for ScsiBlockMatcher { - fn is_match(&self, uev: &Uevent) -> bool { - uev.subsystem == BLOCK && uev.devpath.contains(&self.search) && !uev.devname.is_empty() - } -} - -#[instrument] -pub async fn get_scsi_device_name( - sandbox: &Arc>, - scsi_addr: &str, -) -> Result { - let matcher = ScsiBlockMatcher::new(scsi_addr); - - scan_scsi_bus(scsi_addr)?; - let uev = wait_for_uevent(sandbox, matcher).await?; - Ok(format!("{}/{}", SYSTEM_DEV_PATH, &uev.devname)) -} - #[derive(Debug)] struct PciMatcher { devpath: String, @@ -362,39 +327,6 @@ async fn wait_for_ap_device(sandbox: &Arc>, address: ap::Address) Ok(()) } -/// Scan SCSI bus for the given SCSI address(SCSI-Id and LUN) -#[instrument] -fn scan_scsi_bus(scsi_addr: &str) -> Result<()> { - let tokens: Vec<&str> = scsi_addr.split(':').collect(); - if tokens.len() != 2 { - return Err(anyhow!( - "Unexpected format for SCSI Address: {}, expect SCSIID:LUA", - scsi_addr - )); - } - - // Scan scsi host passing in the channel, SCSI id and LUN. - // Channel is always 0 because we have only one SCSI controller. - let scan_data = &format!("0 {} {}", tokens[0], tokens[1]); - - for entry in fs::read_dir(SYSFS_SCSI_HOST_PATH)? { - let host = entry?.file_name(); - - let host_str = host.to_str().ok_or_else(|| { - anyhow!( - "failed to convert directory entry to unicode for file {:?}", - host - ) - })?; - - let scan_path = PathBuf::from(&format!("{}/{}/{}", SYSFS_SCSI_HOST_PATH, host_str, "scan")); - - fs::write(scan_path, scan_data)?; - } - - Ok(()) -} - #[derive(Debug, Clone)] pub struct DeviceInfo { // Device type, "b" for block device and "c" for character device @@ -654,19 +586,6 @@ pub fn update_env_pci( Ok(()) } -// device.Id should be the SCSI address of the disk in the format "scsiID:lunID" -#[instrument] -async fn virtio_scsi_device_handler( - device: &Device, - sandbox: &Arc>, -) -> Result { - let vm_path = get_scsi_device_name(sandbox, &device.id).await?; - - Ok(DeviceInfo::new(&vm_path, true) - .context("New device info")? - .into()) -} - fn split_vfio_pci_option(opt: &str) -> Option<(&str, &str)> { let mut tokens = opt.split('='); let hostbdf = tokens.next()?; diff --git a/src/agent/src/device/scsi_device_handler.rs b/src/agent/src/device/scsi_device_handler.rs new file mode 100644 index 0000000000..c65fd431ae --- /dev/null +++ b/src/agent/src/device/scsi_device_handler.rs @@ -0,0 +1,98 @@ +// Copyright (c) 2019 Ant Financial +// Copyright (c) 2024 Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 +// + +use crate::device::{DeviceContext, DeviceHandler, DeviceInfo, SpecUpdate, BLOCK}; +use crate::linux_abi::*; +use crate::sandbox::Sandbox; +use crate::uevent::{wait_for_uevent, Uevent, UeventMatcher}; +use anyhow::{anyhow, Context, Result}; +use protocols::agent::Device; +use std::fs; +use std::path::PathBuf; +use std::sync::Arc; +use tokio::sync::Mutex; +use tracing::instrument; + +#[derive(Debug)] +pub struct ScsiDeviceHandler {} + +#[async_trait::async_trait] +impl DeviceHandler for ScsiDeviceHandler { + #[instrument] + async fn device_handler(&self, device: &Device, ctx: &mut DeviceContext) -> Result { + let vm_path = get_scsi_device_name(ctx.sandbox, &device.id).await?; + + Ok(DeviceInfo::new(&vm_path, true) + .context("New device info")? + .into()) + } +} + +#[instrument] +pub async fn get_scsi_device_name( + sandbox: &Arc>, + scsi_addr: &str, +) -> Result { + let matcher = ScsiBlockMatcher::new(scsi_addr); + + scan_scsi_bus(scsi_addr)?; + let uev = wait_for_uevent(sandbox, matcher).await?; + Ok(format!("{}/{}", SYSTEM_DEV_PATH, &uev.devname)) +} + +// FIXME: This matcher is only correct if the guest has at most one +// SCSI host. +#[derive(Debug)] +pub struct ScsiBlockMatcher { + search: String, +} + +impl ScsiBlockMatcher { + pub fn new(scsi_addr: &str) -> ScsiBlockMatcher { + let search = format!(r"/0:0:{}/block/", scsi_addr); + + ScsiBlockMatcher { search } + } +} + +impl UeventMatcher for ScsiBlockMatcher { + fn is_match(&self, uev: &Uevent) -> bool { + uev.subsystem == BLOCK && uev.devpath.contains(&self.search) && !uev.devname.is_empty() + } +} + +/// Scan SCSI bus for the given SCSI address(SCSI-Id and LUN) +#[instrument] +fn scan_scsi_bus(scsi_addr: &str) -> Result<()> { + let tokens: Vec<&str> = scsi_addr.split(':').collect(); + if tokens.len() != 2 { + return Err(anyhow!( + "Unexpected format for SCSI Address: {}, expect SCSIID:LUA", + scsi_addr + )); + } + + // Scan scsi host passing in the channel, SCSI id and LUN. + // Channel is always 0 because we have only one SCSI controller. + let scan_data = &format!("0 {} {}", tokens[0], tokens[1]); + + for entry in fs::read_dir(SYSFS_SCSI_HOST_PATH)? { + let host = entry?.file_name(); + + let host_str = host.to_str().ok_or_else(|| { + anyhow!( + "failed to convert directory entry to unicode for file {:?}", + host + ) + })?; + + let scan_path = PathBuf::from(&format!("{}/{}/{}", SYSFS_SCSI_HOST_PATH, host_str, "scan")); + + fs::write(scan_path, scan_data)?; + } + + Ok(()) +}