agent: implement NVDIMM/PMEM block driver

Support pmem-csi[1] k8s pluging, unlike SCSI and virtio devices,
NVDIMM/PMEM devices support DAX, improving IO Read and Write
operations.

fixes #1289

Signed-off-by: Julio Montes <julio.montes@intel.com>

[1]: https://github.com/intel/pmem-csi
This commit is contained in:
Julio Montes 2021-01-18 15:10:50 -06:00
parent f09128d8c7
commit 12551de8a2
4 changed files with 63 additions and 8 deletions

View File

@ -162,6 +162,14 @@ pub async fn get_pci_device_name(sandbox: &Arc<Mutex<Sandbox>>, pci_id: &str) ->
get_device_name(sandbox, &pci_addr).await
}
pub async fn get_pmem_device_name(
sandbox: &Arc<Mutex<Sandbox>>,
pmem_devname: &str,
) -> Result<String> {
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();

View File

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

View File

@ -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<String>
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<Mutex<Sandbox>>,
) -> Result<String> {
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 {}",

View File

@ -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();