diff --git a/SOURCES/0001-nvme-discover-Retry-discovery-log-if-the-generation-.patch b/SOURCES/0001-nvme-discover-Retry-discovery-log-if-the-generation-.patch new file mode 100644 index 0000000..a93b66c --- /dev/null +++ b/SOURCES/0001-nvme-discover-Retry-discovery-log-if-the-generation-.patch @@ -0,0 +1,126 @@ +From 17e397a84a201f5eac10e2899e80e855fef1fc71 Mon Sep 17 00:00:00 2001 +From: David Milburn +Date: Tue, 18 Dec 2018 15:15:31 -0600 +Subject: [PATCH] nvme-discover: Retry discovery log if the generation counter + changes + +commit 3cbcd165b470a1b86e323e2b256cde8f05a9b5dd +Author: Hannes Reinecke +Date: Thu Sep 20 11:09:34 2018 +0200 + + nvme-discover: Retry discovery log if the generation counter changes + + If the generation counter changes we need to validate if the number + of records has changed, too. + If so we need to retry retrieving the discovery log to the most recent + values. The retry will be terminated after MAX_DISC_RETRIES (currently + set to 10) to avoid infinite recursion. + + Signed-off-by: Hannes Reinecke + +Signed-off-by: David Milburn +--- + fabrics.c | 67 ++++++++++++++++++++++++++++++++++----------------------------- + 1 file changed, 36 insertions(+), 31 deletions(-) + +diff --git a/fabrics.c b/fabrics.c +index 9aee8f8..eb70a3d 100644 +--- a/fabrics.c ++++ b/fabrics.c +@@ -71,6 +71,7 @@ static struct config { + #define PATH_NVMF_HOSTID "/etc/nvme/hostid" + #define SYS_NVME "/sys/class/nvme" + #define MAX_DISC_ARGS 10 ++#define MAX_DISC_RETRIES 10 + + enum { + OPT_INSTANCE, +@@ -281,7 +282,7 @@ static int nvmf_get_log_page_discovery(const char *dev_path, + struct nvmf_disc_rsp_page_hdr *log; + unsigned int log_size = 0; + unsigned long genctr; +- int error, fd; ++ int error, fd, max_retries = MAX_DISC_RETRIES, retries = 0; + + fd = open(dev_path, O_RDWR); + if (fd < 0) { +@@ -311,42 +312,46 @@ static int nvmf_get_log_page_discovery(const char *dev_path, + goto out_free_log; + } + +- /* check numrec limits */ +- *numrec = le64_to_cpu(log->numrec); +- genctr = le64_to_cpu(log->genctr); +- free(log); ++ do { ++ /* check numrec limits */ ++ *numrec = le64_to_cpu(log->numrec); ++ genctr = le64_to_cpu(log->genctr); ++ free(log); + +- if (*numrec == 0) { +- error = DISC_NO_LOG; +- goto out_close; +- } ++ if (*numrec == 0) { ++ error = DISC_NO_LOG; ++ goto out_close; ++ } + +- /* we are actually retrieving the entire discovery tables +- * for the second get_log_page(), per +- * NVMe spec so no need to round_up(), or there is something +- * seriously wrong with the standard +- */ +- log_size = sizeof(struct nvmf_disc_rsp_page_hdr) + ++ /* we are actually retrieving the entire discovery tables ++ * for the second get_log_page(), per ++ * NVMe spec so no need to round_up(), or there is something ++ * seriously wrong with the standard ++ */ ++ log_size = sizeof(struct nvmf_disc_rsp_page_hdr) + + sizeof(struct nvmf_disc_rsp_page_entry) * *numrec; + +- /* allocate discovery log pages based on page_hdr->numrec */ +- log = calloc(1, log_size); +- if (!log) { +- error = -ENOMEM; +- goto out_close; +- } ++ /* allocate discovery log pages based on page_hdr->numrec */ ++ log = calloc(1, log_size); ++ if (!log) { ++ error = -ENOMEM; ++ goto out_close; ++ } + +- /* +- * issue new get_log_page w/numdl+numdh set to get all records, +- * up to MAX_DISC_LOGS. +- */ +- error = nvme_discovery_log(fd, log, log_size); +- if (error) { +- error = DISC_GET_LOG; +- goto out_free_log; +- } ++ /* ++ * issue new get_log_page w/numdl+numdh set to get all records, ++ * up to MAX_DISC_LOGS. ++ */ ++ error = nvme_discovery_log(fd, log, log_size); ++ if (error) { ++ error = DISC_GET_LOG; ++ goto out_free_log; ++ } ++ ++ } while (genctr != le64_to_cpu(log->genctr) && ++ ++retries < max_retries); + +- if (*numrec != le32_to_cpu(log->numrec) || genctr != le64_to_cpu(log->genctr)) { ++ if (*numrec != le32_to_cpu(log->numrec)) { + error = DISC_NOT_EQUAL; + goto out_free_log; + } +-- +1.8.3.1 + diff --git a/SOURCES/0002-nvme-ioctl-retrieve-log-pages-in-4k-chunks.patch b/SOURCES/0002-nvme-ioctl-retrieve-log-pages-in-4k-chunks.patch new file mode 100644 index 0000000..fa6dfe5 --- /dev/null +++ b/SOURCES/0002-nvme-ioctl-retrieve-log-pages-in-4k-chunks.patch @@ -0,0 +1,63 @@ +From e2c00a44b914f652a203a42e5be27b1d99ec2eef Mon Sep 17 00:00:00 2001 +From: David Milburn +Date: Tue, 18 Dec 2018 15:36:54 -0600 +Subject: [PATCH 2/2] nvme-ioctl: retrieve log pages in 4k chunks + +commit 465a4d5ab209bb20ea4b3ba808438747773edd2b +Author: Hannes Reinecke +Date: Thu Sep 20 11:09:35 2018 +0200 + + nvme-ioctl: retrieve log pages in 4k chunks + + Some log pages increase with the scale of the subsystem, so the + overall size might be larger than the MDTS value for that controller. + In order to avoid having to pass in the MDTS value we should restrict + the transfer size to 4k and retrieve the log page in 4k chunks. + + Signed-off-by: Hannes Reinecke + +Signed-off-by: David Milburn +--- + nvme-ioctl.c | 26 ++++++++++++++++++++++++-- + 1 file changed, 24 insertions(+), 2 deletions(-) + +diff --git a/nvme-ioctl.c b/nvme-ioctl.c +index 9cf2a33..c28a0d9 100644 +--- a/nvme-ioctl.c ++++ b/nvme-ioctl.c +@@ -419,8 +419,30 @@ int nvme_get_log13(int fd, __u32 nsid, __u8 log_id, __u8 lsp, __u64 lpo, + + int nvme_get_log(int fd, __u32 nsid, __u8 log_id, __u32 data_len, void *data) + { +- return nvme_get_log13(fd, nsid, log_id, NVME_NO_LOG_LSP, NVME_NO_LOG_LPO, +- 0, 0, data_len, data); ++ void *ptr = data; ++ __u32 offset = 0, xfer_len = data_len; ++ int ret; ++ ++ /* ++ * 4k is the smallest possible transfer unit, so by ++ * restricting ourselves for 4k transfers we avoid having ++ * to check the MDTS value of the controller. ++ */ ++ do { ++ xfer_len = data_len - offset; ++ if (xfer_len > 4096) ++ xfer_len = 4096; ++ ++ ret = nvme_get_log13(fd, nsid, log_id, NVME_NO_LOG_LSP, ++ offset, 0, false, xfer_len, ptr); ++ if (ret) ++ return ret; ++ ++ offset += xfer_len; ++ ptr += xfer_len; ++ } while (offset < data_len); ++ ++ return 0; + } + + int nvme_get_telemetry_log(int fd, void *lp, int generate_report, +-- +1.8.3.1 + diff --git a/SOURCES/0003-nvme-discover-Re-check-generation-counter-after-log-.patch b/SOURCES/0003-nvme-discover-Re-check-generation-counter-after-log-.patch new file mode 100644 index 0000000..03eec4c --- /dev/null +++ b/SOURCES/0003-nvme-discover-Re-check-generation-counter-after-log-.patch @@ -0,0 +1,92 @@ +From 5d3c37d0726f49020dc13be33b0a30834f313cde Mon Sep 17 00:00:00 2001 +From: David Milburn +Date: Tue, 18 Dec 2018 15:42:24 -0600 +Subject: [PATCH 3/3] nvme-discover: Re-check generation counter after log page + transfer + +commit 36efbbbff9f0e5d854f0454e393012ae23c46646 +Author: Hannes Reinecke +Date: Thu Sep 20 11:09:36 2018 +0200 + + nvme-discover: Re-check generation counter after log page transfer + + The log page transfer might have been split up in several chunks, so + it might happen that the generation counter changed inbetween these + transfer. Hence we need to re-fetch the header again to figure out + if there had been changes to the generation counter; if so we need + to fetch the entire page again. + + Signed-off-by: Hannes Reinecke + +Signed-off-by: David Milburn +--- + fabrics.c | 22 ++++++++++++++++++---- + 1 file changed, 18 insertions(+), 4 deletions(-) + +diff --git a/fabrics.c b/fabrics.c +index eb70a3d..f827d29 100644 +--- a/fabrics.c ++++ b/fabrics.c +@@ -280,7 +280,7 @@ static int nvmf_get_log_page_discovery(const char *dev_path, + struct nvmf_disc_rsp_page_hdr **logp, int *numrec) + { + struct nvmf_disc_rsp_page_hdr *log; +- unsigned int log_size = 0; ++ unsigned int hdr_size; + unsigned long genctr; + int error, fd, max_retries = MAX_DISC_RETRIES, retries = 0; + +@@ -293,26 +293,28 @@ static int nvmf_get_log_page_discovery(const char *dev_path, + /* first get_log_page we just need numrec entry from discovery hdr. + * host supplies its desired bytes via dwords, per NVMe spec. + */ +- log_size = round_up((offsetof(struct nvmf_disc_rsp_page_hdr, numrec) + ++ hdr_size = round_up((offsetof(struct nvmf_disc_rsp_page_hdr, numrec) + + sizeof(log->numrec)), sizeof(__u32)); + + /* + * Issue first get log page w/numdl small enough to retrieve numrec. + * We just want to know how many records to retrieve. + */ +- log = calloc(1, log_size); ++ log = calloc(1, hdr_size); + if (!log) { + error = -ENOMEM; + goto out_close; + } + +- error = nvme_discovery_log(fd, log, log_size); ++ error = nvme_discovery_log(fd, log, hdr_size); + if (error) { + error = DISC_GET_NUMRECS; + goto out_free_log; + } + + do { ++ unsigned int log_size; ++ + /* check numrec limits */ + *numrec = le64_to_cpu(log->numrec); + genctr = le64_to_cpu(log->genctr); +@@ -348,6 +350,18 @@ static int nvmf_get_log_page_discovery(const char *dev_path, + goto out_free_log; + } + ++ /* ++ * The above call to nvme_discovery_log() might result ++ * in several calls (with different offsets), so we need ++ * to fetch the header again to have the most up-to-date ++ * value for the generation counter ++ */ ++ genctr = le64_to_cpu(log->genctr); ++ error = nvme_discovery_log(fd, log, hdr_size); ++ if (error) { ++ error = DISC_GET_LOG; ++ goto out_free_log; ++ } + } while (genctr != le64_to_cpu(log->genctr) && + ++retries < max_retries); + +-- +1.8.3.1 + diff --git a/SOURCES/0004-nvme-cli-report-subsystem-reset-not-supported-by-con.patch b/SOURCES/0004-nvme-cli-report-subsystem-reset-not-supported-by-con.patch new file mode 100644 index 0000000..6fb3513 --- /dev/null +++ b/SOURCES/0004-nvme-cli-report-subsystem-reset-not-supported-by-con.patch @@ -0,0 +1,49 @@ +From 705ba547240fb340f9fd6caf4c1a988218dec557 Mon Sep 17 00:00:00 2001 +From: David Milburn +Date: Tue, 18 Dec 2018 15:52:57 -0600 +Subject: [PATCH 4/5] nvme-cli: report subsystem-reset not supported by + controller + +commit 8faa66131151fc2dca5df67881cd7176086421b6 +Author: David Milburn +Date: Wed Sep 26 08:25:57 2018 -0500 + + nvme-cli: report subsystem-reset not supported by controller + + Add a little more description for "nvme subsystem-reset" + failures, currently driver reports "Inappropriate ioctl + for device". + + $ nvme subsystem-reset /dev/nvme0 + Subsystem-reset: Inappropriate ioctl for device + + With this change report controller doesn't support + NVM Subsystem Reset. + + $ nvme subsystem-reset /dev/nvme0 + Subsystem-reset: NVM Subsystem Reset not supported. + +Signed-off-by: David Milburn +--- + nvme.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/nvme.c b/nvme.c +index 4815caa..0722132 100644 +--- a/nvme.c ++++ b/nvme.c +@@ -2392,6 +2392,11 @@ static int subsystem_reset(int argc, char **argv, struct command *cmd, struct pl + if (err < 0) { + close(fd); + perror("Subsystem-reset"); ++ if (errno == ENOTTY) ++ fprintf(stderr, ++ "Subsystem-reset: NVM Subsystem Reset not supported.\n"); ++ else ++ perror("Subsystem-reset"); + return errno; + } + +-- +1.8.3.1 + diff --git a/SOURCES/0005-nvme-list-fix-nvme-list-output-if-identify-failed-on.patch b/SOURCES/0005-nvme-list-fix-nvme-list-output-if-identify-failed-on.patch new file mode 100644 index 0000000..c95ad8f --- /dev/null +++ b/SOURCES/0005-nvme-list-fix-nvme-list-output-if-identify-failed-on.patch @@ -0,0 +1,105 @@ +From 0ffab5433084c8f93d152938e58be2a2162d8059 Mon Sep 17 00:00:00 2001 +From: David Milburn +Date: Tue, 18 Dec 2018 15:55:49 -0600 +Subject: [PATCH 5/5] nvme list : fix nvme list output if identify failed on + device + +commit 6c10501eb7e8423892735c5aa3b8c135d26fdbf3 +Author: Eyal Ben David +Date: Tue Aug 28 19:49:09 2018 +0300 + + nvme list : fix nvme list output if identify failed on device + + changed files: + nvme.c function list() + nvme-ioctl.c function nvme_get_nsid() : return -errno if fstat fails + +Signed-off-by: David Milburn +--- + nvme-ioctl.c | 2 +- + nvme.c | 37 +++++++++++++++++++++++++------------ + 2 files changed, 26 insertions(+), 13 deletions(-) + +diff --git a/nvme-ioctl.c b/nvme-ioctl.c +index c28a0d9..5444806 100644 +--- a/nvme-ioctl.c ++++ b/nvme-ioctl.c +@@ -74,7 +74,7 @@ int nvme_get_nsid(int fd) + int err = fstat(fd, &nvme_stat); + + if (err < 0) +- return err; ++ return -errno; + + if (!S_ISBLK(nvme_stat.st_mode)) { + fprintf(stderr, +diff --git a/nvme.c b/nvme.c +index 0722132..700a4d1 100644 +--- a/nvme.c ++++ b/nvme.c +@@ -1580,37 +1580,50 @@ static int list(int argc, char **argv, struct command *cmd, struct plugin *plugi + list_items = calloc(n, sizeof(*list_items)); + if (!list_items) { + fprintf(stderr, "can not allocate controller list payload\n"); +- return ENOMEM; ++ ret = -ENOMEM; ++ goto cleanup_devices; + } + + for (i = 0; i < n; i++) { + snprintf(path, sizeof(path), "%s%s", dev, devices[i]->d_name); + fd = open(path, O_RDONLY); + if (fd < 0) { +- fprintf(stderr, "can not open %s: %s\n", path, ++ fprintf(stderr, "cannot open %s: %s\n", path, + strerror(errno)); +- return errno; ++ ret = -errno; ++ goto cleanup_list_items; + } + ret = get_nvme_info(fd, &list_items[list_cnt], path); + close(fd); +- if (ret) ++ if (ret == 0) { ++ list_cnt++; ++ } ++ else if (ret > 0) { + fprintf(stderr, "%s: failed to obtain nvme info: %s\n", +- path, strerror(errno)); ++ path, nvme_status_to_string(ret)); ++ } ++ else { ++ fprintf(stderr, "%s: failed to obtain nvme info: %s\n", ++ path, strerror(-ret)); ++ } ++ } ++ ++ if (list_cnt) { ++ if (fmt == JSON) ++ json_print_list_items(list_items, list_cnt); + else +- list_cnt++; ++ show_list_items(list_items, list_cnt); + } + +- if (fmt == JSON) +- json_print_list_items(list_items, list_cnt); +- else +- show_list_items(list_items, list_cnt); ++ cleanup_list_items: ++ free(list_items); + ++ cleanup_devices: + for (i = 0; i < n; i++) + free(devices[i]); + free(devices); +- free(list_items); + +- return 0; ++ return ret; + } + + int __id_ctrl(int argc, char **argv, struct command *cmd, struct plugin *plugin, void (*vs)(__u8 *vs, struct json_object *root)) +-- +1.8.3.1 + diff --git a/SOURCES/0006-nvme-rem-first-perror-on-subsystem-reset-failure-.patch b/SOURCES/0006-nvme-rem-first-perror-on-subsystem-reset-failure-.patch new file mode 100644 index 0000000..b0e5468 --- /dev/null +++ b/SOURCES/0006-nvme-rem-first-perror-on-subsystem-reset-failure-.patch @@ -0,0 +1,25 @@ +From 54a00bda868ca1e45633965841b18dcece69fd3c Mon Sep 17 00:00:00 2001 +From: David Milburn +Date: Wed, 9 Jan 2019 09:05:46 -0600 +Subject: [PATCH] nvme-cli: remove first perror on subsystem reset failure + +Signed-off-by: David Milburn +--- + nvme.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/nvme.c b/nvme.c +index 0185cb5..2dc0822 100644 +--- a/nvme.c ++++ b/nvme.c +@@ -2602,7 +2602,6 @@ static int subsystem_reset(int argc, char **argv, struct command *cmd, struct pl + err = nvme_subsystem_reset(fd); + if (err < 0) { + close(fd); +- perror("Subsystem-reset"); + if (errno == ENOTTY) + fprintf(stderr, + "Subsystem-reset: NVM Subsystem Reset not supported.\n"); +-- +1.8.3.1 + diff --git a/SPECS/nvme-cli.spec b/SPECS/nvme-cli.spec index 2d61288..5558bc0 100644 --- a/SPECS/nvme-cli.spec +++ b/SPECS/nvme-cli.spec @@ -3,7 +3,7 @@ Name: nvme-cli Version: 1.6 -Release: 1%{?dist} +Release: 4%{?dist} Summary: NVMe management command line interface License: GPLv2+ @@ -11,6 +11,13 @@ URL: https://github.com/linux-nvme/nvme-cli #Source0: https://github.com/linux-nvme/%{name}/archive/%{commit0}.tar.gz Source0: https://github.com/linux-nvme/%{name}/archive/v%{version}.tar.gz +Patch0: 0001-nvme-discover-Retry-discovery-log-if-the-generation-.patch +Patch1: 0002-nvme-ioctl-retrieve-log-pages-in-4k-chunks.patch +Patch2: 0003-nvme-discover-Re-check-generation-counter-after-log-.patch +Patch3: 0004-nvme-cli-report-subsystem-reset-not-supported-by-con.patch +Patch4: 0005-nvme-list-fix-nvme-list-output-if-identify-failed-on.patch +Patch5: 0006-nvme-rem-first-perror-on-subsystem-reset-failure-.patch + BuildRequires: libuuid-devel BuildRequires: gcc @@ -20,7 +27,12 @@ nvme-cli provides NVM-Express user space tooling for Linux. %prep #%setup -qn %{name}-%{commit0} %setup - +%patch0 -p1 +%patch1 -p1 +%patch2 -p1 +%patch3 -p1 +%patch4 -p1 +%patch5 -p1 %build make PREFIX=/usr CFLAGS="%{optflags} -std=c99" LDFLAGS="%{__global_ldflags}" %{?_smp_mflags} @@ -37,8 +49,34 @@ make PREFIX=/usr CFLAGS="%{optflags} -std=c99" LDFLAGS="%{__global_ldflags}" %{? %{_mandir}/man1/nvme*.gz %{_datadir}/bash_completion.d/nvme +%clean +rm -rf $RPM_BUILD_ROOT + +%post +if [ $1 = 1 ]; then # 1 : This package is being installed for the first time + if [ ! -f /etc/nvme/hostnqn ]; then + install -D /dev/null /etc/nvme/hostnqn + echo $(nvme gen-hostnqn) > /etc/nvme/hostnqn + chmod 644 /etc/nvme/hostnqn + fi + if [ ! -f /etc/nvme/hostid ]; then + uuidgen > /etc/nvme/hostid + fi +fi + +%preun +if [ -d /etc/nvme ]; then + rm -f /etc/nvme/hostnqn + rm -f /etc/nvme/hostid + if [ ! -n "`ls -A /etc/nvme`" ]; then + rm -rf /etc/nvme + fi +fi %changelog +* Tue Oct 16 2018 dmilburn@redhat.com - 1.6-2 +- Pull in upstream fixes + * Tue Jul 24 2018 luto@kernel.org - 1.6-1 - Update to 1.6