proper support for both native nvme multipath and DM multipath
Signed-off-by: Travis Glenn Hansen <travisghansen@yahoo.com>
This commit is contained in:
parent
a9cc6fb292
commit
afba7d8527
|
|
@ -0,0 +1,58 @@
|
|||
#!/bin/bash
|
||||
|
||||
# simple script to 'start' nvmet on TrueNAS SCALE
|
||||
#
|
||||
# to reinstall nvmetcli simply rm /usr/sbin/nvmetcli
|
||||
|
||||
# debug
|
||||
#set -x
|
||||
|
||||
# exit non-zero
|
||||
set -e
|
||||
|
||||
SCRIPTDIR="$(
|
||||
cd -- "$(dirname "$0")" >/dev/null 2>&1
|
||||
pwd -P
|
||||
)"
|
||||
cd "${SCRIPTDIR}"
|
||||
|
||||
: "${NVMETCONFIG:="${SCRIPTDIR}/nvmet-config.json"}"
|
||||
|
||||
export PATH=${HOME}/.local/bin:${PATH}
|
||||
|
||||
modules=()
|
||||
modules+=("nvmet")
|
||||
modules+=("nvmet-fc")
|
||||
modules+=("nvmet-rdma")
|
||||
modules+=("nvmet-tcp")
|
||||
|
||||
for module in "${modules[@]}"; do
|
||||
modprobe "${module}"
|
||||
done
|
||||
|
||||
which nvmetcli &>/dev/null || {
|
||||
which pip &>/dev/null || {
|
||||
wget -O get-pip.py https://bootstrap.pypa.io/get-pip.py
|
||||
python get-pip.py --user
|
||||
rm get-pip.py
|
||||
}
|
||||
|
||||
if [[ ! -d nvmetcli ]]; then
|
||||
git clone git://git.infradead.org/users/hch/nvmetcli.git
|
||||
fi
|
||||
|
||||
cd nvmetcli
|
||||
|
||||
# install to root home dir
|
||||
python3 setup.py install --user
|
||||
|
||||
# install to root home dir
|
||||
pip install configshell_fb --user
|
||||
|
||||
# remove source
|
||||
cd "${SCRIPTDIR}"
|
||||
rm -rf nvmetcli
|
||||
}
|
||||
|
||||
cd "${SCRIPTDIR}"
|
||||
nvmetcli restore "${NVMETCONFIG}"
|
||||
|
|
@ -14,6 +14,7 @@ const registry = require("../utils/registry");
|
|||
const semver = require("semver");
|
||||
const GeneralUtils = require("../utils/general");
|
||||
const { Zetabyte } = require("../utils/zfs");
|
||||
const { transport } = require("winston");
|
||||
|
||||
const __REGISTRY_NS__ = "CsiBaseDriver";
|
||||
|
||||
|
|
@ -982,7 +983,8 @@ class CsiBaseDriver {
|
|||
try {
|
||||
await GeneralUtils.retry(15, 2000, async () => {
|
||||
namespaceDevice =
|
||||
await nvmeof.namespaceDevicePathByNQNNamespace(
|
||||
await nvmeof.namespaceDevicePathByTransportNQNNamespace(
|
||||
nvmeofConnection.transport,
|
||||
nvmeofConnection.nqn,
|
||||
nvmeofConnection.nsid
|
||||
);
|
||||
|
|
@ -1126,6 +1128,14 @@ class CsiBaseDriver {
|
|||
`failed to discover multipath device`
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// only throw an error if we were not able to attach to *any* devices
|
||||
if (nvmeofNamespaceDevices.length > 1) {
|
||||
throw new GrpcError(
|
||||
grpc.status.UNKNOWN,
|
||||
`too many nvme namespace devices, neither DM nor native multipath enabled`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2348,6 +2358,7 @@ class CsiBaseDriver {
|
|||
}
|
||||
|
||||
if (is_block) {
|
||||
let breakdeviceloop = false;
|
||||
let realBlockDeviceInfos = [];
|
||||
// detect if is a multipath device
|
||||
is_device_mapper = await filesystem.isDeviceMapperDevice(
|
||||
|
|
@ -2369,6 +2380,9 @@ class CsiBaseDriver {
|
|||
|
||||
// TODO: this could be made async to detach all simultaneously
|
||||
for (const block_device_info_i of realBlockDeviceInfos) {
|
||||
if (breakdeviceloop) {
|
||||
break;
|
||||
}
|
||||
switch (block_device_info_i.tran) {
|
||||
case "iscsi":
|
||||
{
|
||||
|
|
@ -2475,7 +2489,15 @@ class CsiBaseDriver {
|
|||
let nqn = await nvmeof.nqnByNamespaceDeviceName(
|
||||
block_device_info_i.name
|
||||
);
|
||||
if (nqn) {
|
||||
await nvmeof.disconnectByNQN(nqn);
|
||||
/**
|
||||
* the above disconnects *all* devices with the nqn so we
|
||||
* do NOT want to keep iterating all the 'real' devices
|
||||
* in the case of DM multipath
|
||||
*/
|
||||
breakdeviceloop = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -170,15 +170,25 @@ class NVMEoF {
|
|||
return result.stdout.trim() == "Y";
|
||||
}
|
||||
|
||||
async namespaceDevicePathByNQNNamespace(nqn, namespace) {
|
||||
async namespaceDevicePathByTransportNQNNamespace(transport, nqn, namespace) {
|
||||
const nvmeof = this;
|
||||
let result = await nvmeof.list(["-v"]);
|
||||
for (let device of result.Devices) {
|
||||
for (let subsytem of device.Subsystems) {
|
||||
if (subsytem.SubsystemNQN != nqn) {
|
||||
transport = nvmeof.parseTransport(transport);
|
||||
let nativeMultipathEnabled = await nvmeof.nativeMultipathEnabled();
|
||||
if (nativeMultipathEnabled) {
|
||||
let subsystem = await nvmeof.getSubsystemByNQN(nqn);
|
||||
if (subsystem) {
|
||||
for (let i_namespace of subsystem.Namespaces) {
|
||||
if (i_namespace.NSID != namespace) {
|
||||
continue;
|
||||
} else {
|
||||
for (let i_namespace of subsytem.Namespaces) {
|
||||
return `/dev/${i_namespace.NameSpace}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let controller = await nvmeof.getControllerByTransportNQN(transport, nqn);
|
||||
if (controller) {
|
||||
for (let i_namespace of controller.Namespaces) {
|
||||
if (i_namespace.NSID != namespace) {
|
||||
continue;
|
||||
} else {
|
||||
|
|
@ -188,18 +198,34 @@ class NVMEoF {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async controllerDevicePathByTransportNQN(transport, nqn) {
|
||||
const nvmeof = this;
|
||||
transport = nvmeof.parseTransport(transport);
|
||||
let controller = await nvmeof.getControllerByTransportNQN(transport, nqn);
|
||||
if (controller) {
|
||||
return `/dev/${controller.Controller}`;
|
||||
}
|
||||
}
|
||||
|
||||
async getSubsystemByNQN(nqn) {
|
||||
const nvmeof = this;
|
||||
let result = await nvmeof.list(["-v"]);
|
||||
for (let device of result.Devices) {
|
||||
for (let subsytem of device.Subsystems) {
|
||||
if (subsytem.SubsystemNQN != nqn) {
|
||||
continue;
|
||||
} else {
|
||||
for (let controller of subsytem.Controllers) {
|
||||
for (let subsystem of device.Subsystems) {
|
||||
if (subsystem.SubsystemNQN == nqn) {
|
||||
return subsystem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async getControllerByTransportNQN(transport, nqn) {
|
||||
const nvmeof = this;
|
||||
transport = nvmeof.parseTransport(transport);
|
||||
let subsystem = await nvmeof.getSubsystemByNQN(nqn);
|
||||
if (subsystem) {
|
||||
for (let controller of subsystem.Controllers) {
|
||||
if (controller.Transport != transport.type) {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -229,9 +255,7 @@ class NVMEoF {
|
|||
continue;
|
||||
}
|
||||
|
||||
return `/dev/${controller.Controller}`;
|
||||
}
|
||||
}
|
||||
return controller;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -240,13 +264,27 @@ class NVMEoF {
|
|||
const nvmeof = this;
|
||||
name = name.replace("/dev/", "");
|
||||
let result = await nvmeof.list(["-v"]);
|
||||
let nativeMultipathEnabled = await nvmeof.nativeMultipathEnabled();
|
||||
|
||||
if (nativeMultipathEnabled) {
|
||||
for (let device of result.Devices) {
|
||||
for (let subsytem of device.Subsystems) {
|
||||
for (let namespace of subsytem.Namespaces) {
|
||||
if (namespace.NameSpace != name) {
|
||||
continue;
|
||||
for (let subsystem of device.Subsystems) {
|
||||
for (let namespace of subsystem.Namespaces) {
|
||||
if (namespace.NameSpace == name) {
|
||||
return subsystem.SubsystemNQN;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return subsytem.SubsystemNQN;
|
||||
for (let device of result.Devices) {
|
||||
for (let subsystem of device.Subsystems) {
|
||||
for (let controller of subsystem.Controllers) {
|
||||
for (let namespace of controller.Namespaces) {
|
||||
if (namespace.NameSpace == name) {
|
||||
return subsystem.SubsystemNQN;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue