runtime-rs: do register/update device in Trait Device/attach

Before calling the device driver to attach a device, register
the device to PCIe topology and allocate a PciPath for it.

However, for some hypervisor such as CLH, the allocation is invalid
when plugging devices to VM, they have the ability to return
DeviceInfo containing PciPath. It'll update the PciPath with the
returned pci path in the PCIe topology for them to prevent the
inferred pcipath from being different from the actual value returned.

But the update will not be executed if the pcipath value doesn't change.

Fixes: #7218

Signed-off-by: alex.lyn <alex.lyn@antgroup.com>
This commit is contained in:
alex.lyn 2023-12-27 15:49:18 +08:00
parent ce7d363695
commit 0f0b6d13c9

View File

@ -5,28 +5,24 @@
//
use std::{
collections::HashMap,
fs,
path::{Path, PathBuf},
process::Command,
sync::{
atomic::{AtomicU8, Ordering},
Arc, RwLock,
},
};
use anyhow::{anyhow, Context, Result};
use async_trait::async_trait;
use lazy_static::lazy_static;
use path_clean::PathClean;
use kata_sys_util::fs::get_base_name;
use crate::device::{
hypervisor,
pci_path::{PciPath, PciSlot},
topology::{do_add_pcie_endpoint, PCIeTopology},
Device, DeviceType, PCIeDevice,
use crate::{
device::{
pci_path::PciPath,
topology::{do_add_pcie_endpoint, PCIeTopology},
Device, DeviceType, PCIeDevice,
},
register_pcie_device, unregister_pcie_device, update_pcie_device, Hypervisor as hypervisor,
};
pub const SYS_BUS_PCI_DRIVER_PROBE: &str = "/sys/bus/pci/drivers_probe";
@ -44,35 +40,6 @@ const INTEL_IOMMU_PREFIX: &str = "dmar";
const AMD_IOMMU_PREFIX: &str = "ivhd";
const ARM_IOMMU_PREFIX: &str = "smmu";
lazy_static! {
static ref GUEST_DEVICE_ID: Arc<AtomicU8> = Arc::new(AtomicU8::new(0_u8));
static ref HOST_GUEST_MAP: Arc<RwLock<HashMap<String, String>>> =
Arc::new(RwLock::new(HashMap::new()));
}
// map host/guest bdf and the mapping saved into `HOST_GUEST_MAP`,
// and return PciPath.
pub fn generate_guest_pci_path(bdf: String) -> Result<PciPath> {
let hg_map = HOST_GUEST_MAP.clone();
let current_id = GUEST_DEVICE_ID.clone();
current_id.fetch_add(1, Ordering::SeqCst);
let slot = current_id.load(Ordering::SeqCst);
// In some Hypervisors, dragonball, cloud-hypervisor or firecracker,
// the device is directly connected to the bus without intermediary bus.
// FIXME: Qemu's pci path needs to be implemented;
let host_bdf = normalize_device_bdf(bdf.as_str());
let guest_bdf = format!("0000:00:{:02x}.0", slot);
// safe, just do unwrap as `HOST_GUEST_MAP` is always valid.
hg_map.write().unwrap().insert(host_bdf, guest_bdf);
Ok(PciPath {
slots: vec![PciSlot::new(slot)],
})
}
pub fn do_check_iommu_on() -> Result<bool> {
let element = std::fs::read_dir(SYS_CLASS_IOMMU)?
.filter_map(|e| e.ok())
@ -479,9 +446,11 @@ impl VfioDevice {
impl Device for VfioDevice {
async fn attach(
&mut self,
_pcie_topo: &mut Option<&mut PCIeTopology>,
pcie_topo: &mut Option<&mut PCIeTopology>,
h: &dyn hypervisor,
) -> Result<()> {
register_pcie_device!(self, pcie_topo)?;
if self
.increase_attach_count()
.await
@ -499,31 +468,13 @@ impl Device for VfioDevice {
self.devices = vfio.devices;
}
if self.bus_mode == VfioBusMode::PCI {
for hostdev in self.devices.iter_mut() {
if hostdev.guest_pci_path.is_none() {
// guest_pci_path may be empty for certain hypervisors such as
// dragonball
hostdev.guest_pci_path = Some(
generate_guest_pci_path(hostdev.bus_slot_func.clone())
.map_err(|e| anyhow!("generate pci path failed: {:?}", e))?,
);
}
// Safe to call unwrap here because of previous assignment.
let pci_path = hostdev.guest_pci_path.clone().unwrap();
self.device_options.push(format!(
"0000:{}={}",
hostdev.bus_slot_func.clone(),
pci_path.to_string()
));
}
}
update_pcie_device!(self, pcie_topo)?;
Ok(())
}
Err(e) => {
self.decrease_attach_count().await?;
unregister_pcie_device!(self, pcie_topo)?;
return Err(e);
}
}