diff --git a/src/agent/src/device.rs b/src/agent/src/device.rs index dc1a47aef6..b0c192be6c 100644 --- a/src/agent/src/device.rs +++ b/src/agent/src/device.rs @@ -162,6 +162,14 @@ pub async fn get_pci_device_name(sandbox: &Arc>, pci_id: &str) -> get_device_name(sandbox, &pci_addr).await } +pub async fn get_pmem_device_name( + sandbox: &Arc>, + pmem_devname: &str, +) -> Result { + let dev_sub_path = format!("/{}/{}", SCSI_BLOCK_SUFFIX, pmem_devname); + get_device_name(sandbox, &dev_sub_path).await +} + /// Scan SCSI bus for the given SCSI address(SCSI-Id and LUN) fn scan_scsi_bus(scsi_addr: &str) -> Result<()> { let tokens: Vec<&str> = scsi_addr.split(':').collect(); diff --git a/src/agent/src/linux_abi.rs b/src/agent/src/linux_abi.rs index 6cf9306b6f..d801963288 100644 --- a/src/agent/src/linux_abi.rs +++ b/src/agent/src/linux_abi.rs @@ -58,6 +58,13 @@ pub fn create_pci_root_bus_path() -> String { ret } +// From https://www.kernel.org/doc/Documentation/acpi/namespace.txt +// The Linux kernel's core ACPI subsystem creates struct acpi_device +// objects for ACPI namespace objects representing devices, power resources +// processors, thermal zones. Those objects are exported to user space via +// sysfs as directories in the subtree under /sys/devices/LNXSYSTM:00 +pub const ACPI_DEV_PATH: &str = "/devices/LNXSYSTM"; + pub const SYSFS_CPU_ONLINE_PATH: &str = "/sys/devices/system/cpu"; pub const SYSFS_MEMORY_BLOCK_SIZE_PATH: &str = "/sys/devices/system/memory/block_size_bytes"; diff --git a/src/agent/src/mount.rs b/src/agent/src/mount.rs index 1c2b3ea368..71e90e3097 100644 --- a/src/agent/src/mount.rs +++ b/src/agent/src/mount.rs @@ -22,7 +22,9 @@ use regex::Regex; use std::fs::File; use std::io::{BufRead, BufReader}; -use crate::device::{get_pci_device_name, get_scsi_device_name, online_device}; +use crate::device::{ + get_pci_device_name, get_pmem_device_name, get_scsi_device_name, online_device, +}; use crate::linux_abi::*; use crate::protocols::agent::Storage; use crate::Sandbox; @@ -122,7 +124,7 @@ lazy_static! { ]; } -pub const STORAGE_HANDLER_LIST: [&str; 7] = [ +pub const STORAGE_HANDLER_LIST: [&str; 8] = [ DRIVERBLKTYPE, DRIVER9PTYPE, DRIVERVIRTIOFSTYPE, @@ -130,6 +132,7 @@ pub const STORAGE_HANDLER_LIST: [&str; 7] = [ DRIVERMMIOBLKTYPE, DRIVERLOCALTYPE, DRIVERSCSITYPE, + DRIVERNVDIMMTYPE, ]; #[derive(Debug, Clone)] @@ -347,6 +350,32 @@ fn common_storage_handler(logger: &Logger, storage: &Storage) -> Result mount_storage(logger, storage).and(Ok(mount_point)) } +// nvdimm_storage_handler handles the storage for NVDIMM driver. +async fn nvdimm_storage_handler( + logger: &Logger, + storage: &Storage, + sandbox: Arc>, +) -> Result { + let mut storage = storage.clone(); + // If hot-plugged, get the device node path based on the PCI address else + // use the virt path provided in Storage Source + let pmem_devname = match storage.source.strip_prefix("/dev/") { + Some(dev) => dev, + None => { + return Err(anyhow!( + "Storage source '{}' must start with /dev/", + storage.source + )) + } + }; + + // Retrieve the device path from NVDIMM address. + let dev_path = get_pmem_device_name(&sandbox, pmem_devname).await?; + storage.source = dev_path; + + common_storage_handler(logger, &storage) +} + // mount_storage performs the mount described by the storage structure. fn mount_storage(logger: &Logger, storage: &Storage) -> Result<()> { let logger = logger.new(o!("subsystem" => "mount")); @@ -441,6 +470,7 @@ pub async fn add_storages( } DRIVERLOCALTYPE => local_storage_handler(&logger, &storage, sandbox.clone()).await, DRIVERSCSITYPE => virtio_scsi_storage_handler(&logger, &storage, sandbox.clone()).await, + DRIVERNVDIMMTYPE => nvdimm_storage_handler(&logger, &storage, sandbox.clone()).await, _ => { return Err(anyhow!( "Failed to find the storage handler {}", diff --git a/src/agent/src/uevent.rs b/src/agent/src/uevent.rs index d3620fe1db..83b4c6a877 100644 --- a/src/agent/src/uevent.rs +++ b/src/agent/src/uevent.rs @@ -54,7 +54,10 @@ impl Uevent { let pci_root_bus_path = create_pci_root_bus_path(); self.action == U_EVENT_ACTION_ADD && self.subsystem == "block" - && self.devpath.starts_with(&pci_root_bus_path) + && { + self.devpath.starts_with(pci_root_bus_path.as_str()) + || self.devpath.starts_with(ACPI_DEV_PATH) // NVDIMM/PMEM devices + } && self.devname != "" } @@ -80,11 +83,18 @@ impl Uevent { // blk block device devpath.starts_with(pci_p.as_str()) || - // scsi block device - { - (*dev_addr).ends_with(SCSI_BLOCK_SUFFIX) && - devpath.contains(*dev_addr) - } + // scsi block device + { + (*dev_addr).ends_with(SCSI_BLOCK_SUFFIX) && + devpath.contains(*dev_addr) + } || + // nvdimm/pmem device + { + let pmem_suffix = format!("/{}/{}", SCSI_BLOCK_SUFFIX, self.devname); + devpath.starts_with(ACPI_DEV_PATH) && + devpath.ends_with(pmem_suffix.as_str()) && + dev_addr.ends_with(pmem_suffix.as_str()) + } }) .map(|(k, sender)| { let devname = self.devname.clone();