* [ndctl PATCH 1/5] ndctl, scrub: fix ndctl_bus_wait_for_scrub_completion()
2018-04-04 21:11 [ndctl PATCH 0/5] Address Range Scrub (ARS) Utilities Dan Williams
@ 2018-04-04 21:12 ` Dan Williams
2018-04-04 21:12 ` [ndctl PATCH 2/5] ndctl, scrub: report the bus scrub state in 'ndctl list' Dan Williams
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Dan Williams @ 2018-04-04 21:12 UTC (permalink / raw)
To: linux-nvdimm
Given that we trust the kernel to increment the scrub count when
transitioning from in-progress to idle it is safe to wait forever.
Previously this routine was mistakenly waiting 120ms when it thought it
was waiting 120 seconds, was not verifying the in-progress was
cleared after a wakeup, and was not checking for the POLLMSG events that
sysfs files emit.
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
ndctl/lib/libndctl.c | 45 ++++++++++++++++++++-------------------------
1 file changed, 20 insertions(+), 25 deletions(-)
diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c
index 580a450e837c..743863b5c7e7 100644
--- a/ndctl/lib/libndctl.c
+++ b/ndctl/lib/libndctl.c
@@ -1154,55 +1154,50 @@ NDCTL_EXPORT unsigned int ndctl_bus_get_scrub_count(struct ndctl_bus *bus)
NDCTL_EXPORT int ndctl_bus_wait_for_scrub_completion(struct ndctl_bus *bus)
{
struct ndctl_ctx *ctx = ndctl_bus_get_ctx(bus);
- unsigned int tmo = 120, scrub_count;
+ unsigned int scrub_count;
char buf[SYSFS_ATTR_SIZE];
- char in_progress = '\0';
struct pollfd fds;
+ char in_progress;
int fd = 0, rc;
fd = open(bus->scrub_path, O_RDONLY|O_CLOEXEC);
+ memset(&fds, 0, sizeof(fds));
fds.fd = fd;
- fds.events = POLLPRI | POLLIN;
- do {
+ for (;;) {
rc = sysfs_read_attr(ctx, bus->scrub_path, buf);
- if (rc < 0)
+ if (rc < 0) {
+ rc = -EOPNOTSUPP;
break;
+ }
rc = sscanf(buf, "%u%c", &scrub_count, &in_progress);
- if (rc < 0)
+ if (rc < 0) {
+ rc = -EOPNOTSUPP;
break;
- else if (rc <= 1) {
+ }
+
+ if (rc == 1) {
/* scrub complete, break successfully */
rc = 0;
break;
} else if (rc == 2 && in_progress == '+') {
/* scrub in progress, wait */
- rc = poll(&fds, 1, tmo);
+ rc = poll(&fds, 1, -1);
if (rc < 0) {
- dbg(ctx, "poll error: %d\n", errno);
- break;
- } else if (rc == 0) {
- dbg(ctx, "poll timeout after: %d seconds", tmo);
- rc = -ENXIO;
+ rc = -errno;
+ dbg(ctx, "poll error: %s\n", strerror(errno));
break;
}
- if (fds.revents & (POLLERR | POLLHUP | POLLNVAL)) {
- dbg(ctx, "poll error, revents: %d\n",
- fds.revents);
- rc = -ENXIO;
- break;
- }
- } else {
- /* unknown condition */
- rc = -ENXIO;
- break;
+ dbg(ctx, "poll wake: revents: %d\n", fds.revents);
+ pread(fd, buf, 1, 0);
+ fds.revents = 0;
}
- } while (in_progress);
+ }
dbg(ctx, "bus%d: scrub complete\n", ndctl_bus_get_id(bus));
if (fd)
close (fd);
- return rc < 0 ? -ENXIO : 0;
+ return rc;
}
static int ndctl_bind(struct ndctl_ctx *ctx, struct kmod_module *module,
_______________________________________________
Linux-nvdimm mailing list
Linux-nvdimm@lists.01.org
https://lists.01.org/mailman/listinfo/linux-nvdimm
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [ndctl PATCH 2/5] ndctl, scrub: report the bus scrub state in 'ndctl list'
2018-04-04 21:11 [ndctl PATCH 0/5] Address Range Scrub (ARS) Utilities Dan Williams
2018-04-04 21:12 ` [ndctl PATCH 1/5] ndctl, scrub: fix ndctl_bus_wait_for_scrub_completion() Dan Williams
@ 2018-04-04 21:12 ` Dan Williams
2018-04-04 21:12 ` [ndctl PATCH 3/5] ndctl, scrub: add ndctl_bus_start_scrub() Dan Williams
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Dan Williams @ 2018-04-04 21:12 UTC (permalink / raw)
To: linux-nvdimm
In preparation for adding 'wait-scrub' and 'start-scrub' utility
helpers, indicate the current state of ARS operations in the listing for
bus objects. The field is omitted if the bus does not support ARS
operations.
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
ndctl/lib/libndctl.c | 49 ++++++++++++++++++++++++++++++++++++++----------
ndctl/lib/libndctl.sym | 1 +
ndctl/libndctl.h | 1 +
util/json.c | 10 ++++++++++
4 files changed, 51 insertions(+), 10 deletions(-)
diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c
index 743863b5c7e7..ff0d44ffefe6 100644
--- a/ndctl/lib/libndctl.c
+++ b/ndctl/lib/libndctl.c
@@ -1114,29 +1114,58 @@ NDCTL_EXPORT int ndctl_bus_wait_probe(struct ndctl_bus *bus)
return rc < 0 ? -ENXIO : 0;
}
-NDCTL_EXPORT unsigned int ndctl_bus_get_scrub_count(struct ndctl_bus *bus)
+static int __ndctl_bus_get_scrub_state(struct ndctl_bus *bus,
+ unsigned int *scrub_count, bool *active)
{
struct ndctl_ctx *ctx = ndctl_bus_get_ctx(bus);
char buf[SYSFS_ATTR_SIZE];
- unsigned int scrub_count;
char in_progress = '\0';
int rc;
rc = sysfs_read_attr(ctx, bus->scrub_path, buf);
if (rc < 0)
- return UINT_MAX;
+ return -EOPNOTSUPP;
- rc = sscanf(buf, "%u%c", &scrub_count, &in_progress);
+ rc = sscanf(buf, "%u%c", scrub_count, &in_progress);
if (rc < 0)
- return UINT_MAX;
- if (rc == 0) {
+ return -ENXIO;
+
+ switch (rc) {
+ case 1:
+ *active = false;
+ return 0;
+ case 2:
+ if (in_progress == '+') {
+ *active = true;
+ return 0;
+ }
+ /* fall through */
+ default:
/* unable to read scrub count */
- return UINT_MAX;
+ return -ENXIO;
}
- if (rc >= 1)
- return scrub_count;
+}
+
+NDCTL_EXPORT int ndctl_bus_get_scrub_state(struct ndctl_bus *bus)
+{
+ unsigned int scrub_count = 0;
+ bool active = false;
+ int rc;
+
+ rc = __ndctl_bus_get_scrub_state(bus, &scrub_count, &active);
+ if (rc < 0)
+ return rc;
+ return active;
+}
+
+NDCTL_EXPORT unsigned int ndctl_bus_get_scrub_count(struct ndctl_bus *bus)
+{
+ unsigned int scrub_count = 0;
+ bool active = false;
- return UINT_MAX;
+ if (__ndctl_bus_get_scrub_state(bus, &scrub_count, &active))
+ return UINT_MAX;
+ return scrub_count;
}
/**
diff --git a/ndctl/lib/libndctl.sym b/ndctl/lib/libndctl.sym
index 3209aefe6672..06cace96724f 100644
--- a/ndctl/lib/libndctl.sym
+++ b/ndctl/lib/libndctl.sym
@@ -352,4 +352,5 @@ global:
ndctl_dimm_fw_update_supported;
ndctl_region_get_persistence_domain;
ndctl_bus_get_persistence_domain;
+ ndctl_bus_get_scrub_state;
} LIBNDCTL_14;
diff --git a/ndctl/libndctl.h b/ndctl/libndctl.h
index cf6a77fd0992..36c04d871bd5 100644
--- a/ndctl/libndctl.h
+++ b/ndctl/libndctl.h
@@ -121,6 +121,7 @@ enum ndctl_persistence_domain ndctl_bus_get_persistence_domain(
int ndctl_bus_wait_probe(struct ndctl_bus *bus);
int ndctl_bus_wait_for_scrub_completion(struct ndctl_bus *bus);
unsigned int ndctl_bus_get_scrub_count(struct ndctl_bus *bus);
+int ndctl_bus_get_scrub_state(struct ndctl_bus *bus);
int ndctl_bus_has_error_injection(struct ndctl_bus *bus);
struct ndctl_dimm;
diff --git a/util/json.c b/util/json.c
index a464f21d6d5a..5b4b4c374d44 100644
--- a/util/json.c
+++ b/util/json.c
@@ -124,6 +124,7 @@ struct json_object *util_bus_to_json(struct ndctl_bus *bus)
{
struct json_object *jbus = json_object_new_object();
struct json_object *jobj;
+ int scrub;
if (!jbus)
return NULL;
@@ -138,6 +139,15 @@ struct json_object *util_bus_to_json(struct ndctl_bus *bus)
goto err;
json_object_object_add(jbus, "dev", jobj);
+ scrub = ndctl_bus_get_scrub_state(bus);
+ if (scrub < 0)
+ return jbus;
+
+ jobj = json_object_new_string(scrub ? "active" : "idle");
+ if (!jobj)
+ goto err;
+ json_object_object_add(jbus, "scrub_state", jobj);
+
return jbus;
err:
json_object_put(jbus);
_______________________________________________
Linux-nvdimm mailing list
Linux-nvdimm@lists.01.org
https://lists.01.org/mailman/listinfo/linux-nvdimm
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [ndctl PATCH 5/5] ndctl, scrub: add {wait, start}-scrub helper utilities
2018-04-04 21:11 [ndctl PATCH 0/5] Address Range Scrub (ARS) Utilities Dan Williams
` (3 preceding siblings ...)
2018-04-04 21:12 ` [ndctl PATCH 4/5] ndctl: add new START and WAIT actions Dan Williams
@ 2018-04-04 21:12 ` Dan Williams
4 siblings, 0 replies; 6+ messages in thread
From: Dan Williams @ 2018-04-04 21:12 UTC (permalink / raw)
To: linux-nvdimm
Provide utilities to make it easy for a platform owner to poll for the
completion of ARS scrubbing, or otherwise launch an ARS run across 1 or
more nvdimm buses.
These commands take 1 or more bus identifiers (bus device name, bus
number, or bus provider name), and runs a 'start' or 'wait' ARS
operation on each.
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
Documentation/ndctl/Makefile.am | 3 +
Documentation/ndctl/ars-description.txt | 9 ++
Documentation/ndctl/ndctl-start-scrub.txt | 61 ++++++++++++++
Documentation/ndctl/ndctl-wait-scrub.txt | 61 ++++++++++++++
builtin.h | 2
ndctl/Makefile.am | 1
ndctl/bus.c | 129 +++++++++++++++++++++++++++++
ndctl/ndctl.c | 2
8 files changed, 268 insertions(+)
create mode 100644 Documentation/ndctl/ars-description.txt
create mode 100644 Documentation/ndctl/ndctl-start-scrub.txt
create mode 100644 Documentation/ndctl/ndctl-wait-scrub.txt
create mode 100644 ndctl/bus.c
diff --git a/Documentation/ndctl/Makefile.am b/Documentation/ndctl/Makefile.am
index 9acb4acd966a..4f04087598b5 100644
--- a/Documentation/ndctl/Makefile.am
+++ b/Documentation/ndctl/Makefile.am
@@ -16,6 +16,8 @@ asciidoc.conf: ../asciidoc.conf.in
man1_MANS = \
ndctl.1 \
+ ndctl-wait-scrub.1 \
+ ndctl-start-scrub.1 \
ndctl-zero-labels.1 \
ndctl-read-labels.1 \
ndctl-write-labels.1 \
@@ -46,6 +48,7 @@ XML_DEPS = \
dimm-description.txt \
xable-dimm-options.txt \
xable-namespace-options.txt \
+ ars-description.txt \
labels-description.txt \
labels-options.txt
diff --git a/Documentation/ndctl/ars-description.txt b/Documentation/ndctl/ars-description.txt
new file mode 100644
index 000000000000..23db8184dcf2
--- /dev/null
+++ b/Documentation/ndctl/ars-description.txt
@@ -0,0 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
+
+DESCRIPTION
+-----------
+NVDIMM Address Range Scrub is a capability provided by platform firmware
+that allows for the discovery of memory errors by system software. It
+enables system software to pre-emptively avoid accesses that could lead
+to uncorrectable memory error handling events, and it otherwise allows
+memory errors to be enumerated.
diff --git a/Documentation/ndctl/ndctl-start-scrub.txt b/Documentation/ndctl/ndctl-start-scrub.txt
new file mode 100644
index 000000000000..365918dec920
--- /dev/null
+++ b/Documentation/ndctl/ndctl-start-scrub.txt
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: GPL-2.0
+
+ndctl-start-scrub(1)
+====================
+
+NAME
+----
+ndctl-start-scrub - start an Address Range Scrub (ARS) operation
+
+SYNOPSIS
+--------
+[verse]
+'ndctl start-scrub' [<bus-id> <bus-id2> ... <bus-idN>] [<options>]
+
+include::ars-description.txt[]
+
+The kernel provides a sysfs file ('scrub') that when written with the
+string "1\n" initiates an ARS operation. The 'ndctl start-scrub'
+operation starts an ARS, across all specified buses, and the kernel in
+turn proceeds to scrub every persistent memory address region on the
+specified buses.
+
+EXAMPLE
+-------
+Start a scrub on all nvdimm buses in the system. The json listing report
+only includes the buses that support ARS operations.
+[verse]
+
+# ndctl start-scrub
+[
+ {
+ "provider":"nfit_test.1",
+ "dev":"ndbus3",
+ "scrub_state":"active"
+ },
+ {
+ "provider":"nfit_test.0",
+ "dev":"ndbus2",
+ "scrub_state":"active"
+ }
+]
+
+When specifying an individual bus, or if there is only one bus in the
+system, the command reports whether ARS support is available.
+[verse]
+# ndctl start-scrub e820
+error starting scrub: Operation not supported
+
+OPTIONS
+-------
+-v::
+--verbose::
+ Emit debug messages for the ARS start process
+
+include::../copyright.txt[]
+
+SEE ALSO
+--------
+linkndctl:ndctl-wait-scrub[1],
+http://www.uefi.org/sites/default/files/resources/ACPI%206_2_A_Sept29.pdf[ACPI
+6.2 Specification Section 9.20.7.2 Address Range Scrubbing (ARS) Overview]
diff --git a/Documentation/ndctl/ndctl-wait-scrub.txt b/Documentation/ndctl/ndctl-wait-scrub.txt
new file mode 100644
index 000000000000..6b5f61fcf48f
--- /dev/null
+++ b/Documentation/ndctl/ndctl-wait-scrub.txt
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: GPL-2.0
+
+ndctl-wait-scrub(1)
+====================
+
+NAME
+----
+ndctl-wait-scrub - wait for an Address Range Scrub (ARS) operation to complete
+
+SYNOPSIS
+--------
+[verse]
+'ndctl wait-scrub' [<bus-id> <bus-id2> ... <bus-idN>] [<options>]
+
+include::ars-description.txt[]
+
+The kernel provides a POLL(2) capable sysfs file ('scrub') to indicate
+the state of ARS. The 'scrub' file maintains a running count of ARS runs
+that have taken place. While a current run is in progress a '+'
+character is emitted along with the current count. The 'ndctl
+wait-scrub' operation waits for 'scrub', across all specified buses, to
+indicate not in-progress at least once.
+
+EXAMPLE
+-------
+Wait for scrub on all nvdimm buses in the system. The json listing
+report at the end only includes the buses that support ARS operations.
+[verse]
+# ndctl wait-scrub
+[
+ {
+ "provider":"nfit_test.1",
+ "dev":"ndbus3",
+ "scrub_state":"idle"
+ },
+ {
+ "provider":"nfit_test.0",
+ "dev":"ndbus2",
+ "scrub_state":"idle"
+ }
+]
+
+When specifying an individual bus, or if there is only one bus in the
+system, the command reports whether ARS support is available.
+[verse]
+# ndctl wait-scrub e820
+error waiting for scrub completion: Operation not supported
+
+OPTIONS
+-------
+-v::
+--verbose::
+ Emit debug messages for the ARS wait process
+
+include::../copyright.txt[]
+
+SEE ALSO
+--------
+linkndctl:ndctl-start-scrub[1],
+http://www.uefi.org/sites/default/files/resources/ACPI%206_2_A_Sept29.pdf[ACPI
+6.2 Specification Section 9.20.7.2 Address Range Scrubbing (ARS) Overview]
diff --git a/builtin.h b/builtin.h
index b24fc99781a9..d3cc7239cdd7 100644
--- a/builtin.h
+++ b/builtin.h
@@ -36,6 +36,8 @@ int cmd_write_labels(int argc, const char **argv, void *ctx);
int cmd_init_labels(int argc, const char **argv, void *ctx);
int cmd_check_labels(int argc, const char **argv, void *ctx);
int cmd_inject_error(int argc, const char **argv, void *ctx);
+int cmd_wait_scrub(int argc, const char **argv, void *ctx);
+int cmd_start_scrub(int argc, const char **argv, void *ctx);
int cmd_list(int argc, const char **argv, void *ctx);
#ifdef ENABLE_TEST
int cmd_test(int argc, const char **argv, void *ctx);
diff --git a/ndctl/Makefile.am b/ndctl/Makefile.am
index 213cabd77a39..d22a37951537 100644
--- a/ndctl/Makefile.am
+++ b/ndctl/Makefile.am
@@ -3,6 +3,7 @@ include $(top_srcdir)/Makefile.am.in
bin_PROGRAMS = ndctl
ndctl_SOURCES = ndctl.c \
+ bus.c \
create-nfit.c \
namespace.c \
check.c \
diff --git a/ndctl/bus.c b/ndctl/bus.c
new file mode 100644
index 000000000000..fc31d065b1a5
--- /dev/null
+++ b/ndctl/bus.c
@@ -0,0 +1,129 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2015-2018 Intel Corporation. All rights reserved. */
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "action.h"
+#include <syslog.h>
+#include <builtin.h>
+#include <util/json.h>
+#include <util/filter.h>
+#include <json-c/json.h>
+#include <util/parse-options.h>
+#include <ndctl/libndctl.h>
+#include <ccan/array_size/array_size.h>
+
+static struct {
+ bool verbose;
+} param;
+
+static const struct option bus_options[] = {
+ OPT_BOOLEAN('v',"verbose", ¶m.verbose, "turn on debug"),
+ OPT_END(),
+};
+
+static int scrub_action(struct ndctl_bus *bus, enum device_action action)
+{
+ switch (action) {
+ case ACTION_WAIT:
+ return ndctl_bus_wait_for_scrub_completion(bus);
+ case ACTION_START:
+ return ndctl_bus_start_scrub(bus);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int bus_action(int argc, const char **argv, const char *usage,
+ const struct option *options, enum device_action action,
+ struct ndctl_ctx *ctx)
+{
+ const char * const u[] = {
+ usage,
+ NULL
+ };
+ struct json_object *jbuses, *jbus;
+ int i, rc, success = 0, fail = 0;
+ struct ndctl_bus *bus;
+ const char *all = "all";
+
+ argc = parse_options(argc, argv, options, u, 0);
+
+ if (param.verbose)
+ ndctl_set_log_priority(ctx, LOG_DEBUG);
+
+ if (argc == 0) {
+ argc = 1;
+ argv = &all;
+ } else
+ for (i = 0; i < argc; i++)
+ if (strcmp(argv[i], "all") == 0) {
+ argv[0] = "all";
+ argc = 1;
+ break;
+ }
+
+ jbuses = json_object_new_array();
+ if (!jbuses)
+ return -ENOMEM;
+ for (i = 0; i < argc; i++) {
+ int found = 0;
+
+ ndctl_bus_foreach(ctx, bus) {
+ if (!util_bus_filter(bus, argv[i]))
+ continue;
+ found++;
+ rc = scrub_action(bus, action);
+ if (rc == 0) {
+ success++;
+ jbus = util_bus_to_json(bus);
+ if (jbus)
+ json_object_array_add(jbuses, jbus);
+ } else if (!fail)
+ fail = rc;
+ }
+ if (!found && param.verbose)
+ fprintf(stderr, "no bus matches id: %s\n", argv[i]);
+ }
+
+ if (success)
+ util_display_json_array(stdout, jbuses,
+ JSON_C_TO_STRING_PRETTY);
+ else
+ json_object_put(jbuses);
+
+ if (success)
+ return success;
+ return fail ? fail : -ENXIO;
+}
+
+int cmd_start_scrub(int argc, const char **argv, void *ctx)
+{
+ char *usage = "ndctl start-scrub [<bus-id> <bus-id2> ... <bus-idN>] [<options>]";
+ int start = bus_action(argc, argv, usage, bus_options,
+ ACTION_START, ctx);
+
+ if (start <= 0) {
+ fprintf(stderr, "error starting scrub: %s\n",
+ strerror(-start));
+ return start;
+ } else {
+ return 0;
+ }
+}
+
+int cmd_wait_scrub(int argc, const char **argv, void *ctx)
+{
+ char *usage = "ndctl wait-scrub [<bus-id> <bus-id2> ... <bus-idN>] [<options>]";
+ int wait = bus_action(argc, argv, usage, bus_options,
+ ACTION_WAIT, ctx);
+
+ if (wait <= 0) {
+ fprintf(stderr, "error waiting for scrub completion: %s\n",
+ strerror(-wait));
+ return wait;
+ } else {
+ return 0;
+ }
+}
diff --git a/ndctl/ndctl.c b/ndctl/ndctl.c
index d3c6db1b6bf0..7daadebd52fc 100644
--- a/ndctl/ndctl.c
+++ b/ndctl/ndctl.c
@@ -86,6 +86,8 @@ static struct cmd_struct commands[] = {
{ "inject-error", cmd_inject_error },
{ "update-firmware", cmd_update_firmware },
{ "inject-smart", cmd_inject_smart },
+ { "wait-scrub", cmd_wait_scrub },
+ { "start-scrub", cmd_start_scrub },
{ "list", cmd_list },
{ "help", cmd_help },
#ifdef ENABLE_TEST
_______________________________________________
Linux-nvdimm mailing list
Linux-nvdimm@lists.01.org
https://lists.01.org/mailman/listinfo/linux-nvdimm
^ permalink raw reply related [flat|nested] 6+ messages in thread