From 9bf6d46b66ade3252d684ed5dbe893b03bf1c40b Mon Sep 17 00:00:00 2001 From: Travis Glenn Hansen Date: Thu, 29 Dec 2022 21:58:47 -0700 Subject: [PATCH] implement nvmeof node expand Signed-off-by: Travis Glenn Hansen --- src/driver/index.js | 19 +++++++--- src/utils/nvmeof.js | 92 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 103 insertions(+), 8 deletions(-) diff --git a/src/driver/index.js b/src/driver/index.js index 303c9a4..1648c7f 100644 --- a/src/driver/index.js +++ b/src/driver/index.js @@ -980,14 +980,13 @@ class CsiBaseDriver { } // find namespace device - - // rescan in scenarios when login previously occurred but volumes never appeared - // must be the NVMe char device, not the namespace device - await nvmeof.rescanNamespace(controllerDevice); - let namespaceDevice; try { await GeneralUtils.retry(15, 2000, async () => { + // rescan in scenarios when login previously occurred but volumes never appeared + // must be the NVMe char device, not the namespace device + await nvmeof.rescanNamespace(controllerDevice); + namespaceDevice = await nvmeof.namespaceDevicePathByTransportNQNNamespace( nvmeofConnection.transport, @@ -3499,6 +3498,8 @@ class CsiBaseDriver { const driver = this; const mount = driver.getDefaultMountInstance(); const filesystem = driver.getDefaultFilesystemInstance(); + const nvmeof = driver.getDefaultNVMEoFInstance(); + let device; let fs_info; let device_path; @@ -3561,6 +3562,14 @@ class CsiBaseDriver { rescan_devices.push(device); for (let sdevice of rescan_devices) { + let is_nvmeof = await filesystem.deviceIsNVMEoF(sdevice); + if (is_nvmeof) { + let controllers = + await nvmeof.getControllersByNamespaceDeviceName(sdevice); + for (let controller of controllers) { + await nvmeof.rescanNamespace(`/dev/${controller.Controller}`); + } + } // TODO: technically rescan is only relevant/available for remote drives // such as iscsi etc, should probably limit this call as appropriate // for now crudely checking the scenario inside the method itself diff --git a/src/utils/nvmeof.js b/src/utils/nvmeof.js index 5e65622..f3aa621 100644 --- a/src/utils/nvmeof.js +++ b/src/utils/nvmeof.js @@ -153,6 +153,54 @@ class NVMEoF { await nvmeof.exec(nvmeof.options.paths.nvme, args); } + async deviceIsNamespaceDevice(device) { + const nvmeof = this; + device = device.replace("/dev/", ""); + const subsystems = await nvmeof.getSubsystems(); + for (let subsystem of subsystems) { + // check subsystem namespaces + if (subsystem.Namespaces) { + for (let namespace of subsystem.Namespaces) { + if (namespace.NameSpace == device) { + return true; + } + } + } + + // check controller namespaces + if (subsystem.Controllers) { + for (let controller of subsystem.Controllers) { + if (controller.Namespaces) { + for (let namespace of controller.Namespaces) { + if (namespace.NameSpace == device) { + return true; + } + } + } + } + } + } + + return false; + } + + async deviceIsControllerDevice(device) { + const nvmeof = this; + device = device.replace("/dev/", ""); + const subsystems = await nvmeof.getSubsystems(); + for (let subsystem of subsystems) { + if (subsystem.Controllers) { + for (let controller of subsystem.Controllers) { + if (controller.Controller == device) { + return true; + } + } + } + } + + return false; + } + async parseTransport(transport) { if (typeof transport === "object") { return transport; @@ -267,9 +315,9 @@ class NVMEoF { /** * used to normalize subsystem list/response across different versions of nvme-cli - * - * @param {*} result - * @returns + * + * @param {*} result + * @returns */ async getNormalizedSubsystems(result) { let subsystems = []; @@ -298,6 +346,44 @@ class NVMEoF { nvmeof.logger.warn(`failed to find subsystem for nqn: ${nqn}`); } + async getControllersByNamespaceDeviceName(name) { + const nvmeof = this; + name = name.replace("/dev/", ""); + let nativeMultipathEnabled = await nvmeof.nativeMultipathEnabled(); + const subsystems = await nvmeof.getSubsystems(); + + if (nativeMultipathEnabled) { + // using per-subsystem namespace + for (let subsystem of subsystems) { + if (subsystem.Namespaces) { + for (let namespace of subsystem.Namespaces) { + if (namespace.NameSpace == name) { + return subsystem.Controllers; + } + } + } + } + } else { + // using per-controller namespace + for (let subsystem of subsystems) { + if (subsystem.Controllers) { + for (let controller of subsystem.Controllers) { + if (controller.Namespaces) { + for (let namespace of controller.Namespaces) { + if (namespace.NameSpace == name) { + return subsystem.Controllers; + } + } + } + } + } + } + } + + nvmeof.logger.warn(`failed to find controllers for device: ${name}`); + return []; + } + async getControllerByTransportNQN(transport, nqn) { const nvmeof = this; transport = await nvmeof.parseTransport(transport);