diff --git a/.gitignore b/.gitignore index 441fe03..65e1ca5 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -SOURCES/nvme-cli-2.6.tar.gz +SOURCES/nvme-cli-2.9.1.tar.gz diff --git a/.nvme-cli.metadata b/.nvme-cli.metadata index d9f8a67..5063a91 100644 --- a/.nvme-cli.metadata +++ b/.nvme-cli.metadata @@ -1 +1 @@ -01d2a5755d0d251eafeeefad27e739353f9e0f12 SOURCES/nvme-cli-2.6.tar.gz +33eaae0a2334451553952ac701f8568a52fd2a98 SOURCES/nvme-cli-2.9.1.tar.gz diff --git a/SOURCES/0001-Revert-fabrics-Use-corresponding-hostid-when-hostnqn.patch b/SOURCES/0001-Revert-fabrics-Use-corresponding-hostid-when-hostnqn.patch new file mode 100644 index 0000000..2d8f91c --- /dev/null +++ b/SOURCES/0001-Revert-fabrics-Use-corresponding-hostid-when-hostnqn.patch @@ -0,0 +1,20 @@ +diff --git a/fabrics.c b/fabrics.c +index 871c20ede093..90c3e5d6c602 100644 +--- a/fabrics.c ++++ b/fabrics.c +@@ -643,6 +643,7 @@ char *nvmf_hostid_from_hostnqn(const char *hostnqn) + + void nvmf_check_hostid_and_hostnqn(const char *hostid, const char *hostnqn, unsigned int verbose) + { ++#if 0 + _cleanup_free_ char *hostid_from_file = NULL; + _cleanup_free_ char *hostid_from_hostnqn = NULL; + +@@ -665,6 +666,7 @@ void nvmf_check_hostid_and_hostnqn(const char *hostid, const char *hostnqn, unsi + fprintf(stderr, + "warning: use hostid which does not match uuid in hostnqn\n"); + } ++#endif + } + + int nvmf_discover(const char *desc, int argc, char **argv, bool connect) diff --git a/SOURCES/0001-udev-rules-set-ctrl_loss_tmo-to-1-for-ONTAP-NVMe-TCP.patch b/SOURCES/0001-udev-rules-set-ctrl_loss_tmo-to-1-for-ONTAP-NVMe-TCP.patch deleted file mode 100644 index 327cc85..0000000 --- a/SOURCES/0001-udev-rules-set-ctrl_loss_tmo-to-1-for-ONTAP-NVMe-TCP.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 0782167f3a6709df232b746cdfa2a036c6207f7f Mon Sep 17 00:00:00 2001 -From: Martin George -Date: Tue, 3 Oct 2023 16:05:23 +0530 -Subject: [PATCH] udev-rules: set ctrl_loss_tmo to -1 for ONTAP NVMe/TCP - -Setting ctrl_loss_tmo to -1 for ONTAP NVMe/TCP controllers would enable -indefinite reconnect attempts during a path loss and help avoid purging -the path on the host, which otherwise may lead to mounted fs read-only -behavior. So add a rule towards enabling the same. - -Signed-off-by: Martin George ---- - nvmf-autoconnect/udev-rules/71-nvmf-iopolicy-netapp.rules.in | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/nvmf-autoconnect/udev-rules/71-nvmf-iopolicy-netapp.rules.in b/nvmf-autoconnect/udev-rules/71-nvmf-iopolicy-netapp.rules.in -index 299fe2251418..99b6a8ba0bf8 100644 ---- a/nvmf-autoconnect/udev-rules/71-nvmf-iopolicy-netapp.rules.in -+++ b/nvmf-autoconnect/udev-rules/71-nvmf-iopolicy-netapp.rules.in -@@ -1,3 +1,6 @@ - # Enable round-robin for NetApp ONTAP and NetApp E-Series - ACTION=="add", SUBSYSTEM=="nvme-subsystem", ATTR{subsystype}=="nvm", ATTR{model}=="NetApp ONTAP Controller", ATTR{iopolicy}="round-robin" - ACTION=="add", SUBSYSTEM=="nvme-subsystem", ATTR{subsystype}=="nvm", ATTR{model}=="NetApp E-Series", ATTR{iopolicy}="round-robin" -+ -+# Set ctrl_loss_tmo to -1 for NetApp ONTAP NVMe/TCP -+ACTION!="remove", SUBSYSTEM=="nvme", KERNEL=="nvme*", ATTR{transport}=="tcp", ATTR{model}=="NetApp ONTAP Controller", ATTR{ctrl_loss_tmo}="-1" --- -2.39.3 - diff --git a/SOURCES/0002-nvme-telemetry-report-the-correct-error-if-the-ioctl.patch b/SOURCES/0002-nvme-telemetry-report-the-correct-error-if-the-ioctl.patch new file mode 100644 index 0000000..7a09bbc --- /dev/null +++ b/SOURCES/0002-nvme-telemetry-report-the-correct-error-if-the-ioctl.patch @@ -0,0 +1,76 @@ +From 42f788edccb954fe8b54c43809523e603c99f63c Mon Sep 17 00:00:00 2001 +From: Maurizio Lombardi +Date: Wed, 22 May 2024 15:06:18 +0200 +Subject: [PATCH] nvme: telemetry: report the correct error if the ioctl() + fails. + +It's wrong to assume that if the ioctl() returns a non-zero number +then the errno variable is set. +The ioctl() might return an NVMe Status error to inform the caller +that the requested log page is not supported, in that case errno is left +untouched. + +The original code didn't handle this case and returned "-errno" even when +the latter was zero. The caller interpreted this as a successful operation +and this might lead to improperly dereferencing the log page pointer. + +$ nvme telemetry-log /dev/nvme0 --output-file=telemetry_log.bin +ERROR: get_telemetry_log: : write failed with error : Bad address + +Fix this bug by returning the NVMe status if errno is zero: + +$ nvme telemetry-log /dev/nvme0 --output-file=telemetry_log.bin +NVMe status: Invalid Log Page: The log page indicated is invalid(0x109) +Failed to acquire telemetry log 265! + +Signed-off-by: Maurizio Lombardi +--- + nvme.c | 18 ++++++++++++++---- + 1 file changed, 14 insertions(+), 4 deletions(-) + +diff --git a/nvme.c b/nvme.c +index d722b91e5ed8..226413bc0eda 100644 +--- a/nvme.c ++++ b/nvme.c +@@ -717,7 +717,10 @@ static int get_log_telemetry_ctrl(struct nvme_dev *dev, bool rae, size_t size, + err = nvme_cli_get_log_telemetry_ctrl(dev, rae, 0, size, log); + if (err) { + free(log); +- return -errno; ++ if (errno) ++ return -errno; ++ else ++ return err; + } + + *buf = log; +@@ -737,7 +740,10 @@ static int get_log_telemetry_host(struct nvme_dev *dev, size_t size, + err = nvme_cli_get_log_telemetry_host(dev, 0, size, log); + if (err) { + free(log); +- return -errno; ++ if (errno) ++ return -errno; ++ else ++ return err; + } + + *buf = log; +@@ -757,8 +763,12 @@ static int __create_telemetry_log_host(struct nvme_dev *dev, + return -ENOMEM; + + err = nvme_cli_get_log_create_telemetry_host(dev, log); +- if (err) +- return -errno; ++ if (err) { ++ if (errno) ++ return -errno; ++ else ++ return err; ++ } + + err = parse_telemetry_da(dev, da, log, size); + if (err) +-- +2.43.0 + diff --git a/SOURCES/0002-udev-rules-rename-netapp-udev-rule.patch b/SOURCES/0002-udev-rules-rename-netapp-udev-rule.patch deleted file mode 100644 index 33650fb..0000000 --- a/SOURCES/0002-udev-rules-rename-netapp-udev-rule.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 748a9ac050fb443b1204d06ce3b5b129b6a8afe2 Mon Sep 17 00:00:00 2001 -From: Martin George -Date: Thu, 5 Oct 2023 12:12:46 +0530 -Subject: [PATCH] udev-rules: rename netapp udev rule - -Rename 71-nvmf-iopolicy-netapp.rules.in to 71-nvmf-netapp.rules.in -so as to make the name generic, since this not only sets the -iopolicy here but also modifies the ctrl_loss_tmo. - -Signed-off-by: Martin George ---- - meson.build | 2 +- - nvme.spec.in | 2 +- - ...71-nvmf-iopolicy-netapp.rules.in => 71-nvmf-netapp.rules.in} | 0 - 3 files changed, 2 insertions(+), 2 deletions(-) - rename nvmf-autoconnect/udev-rules/{71-nvmf-iopolicy-netapp.rules.in => 71-nvmf-netapp.rules.in} (100%) - -diff --git a/meson.build b/meson.build -index 3d3fb08541ff..310ba1f83400 100644 ---- a/meson.build -+++ b/meson.build -@@ -236,7 +236,7 @@ endforeach - - udev_files = [ - '70-nvmf-autoconnect.rules', -- '71-nvmf-iopolicy-netapp.rules', -+ '71-nvmf-netapp.rules', - ] - - foreach file : udev_files -diff --git a/nvme.spec.in b/nvme.spec.in -index fe4675a7bb0b..3eab9ff030ff 100644 ---- a/nvme.spec.in -+++ b/nvme.spec.in -@@ -31,7 +31,7 @@ touch %{buildroot}@SYSCONFDIR@/nvme/hostid - @SYSCONFDIR@/nvme/discovery.conf - %ghost @SYSCONFDIR@/nvme/config.json - @UDEVRULESDIR@/70-nvmf-autoconnect.rules --@UDEVRULESDIR@/71-nvmf-iopolicy-netapp.rules -+@UDEVRULESDIR@/71-nvmf-netapp.rules - @DRACUTRILESDIR@/70-nvmf-autoconnect.conf - @SYSTEMDDIR@/nvmf-connect@.service - @SYSTEMDDIR@/nvmefc-boot-connections.service -diff --git a/nvmf-autoconnect/udev-rules/71-nvmf-iopolicy-netapp.rules.in b/nvmf-autoconnect/udev-rules/71-nvmf-netapp.rules.in -similarity index 100% -rename from nvmf-autoconnect/udev-rules/71-nvmf-iopolicy-netapp.rules.in -rename to nvmf-autoconnect/udev-rules/71-nvmf-netapp.rules.in --- -2.39.3 - diff --git a/SOURCES/0003-Revert-fabrics-Use-corresponding-hostid-when-hostnqn.patch b/SOURCES/0003-Revert-fabrics-Use-corresponding-hostid-when-hostnqn.patch deleted file mode 100644 index fbb6d05..0000000 --- a/SOURCES/0003-Revert-fabrics-Use-corresponding-hostid-when-hostnqn.patch +++ /dev/null @@ -1,92 +0,0 @@ -From 5f872e9c1689078bf2c4e33108c1514da1a91497 Mon Sep 17 00:00:00 2001 -From: Maurizio Lombardi -Date: Mon, 13 Nov 2023 10:49:35 +0100 -Subject: [PATCH] Revert "fabrics: Use corresponding hostid when hostnqn is - generated" - -This reverts commit 7d1c18f581e489e0cedfd9991bc97a2f8239cf82. ---- - fabrics.c | 47 ++--------------------------------------------- - 1 file changed, 2 insertions(+), 45 deletions(-) - -diff --git a/fabrics.c b/fabrics.c -index 57ca927fce9a..f4fb63f0c555 100644 ---- a/fabrics.c -+++ b/fabrics.c -@@ -616,43 +616,6 @@ static int nvme_read_volatile_config(nvme_root_t r) - return ret; - } - --char *nvmf_hostid_from_hostnqn(const char *hostnqn) --{ -- const char *uuid; -- -- if (!hostnqn) -- return NULL; -- -- uuid = strstr(hostnqn, "uuid:"); -- if (!uuid) -- return NULL; -- -- return strdup(uuid + strlen("uuid:")); --} -- --void nvmf_check_hostid_and_hostnqn(const char *hostid, const char *hostnqn) --{ -- char *hostid_from_file, *hostid_from_hostnqn; -- -- if (!hostid) -- return; -- -- hostid_from_file = nvmf_hostid_from_file(); -- if (hostid_from_file && strcmp(hostid_from_file, hostid)) { -- fprintf(stderr, "warning: use generated hostid instead of hostid file\n"); -- free(hostid_from_file); -- } -- -- if (!hostnqn) -- return; -- -- hostid_from_hostnqn = nvmf_hostid_from_hostnqn(hostnqn); -- if (hostid_from_hostnqn && strcmp(hostid_from_hostnqn, hostid)) { -- fprintf(stderr, "warning: use hostid which does not match uuid in hostnqn\n"); -- free(hostid_from_hostnqn); -- } --} -- - int nvmf_discover(const char *desc, int argc, char **argv, bool connect) - { - char *subsysnqn = NVME_DISC_SUBSYS_NAME; -@@ -729,13 +692,10 @@ int nvmf_discover(const char *desc, int argc, char **argv, bool connect) - hostid_arg = hostid; - if (!hostnqn) - hostnqn = hnqn = nvmf_hostnqn_from_file(); -- if (!hostnqn) { -+ if (!hostnqn) - hostnqn = hnqn = nvmf_hostnqn_generate(); -- hostid = hid = nvmf_hostid_from_hostnqn(hostnqn); -- } - if (!hostid) - hostid = hid = nvmf_hostid_from_file(); -- nvmf_check_hostid_and_hostnqn(hostid, hostnqn); - h = nvme_lookup_host(r, hostnqn, hostid); - if (!h) { - ret = ENOMEM; -@@ -946,13 +906,10 @@ int nvmf_connect(const char *desc, int argc, char **argv) - - if (!hostnqn) - hostnqn = hnqn = nvmf_hostnqn_from_file(); -- if (!hostnqn) { -+ if (!hostnqn) - hostnqn = hnqn = nvmf_hostnqn_generate(); -- hostid = hid = nvmf_hostid_from_hostnqn(hostnqn); -- } - if (!hostid) - hostid = hid = nvmf_hostid_from_file(); -- nvmf_check_hostid_and_hostnqn(hostid, hostnqn); - h = nvme_lookup_host(r, hostnqn, hostid); - if (!h) { - errno = ENOMEM; --- -2.39.3 - diff --git a/SOURCES/0003-sed-only-re-read-partition-table-after-unlock.patch b/SOURCES/0003-sed-only-re-read-partition-table-after-unlock.patch new file mode 100644 index 0000000..036db06 --- /dev/null +++ b/SOURCES/0003-sed-only-re-read-partition-table-after-unlock.patch @@ -0,0 +1,63 @@ +From fac45ce03315479b0d30e71316e669d9d4ffb31c Mon Sep 17 00:00:00 2001 +From: Greg Joyce +Date: Fri, 10 May 2024 14:23:11 -0500 +Subject: [PATCH] sed: only re-read partition table after unlock. + +The partition table was being re-read after both lock and +unlock operations. The re-read would fail with an error +message after a lock since the partition was no longer readable. + +Signed-off-by: Greg Joyce +--- + plugins/sed/sedopal_cmd.c | 27 ++++++++++++++------------- + 1 file changed, 14 insertions(+), 13 deletions(-) + +diff --git a/plugins/sed/sedopal_cmd.c b/plugins/sed/sedopal_cmd.c +index 21ebd360c219..221f62b15186 100644 +--- a/plugins/sed/sedopal_cmd.c ++++ b/plugins/sed/sedopal_cmd.c +@@ -251,8 +251,21 @@ int sedopal_cmd_lock(int fd) + */ + int sedopal_cmd_unlock(int fd) + { ++ int rc; ++ ++ rc = sedopal_lock_unlock(fd, OPAL_RW); ++ ++ /* ++ * If the unlock was successful, force a re-read of the ++ * partition table. Return rc of unlock operation. ++ */ ++ if (rc == 0) { ++ if (ioctl(fd, BLKRRPART, 0) != 0) ++ fprintf(stderr, ++ "Warning: failed re-reading partition\n"); ++ } + +- return sedopal_lock_unlock(fd, OPAL_RW); ++ return rc; + } + + /* +@@ -275,18 +288,6 @@ int sedopal_lock_unlock(int fd, int lock_state) + if (rc != 0) + fprintf(stderr, + "Error: failed locking or unlocking - %d\n", rc); +- +- /* +- * If the unlock was successful, force a re-read of the +- * partition table. +- */ +- if (rc == 0) { +- rc = ioctl(fd, BLKRRPART, 0); +- if (rc != 0) +- fprintf(stderr, +- "Error: failed re-reading partition\n"); +- } +- + return rc; + } + +-- +2.43.0 + diff --git a/SOURCES/0004-nvme-Fixed-segmentation-fault-when-getting-host-init.patch b/SOURCES/0004-nvme-Fixed-segmentation-fault-when-getting-host-init.patch deleted file mode 100644 index 0029be0..0000000 --- a/SOURCES/0004-nvme-Fixed-segmentation-fault-when-getting-host-init.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 2f30d87d5c258fd97f78b0705bb92519d8a2498d Mon Sep 17 00:00:00 2001 -From: "da Cunha, Leonardo" -Date: Wed, 11 Oct 2023 09:01:44 -0700 -Subject: [PATCH] nvme: Fixed segmentation fault when getting host initiated - telemetry - -Signed-off-by: leonardo.da.cunha ---- - nvme.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/nvme.c b/nvme.c -index b9e56a48f0a5..73d74afdfd73 100644 ---- a/nvme.c -+++ b/nvme.c -@@ -851,6 +851,10 @@ static int __get_telemetry_log_host(struct nvme_dev *dev, - _cleanup_free_ struct nvme_telemetry_log *log = NULL; - int err; - -+ log = nvme_alloc(sizeof(*log)); -+ if (!log) -+ return -errno; -+ - err = nvme_cli_get_log_telemetry_host(dev, 0, - NVME_LOG_TELEM_BLOCK_SIZE, - log); --- -2.39.3 - diff --git a/SOURCES/99-nvme-nbft-connect.sh b/SOURCES/99-nvme-nbft-connect.sh new file mode 100644 index 0000000..1dc0324 --- /dev/null +++ b/SOURCES/99-nvme-nbft-connect.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +if [[ "$1" == nbft* ]] && [[ "$2" == "up" ]]; then + systemctl start nvmf-connect-nbft.service +fi diff --git a/SOURCES/99-nvme-nbft-no-ignore-carrier.conf b/SOURCES/99-nvme-nbft-no-ignore-carrier.conf new file mode 100644 index 0000000..4f19515 --- /dev/null +++ b/SOURCES/99-nvme-nbft-no-ignore-carrier.conf @@ -0,0 +1,15 @@ +# Boot from NVMe over TCP (NBFT) +# +# For NVMe/TCP connections that provide namespaces containing rootfs +# it is crucial to react on carrier events and reconnect any missing +# NVMe/TCP connections as defined in the ACPI NBFT table. A custom +# /usr/lib/NetworkManager/dispatcher.d/99-nvme-nbft-connect.sh hook +# will respawn nvmf-connect-nbft.service on such occasion. + +[device-nbft-no-ignore-carrier] + +# only affects nbft0, nbft1, ... interfaces +match-device=interface-name:nbft* + +# react on link up/down events +ignore-carrier=no diff --git a/SOURCES/nvme-cli-2.10-nbft-discovery.patch b/SOURCES/nvme-cli-2.10-nbft-discovery.patch new file mode 100644 index 0000000..a9fc949 --- /dev/null +++ b/SOURCES/nvme-cli-2.10-nbft-discovery.patch @@ -0,0 +1,596 @@ +From ca58ecc64852fc413a04f41d953914720d05459f Mon Sep 17 00:00:00 2001 +From: Tomas Bzatek +Date: Wed, 24 Apr 2024 17:46:19 +0200 +Subject: [PATCH 1/5] fabrics: Make some symbols public + +Needed for nbft, useful to have public. + +Signed-off-by: Tomas Bzatek +--- + fabrics.c | 24 ++++++++++++------------ + fabrics.h | 6 ++++++ + 2 files changed, 18 insertions(+), 12 deletions(-) + +diff --git a/fabrics.c b/fabrics.c +index 0b70d290a9..a82a56c7b0 100644 +--- a/fabrics.c ++++ b/fabrics.c +@@ -195,9 +195,9 @@ static nvme_ctrl_t __create_discover_ctrl(nvme_root_t r, nvme_host_t h, + return c; + } + +-static nvme_ctrl_t create_discover_ctrl(nvme_root_t r, nvme_host_t h, +- struct nvme_fabrics_config *cfg, +- struct tr_config *trcfg) ++nvme_ctrl_t nvmf_create_discover_ctrl(nvme_root_t r, nvme_host_t h, ++ struct nvme_fabrics_config *cfg, ++ struct tr_config *trcfg) + { + _cleanup_free_ struct nvme_id_ctrl *id = NULL; + nvme_ctrl_t c; +@@ -378,8 +378,7 @@ static int __discover(nvme_ctrl_t c, struct nvme_fabrics_config *defcfg, + return 0; + } + +-static char *get_default_trsvcid(const char *transport, +- bool discovery_ctrl) ++char *nvmf_get_default_trsvcid(const char *transport, bool discovery_ctrl) + { + if (!transport) + return NULL; +@@ -465,7 +464,7 @@ static int discover_from_conf_file(nvme_root_t r, nvme_host_t h, + goto next; + + if (!trsvcid) +- trsvcid = get_default_trsvcid(transport, true); ++ trsvcid = nvmf_get_default_trsvcid(transport, true); + + struct tr_config trcfg = { + .subsysnqn = subsysnqn, +@@ -485,7 +484,7 @@ static int discover_from_conf_file(nvme_root_t r, nvme_host_t h, + } + } + +- c = create_discover_ctrl(r, h, &cfg, &trcfg); ++ c = nvmf_create_discover_ctrl(r, h, &cfg, &trcfg); + if (!c) + goto next; + +@@ -549,7 +548,8 @@ static int discover_from_json_config_file(nvme_root_t r, nvme_host_t h, + + trsvcid = nvme_ctrl_get_trsvcid(c); + if (!trsvcid || !strcmp(trsvcid, "")) +- trsvcid = get_default_trsvcid(transport, true); ++ trsvcid = nvmf_get_default_trsvcid(transport, ++ true); + + if (force) + subsysnqn = nvme_ctrl_get_subsysnqn(c); +@@ -579,7 +579,7 @@ static int discover_from_json_config_file(nvme_root_t r, nvme_host_t h, + } + } + +- cn = create_discover_ctrl(r, h, &cfg, &trcfg); ++ cn = nvmf_create_discover_ctrl(r, h, &cfg, &trcfg); + if (!cn) + continue; + +@@ -806,7 +806,7 @@ int nvmf_discover(const char *desc, int argc, char **argv, bool connect) + } + + if (!trsvcid) +- trsvcid = get_default_trsvcid(transport, true); ++ trsvcid = nvmf_get_default_trsvcid(transport, true); + + struct tr_config trcfg = { + .subsysnqn = subsysnqn, +@@ -876,7 +876,7 @@ int nvmf_discover(const char *desc, int argc, char **argv, bool connect) + } + if (!c) { + /* No device or non-matching device, create a new controller */ +- c = create_discover_ctrl(r, h, &cfg, &trcfg); ++ c = nvmf_create_discover_ctrl(r, h, &cfg, &trcfg); + if (!c) { + if (errno != ENVME_CONNECT_IGNORED) + fprintf(stderr, +@@ -1005,7 +1005,7 @@ int nvmf_connect(const char *desc, int argc, char **argv) + if (hostkey) + nvme_host_set_dhchap_key(h, hostkey); + if (!trsvcid) +- trsvcid = get_default_trsvcid(transport, false); ++ trsvcid = nvmf_get_default_trsvcid(transport, false); + + struct tr_config trcfg = { + .subsysnqn = subsysnqn, +diff --git a/fabrics.h b/fabrics.h +index c16df60472..aec305dc31 100644 +--- a/fabrics.h ++++ b/fabrics.h +@@ -18,5 +18,11 @@ extern int nvmf_disconnect(const char *desc, int argc, char **argv); + extern int nvmf_disconnect_all(const char *desc, int argc, char **argv); + extern int nvmf_config(const char *desc, int argc, char **argv); + extern int nvmf_dim(const char *desc, int argc, char **argv); ++extern nvme_ctrl_t nvmf_create_discover_ctrl(nvme_root_t r, nvme_host_t h, ++ struct nvme_fabrics_config *cfg, ++ struct tr_config *trcfg); ++extern char *nvmf_get_default_trsvcid(const char *transport, ++ bool discovery_ctrl); ++ + + #endif + +From 996fd5554157949ed77154eecd0f8236590cc716 Mon Sep 17 00:00:00 2001 +From: Tomas Bzatek +Date: Wed, 24 Apr 2024 17:47:02 +0200 +Subject: [PATCH 2/5] util/cleanup: Add cleanup for struct nvme_fabrics_uri + +libnvme cleanup definitions are not part of public API. + +Signed-off-by: Tomas Bzatek +--- + util/cleanup.h | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff -up nvme-cli-2.9.1/util/cleanup.h.bak nvme-cli-2.9.1/util/cleanup.h +--- nvme-cli-2.9.1/util/cleanup.h.bak 2024-06-21 15:53:35.839852234 +0200 ++++ nvme-cli-2.9.1/util/cleanup.h 2024-05-03 16:03:42.000000000 +0200 +@@ -34,4 +34,12 @@ static inline void close_file(int *f) + } + #define _cleanup_file_ __cleanup__(close_file) + ++static inline void free_uri(struct nvme_fabrics_uri **uri) ++{ ++ if (*uri) ++ nvme_free_uri(*uri); ++} ++ ++#define _cleanup_uri_ __cleanup__(free_uri) ++ + #endif + +From 2f79015b83faff4947d29fb172d6f92d81f078e2 Mon Sep 17 00:00:00 2001 +From: Tomas Bzatek +Date: Wed, 24 Apr 2024 17:52:46 +0200 +Subject: [PATCH 3/5] nbft: Perform actual discovery + +This adds actual discovery support for Discovery Descriptor records. + +SSNS records are connected first. Discovery Descriptor records +are checked for any existing (back-)reference from SSNS records +and are skipped if so. It is assumed in such case that the pre-OS +driver has succeeded in discovery and filled SSNS records +accordingly. + +In case no SSNS record references the particular Discovery +record, an actual discovery is performed. + +Signed-off-by: Tomas Bzatek +--- + nbft.c | 232 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--- + nbft.h | 2 +- + 2 files changed, 223 insertions(+), 11 deletions(-) + +diff --git a/nbft.c b/nbft.c +index 7ff8765a80..995b31ca54 100644 +--- a/nbft.c ++++ b/nbft.c +@@ -7,6 +7,7 @@ + + #include + ++#include "common.h" + #include "nvme.h" + #include "nbft.h" + #include "fabrics.h" +@@ -77,12 +78,38 @@ void free_nbfts(struct list_head *nbft_list) + } + } + ++static bool validate_uri(struct nbft_info_discovery *dd, ++ struct nvme_fabrics_uri *uri) ++{ ++ if (!uri) { ++ fprintf(stderr, ++ "Discovery Descriptor %d: failed to parse URI %s\n", ++ dd->index, dd->uri); ++ return false; ++ } ++ if (strcmp(uri->scheme, "nvme") != 0) { ++ fprintf(stderr, ++ "Discovery Descriptor %d: unsupported scheme '%s'\n", ++ dd->index, uri->scheme); ++ return false; ++ } ++ if (!uri->protocol || strcmp(uri->protocol, "tcp") != 0) { ++ fprintf(stderr, ++ "Discovery Descriptor %d: unsupported transport '%s'\n", ++ dd->index, uri->protocol); ++ return false; ++ } ++ ++ return true; ++} ++ + /* returns 0 for success or negative errno otherwise */ + static int do_connect(nvme_root_t r, + nvme_host_t h, ++ struct nvmf_disc_log_entry *e, + struct nbft_info_subsystem_ns *ss, + struct tr_config *trcfg, +- const struct nvme_fabrics_config *cfg, ++ struct nvme_fabrics_config *cfg, + enum nvme_print_flags flags, + unsigned int verbose) + { +@@ -111,6 +138,12 @@ static int do_connect(nvme_root_t r, + nvme_init_logging(r, -1, false, false); + } + ++ if (e) { ++ if (e->trtype == NVMF_TRTYPE_TCP && ++ e->tsas.tcp.sectype != NVMF_TCP_SECTYPE_NONE) ++ cfg->tls = true; ++ } ++ + errno = 0; + ret = nvmf_add_ctrl(h, c, cfg); + +@@ -145,10 +178,114 @@ static int do_connect(nvme_root_t r, + return 0; + } + ++static int do_discover(struct nbft_info_discovery *dd, ++ nvme_root_t r, ++ nvme_host_t h, ++ nvme_ctrl_t c, ++ struct nvme_fabrics_config *defcfg, ++ struct tr_config *deftrcfg, ++ enum nvme_print_flags flags, ++ unsigned int verbose) ++{ ++ struct nvmf_discovery_log *log = NULL; ++ int i; ++ int ret; ++ ++ struct nvme_get_discovery_args args = { ++ .c = c, ++ .args_size = sizeof(args), ++ .max_retries = 10 /* MAX_DISC_RETRIES */, ++ .result = 0, ++ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT, ++ .lsp = 0, ++ }; ++ ++ log = nvmf_get_discovery_wargs(&args); ++ if (!log) { ++ fprintf(stderr, ++ "Discovery Descriptor %d: failed to get discovery log: %s\n", ++ dd->index, nvme_strerror(errno)); ++ return -errno; ++ } ++ ++ for (i = 0; i < le64_to_cpu(log->numrec); i++) { ++ struct nvmf_disc_log_entry *e = &log->entries[i]; ++ nvme_ctrl_t cl; ++ int tmo = defcfg->keep_alive_tmo; ++ ++ struct tr_config trcfg = { ++ .subsysnqn = e->subnqn, ++ .transport = nvmf_trtype_str(e->trtype), ++ .traddr = e->traddr, ++ .host_traddr = deftrcfg->host_traddr, ++ .host_iface = deftrcfg->host_iface, ++ .trsvcid = e->trsvcid, ++ }; ++ ++ if (e->subtype == NVME_NQN_CURR) ++ continue; ++ ++ /* Already connected ? */ ++ cl = lookup_ctrl(h, &trcfg); ++ if (cl && nvme_ctrl_get_name(cl)) ++ continue; ++ ++ /* Skip connect if the transport types don't match */ ++ if (strcmp(nvme_ctrl_get_transport(c), ++ nvmf_trtype_str(e->trtype))) ++ continue; ++ ++ if (e->subtype == NVME_NQN_DISC) { ++ nvme_ctrl_t child; ++ ++ child = nvmf_connect_disc_entry(h, e, defcfg, NULL); ++ do_discover(dd, r, h, child, defcfg, &trcfg, ++ flags, verbose); ++ nvme_disconnect_ctrl(child); ++ nvme_free_ctrl(child); ++ } else { ++ ret = do_connect(r, h, e, NULL, &trcfg, ++ defcfg, flags, verbose); ++ ++ /* ++ * With TCP/DHCP, it can happen that the OS ++ * obtains a different local IP address than the ++ * firmware had. Retry without host_traddr. ++ */ ++ if (ret == -ENVME_CONNECT_ADDRNOTAVAIL && ++ !strcmp(trcfg.transport, "tcp") && ++ strlen(dd->hfi->tcp_info.dhcp_server_ipaddr) > 0) { ++ const char *htradr = trcfg.host_traddr; ++ ++ trcfg.host_traddr = NULL; ++ ret = do_connect(r, h, e, NULL, &trcfg, ++ defcfg, flags, verbose); ++ ++ if (ret == 0 && verbose >= 1) ++ fprintf(stderr, ++ "Discovery Descriptor %d: connect with host_traddr=\"%s\" failed, success after omitting host_traddr\n", ++ dd->index, ++ htradr); ++ } ++ ++ if (ret) ++ fprintf(stderr, "Discovery Descriptor %d: no controller found\n", ++ dd->index); ++ if (ret == -ENOMEM) ++ break; ++ } ++ ++ defcfg->keep_alive_tmo = tmo; ++ } ++ ++ free(log); ++ return 0; ++} ++ + int discover_from_nbft(nvme_root_t r, char *hostnqn_arg, char *hostid_arg, + char *hostnqn_sys, char *hostid_sys, + const char *desc, bool connect, +- const struct nvme_fabrics_config *cfg, char *nbft_path, ++ struct nvme_fabrics_config *cfg, char *nbft_path, + enum nvme_print_flags flags, unsigned int verbose) + { + char *hostnqn = NULL, *hostid = NULL, *host_traddr = NULL; +@@ -158,6 +295,7 @@ int discover_from_nbft(nvme_root_t r, char *hostnqn_arg, char *hostid_arg, + struct nbft_file_entry *entry = NULL; + struct nbft_info_subsystem_ns **ss; + struct nbft_info_hfi *hfi; ++ struct nbft_info_discovery **dd; + + if (!connect) + /* to do: print discovery-type info from NBFT tables */ +@@ -192,15 +330,15 @@ int discover_from_nbft(nvme_root_t r, char *hostnqn_arg, char *hostid_arg, + if (!h) + goto out_free; + ++ /* Subsystem Namespace Descriptor List */ + for (ss = entry->nbft->subsystem_ns_list; ss && *ss; ss++) + for (i = 0; i < (*ss)->num_hfis; i++) { + hfi = (*ss)->hfis[i]; + +- if (!cfg->host_traddr) { +- host_traddr = NULL; +- if (!strncmp((*ss)->transport, "tcp", 3)) +- host_traddr = hfi->tcp_info.ipaddr; +- } ++ host_traddr = NULL; ++ if (!cfg->host_traddr && ++ !strncmp((*ss)->transport, "tcp", 3)) ++ host_traddr = hfi->tcp_info.ipaddr; + + struct tr_config trcfg = { + .subsysnqn = (*ss)->subsys_nqn, +@@ -211,7 +349,7 @@ int discover_from_nbft(nvme_root_t r, char *hostnqn_arg, char *hostid_arg, + .trsvcid = (*ss)->trsvcid, + }; + +- ret = do_connect(r, h, *ss, &trcfg, ++ ret = do_connect(r, h, NULL, *ss, &trcfg, + cfg, flags, verbose); + + /* +@@ -220,11 +358,11 @@ int discover_from_nbft(nvme_root_t r, char *hostnqn_arg, char *hostid_arg, + * firmware had. Retry without host_traddr. + */ + if (ret == -ENVME_CONNECT_ADDRNOTAVAIL && +- !strcmp((*ss)->transport, "tcp") && ++ !strcmp(trcfg.transport, "tcp") && + strlen(hfi->tcp_info.dhcp_server_ipaddr) > 0) { + trcfg.host_traddr = NULL; + +- ret = do_connect(r, h, *ss, &trcfg, ++ ret = do_connect(r, h, NULL, *ss, &trcfg, + cfg, flags, verbose); + + if (ret == 0 && verbose >= 1) +@@ -241,6 +379,80 @@ int discover_from_nbft(nvme_root_t r, char *hostnqn_arg, char *hostid_arg, + if (ret == -ENOMEM) + goto out_free; + } ++ ++ /* Discovery Descriptor List */ ++ for (dd = entry->nbft->discovery_list; dd && *dd; dd++) { ++ nvme_ctrl_t c; ++ bool linked = false; ++ _cleanup_uri_ struct nvme_fabrics_uri *uri = NULL; ++ _cleanup_free_ char *trsvcid = NULL; ++ ++ /* only perform discovery when no SSNS record references it */ ++ for (ss = entry->nbft->subsystem_ns_list; ss && *ss; ss++) ++ if ((*ss)->discovery && ++ (*ss)->discovery->index == (*dd)->index && ++ /* unavailable boot attempts are not discovered ++ * and may get transferred along with a well-known ++ * discovery NQN into an SSNS record. ++ */ ++ strcmp((*ss)->subsys_nqn, NVME_DISC_SUBSYS_NAME) != 0) { ++ linked = true; ++ break; ++ } ++ if (linked) ++ continue; ++ ++ hfi = (*dd)->hfi; ++ uri = nvme_parse_uri((*dd)->uri); ++ if (!validate_uri(*dd, uri)) ++ continue; ++ ++ host_traddr = NULL; ++ if (!cfg->host_traddr && ++ !strncmp(uri->protocol, "tcp", 3)) ++ host_traddr = hfi->tcp_info.ipaddr; ++ if (uri->port > 0) { ++ if (asprintf(&trsvcid, "%d", uri->port) < 0) { ++ errno = ENOMEM; ++ goto out_free; ++ } ++ } else ++ trsvcid = strdup(nvmf_get_default_trsvcid(uri->protocol, true)); ++ ++ struct tr_config trcfg = { ++ .subsysnqn = NVME_DISC_SUBSYS_NAME, ++ .transport = uri->protocol, ++ .traddr = uri->host, ++ .host_traddr = host_traddr, ++ .host_iface = NULL, ++ .trsvcid = trsvcid, ++ }; ++ ++ c = nvmf_create_discover_ctrl(r, h, cfg, &trcfg); ++ if (!c && errno == ENVME_CONNECT_ADDRNOTAVAIL && ++ !strcmp(trcfg.transport, "tcp") && ++ strlen(hfi->tcp_info.dhcp_server_ipaddr) > 0) { ++ trcfg.host_traddr = NULL; ++ c = nvmf_create_discover_ctrl(r, h, cfg, &trcfg); ++ } ++ ++ if (!c) { ++ fprintf(stderr, ++ "Discovery Descriptor %d: failed to add discovery controller: %s\n", ++ (*dd)->index, ++ nvme_strerror(errno)); ++ if (errno == ENOMEM) ++ goto out_free; ++ continue; ++ } ++ ++ ret = do_discover(*dd, r, h, c, cfg, &trcfg, ++ flags, verbose); ++ nvme_disconnect_ctrl(c); ++ nvme_free_ctrl(c); ++ if (ret == -ENOMEM) ++ goto out_free; ++ } + } + out_free: + free_nbfts(&nbft_list); +diff --git a/nbft.h b/nbft.h +index 0f7e33cee5..5dfb8704fd 100644 +--- a/nbft.h ++++ b/nbft.h +@@ -15,5 +15,5 @@ void free_nbfts(struct list_head *nbft_list); + extern int discover_from_nbft(nvme_root_t r, char *hostnqn_arg, char *hostid_arg, + char *hostnqn_sys, char *hostid_sys, + const char *desc, bool connect, +- const struct nvme_fabrics_config *cfg, char *nbft_path, ++ struct nvme_fabrics_config *cfg, char *nbft_path, + enum nvme_print_flags flags, unsigned int verbose); + +From 1074da1dbbbef229bf7e42a3cb644ab5b9745267 Mon Sep 17 00:00:00 2001 +From: Tomas Bzatek +Date: Thu, 25 Apr 2024 15:54:53 +0200 +Subject: [PATCH 4/5] nbft: Skip SSNS records pointing to well-known discovery + NQN + +Depending on a pre-OS implementation, boot attempts pointing +to the well-known discovery NQN may get transformed in +an SSNS record (and marked as 'unavailable') in case +the discovery cannot be performed. Otherwise the NBFT +table should be populated by discovered records instead. + +Signed-off-by: Tomas Bzatek +--- + nbft.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/nbft.c b/nbft.c +index 995b31ca54..9d1834d0db 100644 +--- a/nbft.c ++++ b/nbft.c +@@ -335,6 +335,15 @@ int discover_from_nbft(nvme_root_t r, char *hostnqn_arg, char *hostid_arg, + for (i = 0; i < (*ss)->num_hfis; i++) { + hfi = (*ss)->hfis[i]; + ++ /* Skip discovery NQN records */ ++ if (strcmp((*ss)->subsys_nqn, NVME_DISC_SUBSYS_NAME) == 0) { ++ if (verbose >= 1) ++ fprintf(stderr, ++ "SSNS %d points to well-known discovery NQN, skipping\n", ++ (*ss)->index); ++ continue; ++ } ++ + host_traddr = NULL; + if (!cfg->host_traddr && + !strncmp((*ss)->transport, "tcp", 3)) + +From 8b4c30014ed17fa226a34a3dd92167f122ccec42 Mon Sep 17 00:00:00 2001 +From: Tomas Bzatek +Date: Mon, 20 May 2024 17:43:01 +0200 +Subject: [PATCH 5/5] nbft: Reuse existing discovery controller + +Attempt to look up and use existing (persistent) discovery +controller. + +Signed-off-by: Tomas Bzatek +--- + nbft.c | 21 +++++++++++++++------ + 1 file changed, 15 insertions(+), 6 deletions(-) + +diff --git a/nbft.c b/nbft.c +index 9d1834d0db..8c03a1f53b 100644 +--- a/nbft.c ++++ b/nbft.c +@@ -393,6 +393,7 @@ int discover_from_nbft(nvme_root_t r, char *hostnqn_arg, char *hostid_arg, + for (dd = entry->nbft->discovery_list; dd && *dd; dd++) { + nvme_ctrl_t c; + bool linked = false; ++ bool persistent = false; + _cleanup_uri_ struct nvme_fabrics_uri *uri = NULL; + _cleanup_free_ char *trsvcid = NULL; + +@@ -437,12 +438,19 @@ int discover_from_nbft(nvme_root_t r, char *hostnqn_arg, char *hostid_arg, + .trsvcid = trsvcid, + }; + +- c = nvmf_create_discover_ctrl(r, h, cfg, &trcfg); +- if (!c && errno == ENVME_CONNECT_ADDRNOTAVAIL && +- !strcmp(trcfg.transport, "tcp") && +- strlen(hfi->tcp_info.dhcp_server_ipaddr) > 0) { +- trcfg.host_traddr = NULL; ++ /* Lookup existing discovery controller */ ++ c = lookup_ctrl(h, &trcfg); ++ if (c && nvme_ctrl_get_name(c)) ++ persistent = true; ++ ++ if (!c) { + c = nvmf_create_discover_ctrl(r, h, cfg, &trcfg); ++ if (!c && errno == ENVME_CONNECT_ADDRNOTAVAIL && ++ !strcmp(trcfg.transport, "tcp") && ++ strlen(hfi->tcp_info.dhcp_server_ipaddr) > 0) { ++ trcfg.host_traddr = NULL; ++ c = nvmf_create_discover_ctrl(r, h, cfg, &trcfg); ++ } + } + + if (!c) { +@@ -457,7 +465,8 @@ int discover_from_nbft(nvme_root_t r, char *hostnqn_arg, char *hostid_arg, + + ret = do_discover(*dd, r, h, c, cfg, &trcfg, + flags, verbose); +- nvme_disconnect_ctrl(c); ++ if (!persistent) ++ nvme_disconnect_ctrl(c); + nvme_free_ctrl(c); + if (ret == -ENOMEM) + goto out_free; diff --git a/SPECS/nvme-cli.spec b/SPECS/nvme-cli.spec index f51199a..df2c654 100644 --- a/SPECS/nvme-cli.spec +++ b/SPECS/nvme-cli.spec @@ -1,19 +1,24 @@ #%%global commit0 bdbb4da0979fbdc079cf98410cdb31cf799e83b3 #%%global shortcommit0 %%(c=%%{commit0}; echo ${c:0:7}) +%global nmlibdir %{_prefix}/lib/NetworkManager + Name: nvme-cli -Version: 2.6 -Release: 5%{?dist} +Version: 2.9.1 +Release: 6%{?dist} Summary: NVMe management command line interface License: GPL-2.0-only URL: https://github.com/linux-nvme/nvme-cli Source0: %{url}/archive/v%{version}/%{name}-%{version}.tar.gz +Source1: 99-nvme-nbft-connect.sh +Source2: 99-nvme-nbft-no-ignore-carrier.conf -Patch0: 0001-udev-rules-set-ctrl_loss_tmo-to-1-for-ONTAP-NVMe-TCP.patch -Patch1: 0002-udev-rules-rename-netapp-udev-rule.patch -Patch2: 0003-Revert-fabrics-Use-corresponding-hostid-when-hostnqn.patch -Patch3: 0004-nvme-Fixed-segmentation-fault-when-getting-host-init.patch +Patch0: 0001-Revert-fabrics-Use-corresponding-hostid-when-hostnqn.patch +Patch1: 0002-nvme-telemetry-report-the-correct-error-if-the-ioctl.patch +# https://issues.redhat.com/browse/RHEL-37601 +Patch2: nvme-cli-2.10-nbft-discovery.patch +Patch3: 0003-sed-only-re-read-partition-table-after-unlock.patch BuildRequires: meson >= 0.50.0 BuildRequires: gcc gcc-c++ @@ -21,7 +26,7 @@ BuildRequires: libuuid-devel BuildRequires: systemd-devel BuildRequires: systemd-rpm-macros BuildRequires: zlib-devel -BuildRequires: libnvme-devel >= 1.6-1 +BuildRequires: libnvme-devel >= 1.9-2 BuildRequires: json-c-devel >= 0.14 BuildRequires: asciidoc BuildRequires: xmlto @@ -32,13 +37,7 @@ Requires: util-linux nvme-cli provides NVM-Express user space tooling for Linux. %prep -#%%setup -qn %%{name}-%%{commit0} -%setup -q - -%patch0 -p1 -%patch1 -p1 -%patch2 -p1 -%patch3 -p1 +%autosetup -p1 -n %{name}-%{version} %build %meson -Dudevrulesdir=%{_udevrulesdir} -Dsystemddir=%{_unitdir} -Ddocs=all -Ddocs-build=true -Dhtmldir=%{_pkgdocdir} @@ -46,6 +45,10 @@ nvme-cli provides NVM-Express user space tooling for Linux. %install %meson_install +mkdir -p $RPM_BUILD_ROOT%{nmlibdir}/dispatcher.d +mkdir -p $RPM_BUILD_ROOT%{nmlibdir}/conf.d +%{__install} -pm 755 %{SOURCE1} $RPM_BUILD_ROOT%{nmlibdir}/dispatcher.d/ +%{__install} -pm 644 %{SOURCE2} $RPM_BUILD_ROOT%{nmlibdir}/conf.d/ # Do not install the dracut rule yet. See rhbz 1742764 # Do we want to keep this here? Now that we have boot support for nvme/fc + tcp? @@ -67,13 +70,17 @@ rm -rf %{buildroot}%{_pkgdocdir}/nvme %config(noreplace) %{_sysconfdir}/nvme/discovery.conf %{_unitdir}/nvmefc-boot-connections.service %{_unitdir}/nvmf-autoconnect.service +%{_unitdir}/nvmf-connect-nbft.service %{_unitdir}/nvmf-connect.target %{_unitdir}/nvmf-connect@.service +%{_udevrulesdir}/65-persistent-net-nbft.rules %{_udevrulesdir}/70-nvmf-autoconnect.rules %{_udevrulesdir}/71-nvmf-netapp.rules # Do not install the dracut rule yet. See rhbz 1742764 # Is this still true? Now that we support nvme-of boot, do we want to install this file? # /usr/lib/dracut/dracut.conf.d/70-nvmf-autoconnect.conf +%{nmlibdir}/dispatcher.d/99-nvme-nbft-connect.sh +%{nmlibdir}/conf.d/99-nvme-nbft-no-ignore-carrier.conf %post if [ $1 -eq 1 ] || [ $1 -eq 2 ]; then @@ -94,6 +101,28 @@ if [ $1 -eq 1 ] || [ $1 -eq 2 ]; then fi %changelog +* Thu Aug 22 2024 Tomas Bzatek - 2.9.1-6 +- Install NetworkManager override for nbft interfaces +- Rename reconnect NetworkManager hook to 99-nvme-nbft-connect.sh + +* Tue Aug 06 2024 Maurizio Lombardi - 2.9.1-5 +- Fix RHEL-38372 + +* Wed Jul 24 2024 Tomas Bzatek - 2.9.1-4 +- Backport NBFT discovery support (RHEL-37601) + +* Wed June 19 2024 Maurizio Lombardi - 2.9.1-3 +- Fix RHEL-36139 + +* Tue May 07 2024 Tomas Bzatek - 2.9.1-2 +- Install custom nvmf-connect-nbft.sh NetworkManager hook (RHEL-18912) + +* Tue May 07 2024 Maurizio Lombardi - 2.9.1-1 +- Update to version 2.9.1 + +* Wed Apr 03 2024 Maurizio Lombardi - 2.8-1 +- Update to version 2.8 + * Thu Feb 22 2024 Maurizio Lombardi - 2.6-5 - Fix for RHEL-13107