* [ndctl PATCH v13 1/5] ndctl, monitor: add a new command - monitor
2018-07-13 23:33 [ndctl PATCH v13 0/5] ndctl, monitor: add ndctl monitor daemon QI Fuli
@ 2018-07-13 23:33 ` QI Fuli
2018-07-13 23:33 ` [ndctl PATCH v13 2/5] ndctl, monitor: add main ndctl monitor configuration file QI Fuli
` (4 subsequent siblings)
5 siblings, 0 replies; 11+ messages in thread
From: QI Fuli @ 2018-07-13 23:33 UTC (permalink / raw)
To: linux-nvdimm; +Cc: tokunaga.keiich
Ndctl monitor is used for monitoring the smart events of NVDIMMs.
When a smart event fires, monitor will output the notifications which
include dimm health status and event information to syslog, standard
output or a file by setting [--log] option. The notifications follow
json format and can be consumed by log collectors like Fluentd.
The objects to monitor can be selected by setting [--dimm] [--region]
[--namespace] [--bus] options and the event type can be filtered by
setting [--dimm-event] option. These options support multiple
space-separated arguments.
Ndctl monitor can be forked as a daemon by using [--daemon] option,
such as:
# ndctl monitor --daemon --log /var/log/ndctl/monitor.log
Signed-off-by: QI Fuli <qi.fuli@jp.fujitsu.com>
---
builtin.h | 1 +
ndctl/Makefile.am | 3 +-
ndctl/lib/libndctl.c | 82 +++++++
ndctl/lib/libndctl.sym | 4 +
ndctl/libndctl.h | 10 +
ndctl/monitor.c | 542 +++++++++++++++++++++++++++++++++++++++++
ndctl/ndctl.c | 1 +
util/filter.h | 9 +
8 files changed, 651 insertions(+), 1 deletion(-)
create mode 100644 ndctl/monitor.c
diff --git a/builtin.h b/builtin.h
index d3cc723..675a6ce 100644
--- a/builtin.h
+++ b/builtin.h
@@ -39,6 +39,7 @@ 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);
+int cmd_monitor(int argc, const char **argv, void *ctx);
#ifdef ENABLE_TEST
int cmd_test(int argc, const char **argv, void *ctx);
#endif
diff --git a/ndctl/Makefile.am b/ndctl/Makefile.am
index 0f56871..083609a 100644
--- a/ndctl/Makefile.am
+++ b/ndctl/Makefile.am
@@ -15,7 +15,8 @@ ndctl_SOURCES = ndctl.c \
util/json-smart.c \
util/json-firmware.c \
inject-error.c \
- inject-smart.c
+ inject-smart.c \
+ monitor.c
if ENABLE_DESTRUCTIVE
ndctl_SOURCES += ../test/blk_namespaces.c \
diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c
index 47e005e..969e4aa 100644
--- a/ndctl/lib/libndctl.c
+++ b/ndctl/lib/libndctl.c
@@ -1635,6 +1635,88 @@ NDCTL_EXPORT int ndctl_dimm_get_health_eventfd(struct ndctl_dimm *dimm)
return dimm->health_eventfd;
}
+NDCTL_EXPORT unsigned int ndctl_dimm_get_health(struct ndctl_dimm *dimm)
+{
+ struct ndctl_cmd *cmd = NULL;
+ unsigned int health;
+ struct ndctl_ctx *ctx = ndctl_dimm_get_ctx(dimm);
+ const char *devname = ndctl_dimm_get_devname(dimm);
+
+ cmd = ndctl_dimm_cmd_new_smart(dimm);
+ if (!cmd) {
+ err(ctx, "%s: no smart command support\n", devname);
+ return UINT_MAX;
+ }
+ if (ndctl_cmd_submit(cmd)) {
+ err(ctx, "%s: smart command failed\n", devname);
+ return UINT_MAX;
+ }
+
+ health = ndctl_cmd_smart_get_health(cmd);
+ ndctl_cmd_unref(cmd);
+ return health;
+}
+
+NDCTL_EXPORT unsigned int ndctl_dimm_get_flags(struct ndctl_dimm *dimm)
+{
+ struct ndctl_cmd *cmd = NULL;
+ unsigned int flags;
+ struct ndctl_ctx *ctx = ndctl_dimm_get_ctx(dimm);
+ const char *devname = ndctl_dimm_get_devname(dimm);
+
+ cmd = ndctl_dimm_cmd_new_smart(dimm);
+ if (!cmd) {
+ dbg(ctx, "%s: no smart command support\n", devname);
+ return UINT_MAX;
+ }
+ if (ndctl_cmd_submit(cmd)) {
+ dbg(ctx, "%s: smart command failed\n", devname);
+ return UINT_MAX;
+ }
+
+ flags = ndctl_cmd_smart_get_flags(cmd);
+ ndctl_cmd_unref(cmd);
+ return flags;
+}
+
+NDCTL_EXPORT int ndctl_dimm_is_flag_supported(struct ndctl_dimm *dimm,
+ unsigned int flag)
+{
+ unsigned int flags = ndctl_dimm_get_flags(dimm);
+ return (flags == UINT_MAX) ? 0 : !!(flags & flag);
+}
+
+NDCTL_EXPORT unsigned int ndctl_dimm_get_event_flags(struct ndctl_dimm *dimm)
+{
+ struct ndctl_cmd *cmd = NULL;
+ unsigned int alarm_flags, event_flags = 0;
+ struct ndctl_ctx *ctx = ndctl_dimm_get_ctx(dimm);
+ const char *devname = ndctl_dimm_get_devname(dimm);
+
+ cmd = ndctl_dimm_cmd_new_smart(dimm);
+ if (!cmd) {
+ err(ctx, "%s: no smart command support\n", devname);
+ return UINT_MAX;
+ }
+ if (ndctl_cmd_submit(cmd)) {
+ err(ctx, "%s: smart command failed\n", devname);
+ return UINT_MAX;
+ }
+
+ alarm_flags = ndctl_cmd_smart_get_alarm_flags(cmd);
+ if (alarm_flags & ND_SMART_SPARE_TRIP)
+ event_flags |= ND_EVENT_SPARES_REMAINING;
+ if (alarm_flags & ND_SMART_MTEMP_TRIP)
+ event_flags |= ND_EVENT_MEDIA_TEMPERATURE;
+ if (alarm_flags & ND_SMART_CTEMP_TRIP)
+ event_flags |= ND_EVENT_CTRL_TEMPERATURE;
+ if (ndctl_cmd_smart_get_shutdown_state(cmd))
+ event_flags |= ND_EVENT_UNCLEAN_SHUTDOWN;
+
+ ndctl_cmd_unref(cmd);
+ return event_flags;
+}
+
NDCTL_EXPORT unsigned int ndctl_dimm_handle_get_node(struct ndctl_dimm *dimm)
{
return dimm->handle >> 16 & 0xfff;
diff --git a/ndctl/lib/libndctl.sym b/ndctl/lib/libndctl.sym
index 8932ef6..9b36960 100644
--- a/ndctl/lib/libndctl.sym
+++ b/ndctl/lib/libndctl.sym
@@ -371,4 +371,8 @@ global:
LIBNDCTL_17 {
global:
ndctl_dimm_smart_inject_supported;
+ ndctl_dimm_get_health;
+ ndctl_dimm_get_flags;
+ ndctl_dimm_get_event_flags;
+ ndctl_dimm_is_flag_supported;
} LIBNDCTL_16;
diff --git a/ndctl/libndctl.h b/ndctl/libndctl.h
index 8a96c84..6a6bb0d 100644
--- a/ndctl/libndctl.h
+++ b/ndctl/libndctl.h
@@ -73,6 +73,12 @@ typedef unsigned char uuid_t[16];
extern "C" {
#endif
+#define ND_EVENT_SPARES_REMAINING (1 << 0)
+#define ND_EVENT_MEDIA_TEMPERATURE (1 << 1)
+#define ND_EVENT_CTRL_TEMPERATURE (1 << 2)
+#define ND_EVENT_HEALTH_STATE (1 << 3)
+#define ND_EVENT_UNCLEAN_SHUTDOWN (1 << 4)
+
size_t ndctl_min_namespace_size(void);
size_t ndctl_sizeof_namespace_index(void);
size_t ndctl_sizeof_namespace_label(void);
@@ -170,6 +176,10 @@ int ndctl_dimm_failed_map(struct ndctl_dimm *dimm);
int ndctl_dimm_smart_pending(struct ndctl_dimm *dimm);
int ndctl_dimm_failed_flush(struct ndctl_dimm *dimm);
int ndctl_dimm_get_health_eventfd(struct ndctl_dimm *dimm);
+unsigned int ndctl_dimm_get_health(struct ndctl_dimm *dimm);
+unsigned int ndctl_dimm_get_flags(struct ndctl_dimm *dimm);
+unsigned int ndctl_dimm_get_event_flags(struct ndctl_dimm *dimm);
+int ndctl_dimm_is_flag_supported(struct ndctl_dimm *dimm, unsigned int flag);
unsigned int ndctl_dimm_handle_get_node(struct ndctl_dimm *dimm);
unsigned int ndctl_dimm_handle_get_socket(struct ndctl_dimm *dimm);
unsigned int ndctl_dimm_handle_get_imc(struct ndctl_dimm *dimm);
diff --git a/ndctl/monitor.c b/ndctl/monitor.c
new file mode 100644
index 0000000..12317d0
--- /dev/null
+++ b/ndctl/monitor.c
@@ -0,0 +1,542 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2018, FUJITSU LIMITED. All rights reserved. */
+
+#include <stdio.h>
+#include <json-c/json.h>
+#include <libgen.h>
+#include <dirent.h>
+#include <util/log.h>
+#include <util/json.h>
+#include <util/filter.h>
+#include <util/util.h>
+#include <util/parse-options.h>
+#include <util/strbuf.h>
+#include <ndctl/lib/private.h>
+#include <ndctl/libndctl.h>
+#include <sys/epoll.h>
+#define BUF_SIZE 2048
+
+
+static struct monitor {
+ const char *log;
+ const char *dimm_event;
+ bool daemon;
+ bool human;
+ unsigned int event_flags;
+} monitor;
+
+struct monitor_dimm {
+ struct ndctl_dimm *dimm;
+ int health_eventfd;
+ unsigned int health;
+ unsigned int event_flags;
+ struct list_node list;
+};
+
+struct util_filter_params param;
+
+static int did_fail;
+
+#define fail(fmt, ...) \
+do { \
+ did_fail = 1; \
+ dbg(ctx, "ndctl-%s:%s:%d: " fmt, \
+ VERSION, __func__, __LINE__, ##__VA_ARGS__); \
+} while (0)
+
+static void log_syslog(struct ndctl_ctx *ctx, int priority, const char *file,
+ int line, const char *fn, const char *format, va_list args)
+{
+ char *buf;
+
+ if (vasprintf(&buf, format, args) < 0) {
+ fail("vasprintf error\n");
+ return;
+ }
+ syslog(priority, "%s", buf);
+
+ free(buf);
+ return;
+}
+
+static void log_standard(struct ndctl_ctx *ctx, int priority, const char *file,
+ int line, const char *fn, const char *format, va_list args)
+{
+ char *buf;
+
+ if (vasprintf(&buf, format, args) < 0) {
+ fail("vasprintf error\n");
+ return;
+ }
+
+ if (priority == 6)
+ fprintf(stdout, "%s", buf);
+ else
+ fprintf(stderr, "%s", buf);
+
+ free(buf);
+ return;
+}
+
+static void log_file(struct ndctl_ctx *ctx, int priority, const char *file,
+ int line, const char *fn, const char *format, va_list args)
+{
+ FILE *f;
+ char *buf;
+
+ if (vasprintf(&buf, format, args) < 0) {
+ fail("vasprintf error\n");
+ return;
+ }
+
+ f = fopen(monitor.log, "a+");
+ if (!f) {
+ ndctl_set_log_fn(ctx, log_syslog);
+ fail("open logfile %s failed\n%s", monitor.log, buf);
+ goto end;
+ }
+ fprintf(f, "%s", buf);
+ fflush(f);
+ fclose(f);
+end:
+ free(buf);
+ return;
+}
+
+static struct json_object *dimm_event_to_json(struct monitor_dimm *mdimm)
+{
+ struct json_object *jevent, *jobj;
+ bool spares_flag, media_temp_flag, ctrl_temp_flag,
+ health_state_flag, unclean_shutdown_flag;
+ struct ndctl_ctx *ctx = ndctl_dimm_get_ctx(mdimm->dimm);
+
+ jevent = json_object_new_object();
+ if (!jevent) {
+ fail("\n");
+ return NULL;
+ }
+
+ if (monitor.event_flags & ND_EVENT_SPARES_REMAINING) {
+ spares_flag = !!(mdimm->event_flags
+ & ND_EVENT_SPARES_REMAINING);
+ jobj = json_object_new_boolean(spares_flag);
+ if (jobj)
+ json_object_object_add(jevent,
+ "dimm-spares-remaining", jobj);
+ }
+
+ if (monitor.event_flags & ND_EVENT_MEDIA_TEMPERATURE) {
+ media_temp_flag = !!(mdimm->event_flags
+ & ND_EVENT_MEDIA_TEMPERATURE);
+ jobj = json_object_new_boolean(media_temp_flag);
+ if (jobj)
+ json_object_object_add(jevent,
+ "dimm-media-temperature", jobj);
+ }
+
+ if (monitor.event_flags & ND_EVENT_CTRL_TEMPERATURE) {
+ ctrl_temp_flag = !!(mdimm->event_flags
+ & ND_EVENT_CTRL_TEMPERATURE);
+ jobj = json_object_new_boolean(ctrl_temp_flag);
+ if (jobj)
+ json_object_object_add(jevent,
+ "dimm-controller-temperature", jobj);
+ }
+
+ if (monitor.event_flags & ND_EVENT_HEALTH_STATE) {
+ health_state_flag = !!(mdimm->event_flags
+ & ND_EVENT_HEALTH_STATE);
+ jobj = json_object_new_boolean(health_state_flag);
+ if (jobj)
+ json_object_object_add(jevent,
+ "dimm-health-state", jobj);
+ }
+
+ if (monitor.event_flags & ND_EVENT_UNCLEAN_SHUTDOWN) {
+ unclean_shutdown_flag = !!(mdimm->event_flags
+ & ND_EVENT_UNCLEAN_SHUTDOWN);
+ jobj = json_object_new_boolean(unclean_shutdown_flag);
+ if (jobj)
+ json_object_object_add(jevent,
+ "dimm-unclean-shutdown", jobj);
+ }
+
+ return jevent;
+}
+
+static int notify_dimm_event(struct monitor_dimm *mdimm)
+{
+ struct json_object *jmsg, *jdimm, *jobj;
+ struct timespec ts;
+ char timestamp[32];
+ struct ndctl_ctx *ctx = ndctl_dimm_get_ctx(mdimm->dimm);
+
+ jmsg = json_object_new_object();
+ if (!jmsg) {
+ fail("\n");
+ return -1;
+ }
+
+ clock_gettime(CLOCK_REALTIME, &ts);
+ sprintf(timestamp, "%10ld.%09ld", ts.tv_sec, ts.tv_nsec);
+ jobj = json_object_new_string(timestamp);
+ if (!jobj) {
+ fail("\n");
+ return -1;
+ }
+ json_object_object_add(jmsg, "timestamp", jobj);
+
+ jobj = json_object_new_int(getpid());
+ if (!jobj) {
+ fail("\n");
+ return -1;
+ }
+ json_object_object_add(jmsg, "pid", jobj);
+
+ jobj = dimm_event_to_json(mdimm);
+ if (!jobj) {
+ fail("\n");
+ return -1;
+ }
+ json_object_object_add(jmsg, "event", jobj);
+
+ jdimm = util_dimm_to_json(mdimm->dimm, 0);
+ if (!jdimm) {
+ fail("\n");
+ return -1;
+ }
+ json_object_object_add(jmsg, "dimm", jdimm);
+
+ jobj = util_dimm_health_to_json(mdimm->dimm);
+ if (!jobj) {
+ fail("\n");
+ return -1;
+ }
+ json_object_object_add(jdimm, "health", jobj);
+
+ if (monitor.human)
+ notice(ctx, "%s\n", json_object_to_json_string_ext(jmsg,
+ JSON_C_TO_STRING_PRETTY));
+ else
+ notice(ctx, "%s\n", json_object_to_json_string_ext(jmsg,
+ JSON_C_TO_STRING_PLAIN));
+
+ free(jobj);
+ free(jdimm);
+ free(jmsg);
+ return 0;
+}
+
+static struct monitor_dimm *util_dimm_event_filter(struct monitor_dimm *mdimm,
+ unsigned int event_flags)
+{
+ unsigned int health;
+
+ mdimm->event_flags = ndctl_dimm_get_event_flags(mdimm->dimm);
+ if (mdimm->event_flags == UINT_MAX)
+ return NULL;
+
+ health = ndctl_dimm_get_health(mdimm->dimm);
+ if (health == UINT_MAX)
+ return NULL;
+ if (mdimm->health != health)
+ mdimm->event_flags |= ND_EVENT_HEALTH_STATE;
+
+ if (mdimm->event_flags & event_flags)
+ return mdimm;
+ return NULL;
+}
+
+static int enable_dimm_supported_threshold_alarms(struct ndctl_dimm *dimm)
+{
+ unsigned int alarm;
+ int rc = -EOPNOTSUPP;
+ struct ndctl_cmd *st_cmd = NULL, *sst_cmd = NULL;
+ const char *name = ndctl_dimm_get_devname(dimm);
+ struct ndctl_ctx *ctx = ndctl_dimm_get_ctx(dimm);
+
+ st_cmd = ndctl_dimm_cmd_new_smart_threshold(dimm);
+ if (!st_cmd) {
+ err(ctx, "%s: no smart threshold command support\n", name);
+ goto out;
+ }
+ if (ndctl_cmd_submit(st_cmd)) {
+ err(ctx, "%s: smart threshold command failed\n", name);
+ goto out;
+ }
+
+ sst_cmd = ndctl_dimm_cmd_new_smart_set_threshold(st_cmd);
+ if (!sst_cmd) {
+ err(ctx, "%s: no smart set threshold command support\n", name);
+ goto out;
+ }
+
+ alarm = ndctl_cmd_smart_threshold_get_alarm_control(st_cmd);
+ if (monitor.event_flags & ND_EVENT_SPARES_REMAINING)
+ alarm |= ND_SMART_SPARE_TRIP;
+ if (monitor.event_flags & ND_EVENT_MEDIA_TEMPERATURE)
+ alarm |= ND_SMART_TEMP_TRIP;
+ if (monitor.event_flags & ND_EVENT_CTRL_TEMPERATURE)
+ alarm |= ND_SMART_CTEMP_TRIP;
+ ndctl_cmd_smart_threshold_set_alarm_control(sst_cmd, alarm);
+
+ rc = ndctl_cmd_submit(sst_cmd);
+ if (rc) {
+ err(ctx, "%s: smart set threshold command failed\n", name);
+ goto out;
+ }
+
+out:
+ ndctl_cmd_unref(sst_cmd);
+ ndctl_cmd_unref(st_cmd);
+ return rc;
+}
+
+static bool filter_region(struct ndctl_region *region,
+ struct util_filter_ctx *fctx)
+{
+ return true;
+}
+
+static void filter_dimm(struct ndctl_dimm *dimm, struct util_filter_ctx *fctx)
+{
+ struct monitor_dimm *mdimm;
+ struct monitor_filter_arg *mfa = fctx->monitor;
+ struct ndctl_ctx *ctx = ndctl_dimm_get_ctx(dimm);
+ const char *name = ndctl_dimm_get_devname(dimm);
+
+ if (!ndctl_dimm_is_cmd_supported(dimm, ND_CMD_SMART)) {
+ err(ctx, "%s: no smart support\n", name);
+ return;
+ }
+ if (!ndctl_dimm_is_cmd_supported(dimm, ND_CMD_SMART_THRESHOLD)) {
+ err(ctx, "%s: no smart threshold support\n", name);
+ return;
+ }
+
+ if (!ndctl_dimm_is_flag_supported(dimm, ND_SMART_ALARM_VALID)) {
+ err(ctx, "%s: smart alarm invalid\n", name);
+ return;
+ }
+
+ if (enable_dimm_supported_threshold_alarms(dimm)) {
+ err(ctx, "%s: enable supported threshold alarms failed\n", name);
+ return;
+ }
+
+ mdimm = calloc(1, sizeof(struct monitor_dimm));
+ if (!mdimm) {
+ err(ctx, "%s: calloc for monitor dimm failed\n", name);
+ return;
+ }
+
+ mdimm->dimm = dimm;
+ mdimm->health_eventfd = ndctl_dimm_get_health_eventfd(dimm);
+ mdimm->health = ndctl_dimm_get_health(dimm);
+ mdimm->event_flags = ndctl_dimm_get_event_flags(dimm);
+
+ if (mdimm->event_flags
+ && util_dimm_event_filter(mdimm, monitor.event_flags)) {
+ if (notify_dimm_event(mdimm)) {
+ err(ctx, "%s: notify dimm event failed\n", name);
+ free(mdimm);
+ return;
+ }
+ }
+
+ list_add_tail(&mfa->dimms, &mdimm->list);
+ if (mdimm->health_eventfd > mfa->maxfd_dimm)
+ mfa->maxfd_dimm = mdimm->health_eventfd;
+ mfa->num_dimm++;
+ return;
+}
+
+static bool filter_bus(struct ndctl_bus *bus, struct util_filter_ctx *fctx)
+{
+ return true;
+}
+
+static int monitor_event(struct ndctl_ctx *ctx,
+ struct monitor_filter_arg *mfa)
+{
+ struct epoll_event ev, *events;
+ int nfds, epollfd, i, rc;
+ struct monitor_dimm *mdimm;
+ char buf;
+
+ events = calloc(mfa->num_dimm, sizeof(struct epoll_event));
+ if (!events) {
+ err(ctx, "malloc for events error\n");
+ return 1;
+ }
+ epollfd = epoll_create1(0);
+ if (epollfd == -1) {
+ err(ctx, "epoll_create1 error\n");
+ return 1;
+ }
+ list_for_each(&mfa->dimms, mdimm, list) {
+ memset(&ev, 0, sizeof(ev));
+ rc = pread(mdimm->health_eventfd, &buf, sizeof(buf), 0);
+ if (rc < 0) {
+ err(ctx, "pread error\n");
+ return 1;
+ }
+ ev.data.ptr = mdimm;
+ if (epoll_ctl(epollfd, EPOLL_CTL_ADD,
+ mdimm->health_eventfd, &ev) != 0) {
+ err(ctx, "epoll_ctl error\n");
+ return 1;
+ }
+ }
+
+ while (1) {
+ did_fail = 0;
+ nfds = epoll_wait(epollfd, events, mfa->num_dimm, -1);
+ if (nfds <= 0) {
+ err(ctx, "epoll_wait error\n");
+ return 1;
+ }
+ for (i = 0; i < nfds; i++) {
+ mdimm = events[i].data.ptr;
+ if (util_dimm_event_filter(mdimm, monitor.event_flags)) {
+ if (notify_dimm_event(mdimm))
+ fail("%s: notify dimm event failed\n",
+ ndctl_dimm_get_devname(mdimm->dimm));
+ }
+ rc = pread(mdimm->health_eventfd, &buf, sizeof(buf), 0);
+ if (rc < 0)
+ fail("pread error\n");
+ }
+ if (did_fail)
+ return 1;
+ }
+ return 0;
+}
+
+static int parse_monitor_event(struct monitor *_monitor)
+{
+ char *dimm_event, *save;
+ const char *event;
+
+ if (!_monitor->dimm_event)
+ goto dimm_event_all;
+ dimm_event = strdup(_monitor->dimm_event);
+ if (!dimm_event)
+ return 1;
+
+ for (event = strtok_r(dimm_event, " ", &save); event;
+ event = strtok_r(NULL, " ", &save)) {
+ if (strcmp(event, "all") == 0) {
+ free(dimm_event);
+ goto dimm_event_all;
+ }
+ if (strcmp(event, "dimm-spares-remaining") == 0)
+ _monitor->event_flags |= ND_EVENT_SPARES_REMAINING;
+ if (strcmp(event, "dimm-media-temperature") == 0)
+ _monitor->event_flags |= ND_EVENT_MEDIA_TEMPERATURE;
+ if (strcmp(event, "dimm-controller-temperature") == 0)
+ _monitor->event_flags |= ND_EVENT_CTRL_TEMPERATURE;
+ if (strcmp(event, "dimm-health-state") == 0)
+ _monitor->event_flags |= ND_EVENT_HEALTH_STATE;
+ if (strcmp(event, "dimm-unclean-shutdown") == 0)
+ _monitor->event_flags |= ND_EVENT_UNCLEAN_SHUTDOWN;
+ }
+
+ free(dimm_event);
+ return 0;
+
+dimm_event_all:
+ _monitor->event_flags = ND_EVENT_SPARES_REMAINING
+ | ND_EVENT_MEDIA_TEMPERATURE
+ | ND_EVENT_CTRL_TEMPERATURE
+ | ND_EVENT_HEALTH_STATE
+ | ND_EVENT_UNCLEAN_SHUTDOWN;
+ return 0;
+}
+
+int cmd_monitor(int argc, const char **argv, void *ctx)
+{
+ const struct option options[] = {
+ OPT_STRING('b', "bus", ¶m.bus, "bus-id", "filter by bus"),
+ OPT_STRING('r', "region", ¶m.region, "region-id",
+ "filter by region"),
+ OPT_STRING('d', "dimm", ¶m.dimm, "dimm-id",
+ "filter by dimm"),
+ OPT_STRING('n', "namespace", ¶m.namespace,
+ "namespace-id", "filter by namespace id"),
+ OPT_STRING('D', "dimm-event", &monitor.dimm_event,
+ "name of event type", "filter by DIMM event type"),
+ OPT_FILENAME('l', "log", &monitor.log,
+ "<file> | syslog | standard",
+ "where to output the monitor's notification"),
+ OPT_BOOLEAN('x', "daemon", &monitor.daemon,
+ "run ndctl monitor as a daemon"),
+ OPT_BOOLEAN('u', "human", &monitor.human,
+ "use human friendly output formats"),
+ OPT_END(),
+ };
+ const char * const u[] = {
+ "ndctl monitor [<options>]",
+ NULL
+ };
+ const char *prefix = "./";
+ struct util_filter_ctx fctx = { 0 };
+ struct monitor_filter_arg mfa = { 0 };
+ int i;
+
+ argc = parse_options_prefix(argc, argv, prefix, options, u, 0);
+ for (i = 0; i < argc; i++) {
+ error("unknown parameter \"%s\"\n", argv[i]);
+ }
+ if (argc)
+ usage_with_options(u, options);
+
+ /* default to log_standard */
+ ndctl_set_log_fn((struct ndctl_ctx *)ctx, log_standard);
+ ndctl_set_log_priority((struct ndctl_ctx *)ctx, LOG_NOTICE);
+
+ if (monitor.log) {
+ if (strncmp(monitor.log, "./syslog", 8) == 0)
+ ndctl_set_log_fn((struct ndctl_ctx *)ctx, log_syslog);
+ else if (strncmp(monitor.log, "./standard", 10) == 0)
+ ; /*default, already set */
+ else
+ ndctl_set_log_fn((struct ndctl_ctx *)ctx, log_file);
+ }
+
+ if (monitor.daemon) {
+ if (daemon(0, 0) != 0) {
+ err((struct ndctl_ctx *)ctx, "daemon start failed\n");
+ goto out;
+ }
+ notice((struct ndctl_ctx *)ctx, "ndctl monitor daemon started\n");
+ }
+
+ if (parse_monitor_event(&monitor))
+ goto out;
+
+ fctx.filter_bus = filter_bus;
+ fctx.filter_dimm = filter_dimm;
+ fctx.filter_region = filter_region;
+ fctx.filter_namespace = NULL;
+ fctx.arg = &mfa;
+ list_head_init(&mfa.dimms);
+ mfa.num_dimm = 0;
+ mfa.maxfd_dimm = -1;
+ mfa.flags = 0;
+
+ if (util_filter_walk(ctx, &fctx, ¶m))
+ goto out;
+
+ if (!mfa.num_dimm) {
+ err((struct ndctl_ctx *)ctx, "no dimms to monitor\n");
+ goto out;
+ }
+
+ if (monitor_event(ctx, &mfa))
+ goto out;
+
+ return 0;
+out:
+ return 1;
+}
diff --git a/ndctl/ndctl.c b/ndctl/ndctl.c
index 7daadeb..73dabfa 100644
--- a/ndctl/ndctl.c
+++ b/ndctl/ndctl.c
@@ -89,6 +89,7 @@ static struct cmd_struct commands[] = {
{ "wait-scrub", cmd_wait_scrub },
{ "start-scrub", cmd_start_scrub },
{ "list", cmd_list },
+ { "monitor", cmd_monitor},
{ "help", cmd_help },
#ifdef ENABLE_TEST
{ "test", cmd_test },
diff --git a/util/filter.h b/util/filter.h
index effda24..c2cdddf 100644
--- a/util/filter.h
+++ b/util/filter.h
@@ -13,6 +13,7 @@
#ifndef _UTIL_FILTER_H_
#define _UTIL_FILTER_H_
#include <stdbool.h>
+#include <ccan/list/list.h>
struct ndctl_bus *util_bus_filter(struct ndctl_bus *bus, const char *ident);
struct ndctl_region *util_region_filter(struct ndctl_region *region,
@@ -50,6 +51,13 @@ struct list_filter_arg {
unsigned long flags;
};
+struct monitor_filter_arg {
+ struct list_head dimms;
+ int maxfd_dimm;
+ int num_dimm;
+ unsigned long flags;
+};
+
/*
* struct util_filter_ctx - control and callbacks for util_filter_walk()
* ->filter_bus() and ->filter_region() return bool because the
@@ -67,6 +75,7 @@ struct util_filter_ctx {
union {
void *arg;
struct list_filter_arg *list;
+ struct monitor_filter_arg *monitor;
};
};
--
2.18.0
_______________________________________________
Linux-nvdimm mailing list
Linux-nvdimm@lists.01.org
https://lists.01.org/mailman/listinfo/linux-nvdimm
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [ndctl PATCH v13 2/5] ndctl, monitor: add main ndctl monitor configuration file
2018-07-13 23:33 [ndctl PATCH v13 0/5] ndctl, monitor: add ndctl monitor daemon QI Fuli
2018-07-13 23:33 ` [ndctl PATCH v13 1/5] ndctl, monitor: add a new command - monitor QI Fuli
@ 2018-07-13 23:33 ` QI Fuli
2018-10-16 0:23 ` Dan Williams
2018-07-13 23:33 ` [ndctl PATCH v13 3/5] ndctl, monitor: add the unit file of systemd for ndctl-monitor service QI Fuli
` (3 subsequent siblings)
5 siblings, 1 reply; 11+ messages in thread
From: QI Fuli @ 2018-07-13 23:33 UTC (permalink / raw)
To: linux-nvdimm; +Cc: tokunaga.keiich
This patch adds the main configuration file(/etc/ndctl/monitor.conf)
of ndctl monitor. It contains the configuration directives that give
ndctl monitor instructions. Users can change the configuration by
editing this file or using [--config-file] option to override this
file. The changed value will work after restart ndctl monitor service.
Signed-off-by: QI Fuli <qi.fuli@jp.fujitsu.com>
---
configure.ac | 1 +
ndctl.spec.in | 1 +
ndctl/Makefile.am | 5 +++
ndctl/monitor.c | 110 ++++++++++++++++++++++++++++++++++++++++++++-
ndctl/monitor.conf | 41 +++++++++++++++++
5 files changed, 157 insertions(+), 1 deletion(-)
create mode 100644 ndctl/monitor.conf
diff --git a/configure.ac b/configure.ac
index cf44260..ff0096d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -144,6 +144,7 @@ AC_CHECK_FUNCS([ \
])
my_CFLAGS="\
+-D DEF_CONF_FILE='\"${sysconfdir}/ndctl/monitor.conf\"' \
-Wall \
-Wchar-subscripts \
-Wformat-security \
diff --git a/ndctl.spec.in b/ndctl.spec.in
index e2c879c..41a1d59 100644
--- a/ndctl.spec.in
+++ b/ndctl.spec.in
@@ -116,6 +116,7 @@ make check
%{_bindir}/ndctl
%{_mandir}/man1/ndctl*
%{bashcompdir}/
+%{_sysconfdir}/ndctl/monitor.conf
%files -n daxctl
%defattr(-,root,root)
diff --git a/ndctl/Makefile.am b/ndctl/Makefile.am
index 083609a..58b747a 100644
--- a/ndctl/Makefile.am
+++ b/ndctl/Makefile.am
@@ -42,3 +42,8 @@ ndctl_SOURCES += ../test/libndctl.c \
../test/core.c \
test.c
endif
+
+monitor_config_file = monitor.conf
+monitor_configdir = $(sysconfdir)/ndctl/
+monitor_config_DATA = $(monitor_config_file)
+EXTRA_DIST += $(monitor_config_file)
diff --git a/ndctl/monitor.c b/ndctl/monitor.c
index 12317d0..8300250 100644
--- a/ndctl/monitor.c
+++ b/ndctl/monitor.c
@@ -16,9 +16,9 @@
#include <sys/epoll.h>
#define BUF_SIZE 2048
-
static struct monitor {
const char *log;
+ const char *config_file;
const char *dimm_event;
bool daemon;
bool human;
@@ -454,6 +454,108 @@ dimm_event_all:
return 0;
}
+static void parse_config(const char **arg, char *key, char *val, char *ident)
+{
+ struct strbuf value = STRBUF_INIT;
+ size_t arg_len = *arg ? strlen(*arg) : 0;
+
+ if (!ident || !key || (strcmp(ident, key) != 0))
+ return;
+
+ if (arg_len) {
+ strbuf_add(&value, *arg, arg_len);
+ strbuf_addstr(&value, " ");
+ }
+ strbuf_addstr(&value, val);
+ *arg = strbuf_detach(&value, NULL);
+}
+
+static int read_config_file(struct ndctl_ctx *ctx, struct monitor *_monitor,
+ struct util_filter_params *_param)
+{
+ FILE *f;
+ int line = 0;
+ size_t len = 0;
+ char *buf, *value, *config_file;
+
+ if (_monitor->config_file)
+ config_file = strdup(_monitor->config_file);
+ else
+ config_file = strdup(DEF_CONF_FILE);
+ if (!config_file) {
+ fail("strdup default config file failed\n");
+ goto out;
+ }
+
+ buf = malloc(BUF_SIZE);
+ if (!buf) {
+ fail("malloc read config-file buf error\n");
+ goto out;
+ }
+
+ f = fopen(config_file, "r");
+ if (!f) {
+ fail("config-file: %s cannot be opened\n", config_file);
+ goto out;
+ }
+
+ while (fgets(buf, BUF_SIZE, f)) {
+ value = NULL;
+ line++;
+
+ while (isspace(*buf))
+ buf++;
+
+ if (*buf == '#' || *buf == '\0')
+ continue;
+
+ value = strchr(buf, '=');
+ if (!value) {
+ fail("config-file syntax error, skip line[%i]\n", line);
+ continue;
+ }
+
+ value[0] = '\0';
+ value++;
+
+ while (isspace(value[0]))
+ value++;
+
+ len = strlen(buf);
+ if (len == 0)
+ continue;
+ while (isspace(buf[len-1]))
+ len--;
+ buf[len] = '\0';
+
+ len = strlen(value);
+ if (len == 0)
+ continue;
+ while (isspace(value[len-1]))
+ len--;
+ value[len] = '\0';
+
+ if (len == 0)
+ continue;
+
+ parse_config(&_param->bus, "bus", value, buf);
+ parse_config(&_param->dimm, "dimm", value, buf);
+ parse_config(&_param->region, "region", value, buf);
+ parse_config(&_param->namespace, "namespace", value, buf);
+ parse_config(&_monitor->dimm_event, "dimm-event", value, buf);
+
+ if (!_monitor->log)
+ parse_config(&_monitor->log, "log", value, buf);
+ }
+ fclose(f);
+ free(config_file);
+ return 0;
+out:
+ if (config_file)
+ free(config_file);
+ return 1;
+}
+
int cmd_monitor(int argc, const char **argv, void *ctx)
{
const struct option options[] = {
@@ -469,6 +571,8 @@ int cmd_monitor(int argc, const char **argv, void *ctx)
OPT_FILENAME('l', "log", &monitor.log,
"<file> | syslog | standard",
"where to output the monitor's notification"),
+ OPT_FILENAME('c', "config-file", &monitor.config_file,
+ "config-file", "override the default config"),
OPT_BOOLEAN('x', "daemon", &monitor.daemon,
"run ndctl monitor as a daemon"),
OPT_BOOLEAN('u', "human", &monitor.human,
@@ -495,7 +599,11 @@ int cmd_monitor(int argc, const char **argv, void *ctx)
ndctl_set_log_fn((struct ndctl_ctx *)ctx, log_standard);
ndctl_set_log_priority((struct ndctl_ctx *)ctx, LOG_NOTICE);
+ if (read_config_file((struct ndctl_ctx *)ctx, &monitor, ¶m))
+ goto out;
+
if (monitor.log) {
+ fix_filename(prefix, (const char **)&monitor.log);
if (strncmp(monitor.log, "./syslog", 8) == 0)
ndctl_set_log_fn((struct ndctl_ctx *)ctx, log_syslog);
else if (strncmp(monitor.log, "./standard", 10) == 0)
diff --git a/ndctl/monitor.conf b/ndctl/monitor.conf
new file mode 100644
index 0000000..857aadf
--- /dev/null
+++ b/ndctl/monitor.conf
@@ -0,0 +1,41 @@
+# This is the main ndctl monitor configuration file. It contains the
+# configuration directives that give ndctl monitor instructions.
+# You can change the configuration of ndctl monitor by editing this
+# file or using [--config-file=<file>] option to override this one.
+# The changed value will work after restart ndctl monitor service.
+
+# In this file, lines starting with a hash (#) are comments.
+# The configurations should follow <key> = <value> style.
+# Multiple space-separated values are allowed, but except the following
+# characters: : ? / \ % " ' $ & ! * { } [ ] ( ) = < > @
+
+# The objects to monitor are filtered via dimm's name by setting key "dimm".
+# If this value is different from the value of [--dimm=<value>] option,
+# both of the values will work.
+# dimm = all
+
+# The objects to monitor are filtered via its parent bus by setting key "bus".
+# If this value is different from the value of [--bus=<value>] option,
+# both of the values will work.
+# bus = all
+
+# The objects to monitor are filtered via region by setting key "region".
+# If this value is different from the value of [--region=<value>] option,
+# both of the values will work.
+# region = all
+
+# The objects to monitor are filtered via namespace by setting key "namespace".
+# If this value is different from the value of [--namespace=<value>] option,
+# both of the values will work.
+# namespace = all
+
+# The DIMM events to monitor are filtered via event type by setting key
+# "dimm-event". If this value is different from the value of
+# [--dimm-event=<value>] option, both of the values will work.
+# dimm-event = all
+
+# Users can choose to output the notifications to syslog (log=syslog),
+# to standard output (log=standard) or to write into a special file (log=<file>)
+# by setting key "log". If this value is in conflict with the value of
+# [--log=<value>] option, this value will be ignored.
+# log = /var/log/ndctl/monitor.log
--
2.18.0
_______________________________________________
Linux-nvdimm mailing list
Linux-nvdimm@lists.01.org
https://lists.01.org/mailman/listinfo/linux-nvdimm
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [ndctl PATCH v13 5/5] ndctl, test: add a new unit test for monitor
2018-07-13 23:33 [ndctl PATCH v13 0/5] ndctl, monitor: add ndctl monitor daemon QI Fuli
` (3 preceding siblings ...)
2018-07-13 23:33 ` [ndctl PATCH v13 4/5] ndctl, documentation: add man page for monitor QI Fuli
@ 2018-07-13 23:33 ` QI Fuli
2018-07-19 0:42 ` [ndctl PATCH v13 0/5] ndctl, monitor: add ndctl monitor daemon Verma, Vishal L
5 siblings, 0 replies; 11+ messages in thread
From: QI Fuli @ 2018-07-13 23:33 UTC (permalink / raw)
To: linux-nvdimm; +Cc: tokunaga.keiich
Add a new unit test to test all options of the monitor command.
Based-on-patch-by: Yasunori Goto <y-goto@jp.fujitsu.com>
Acked-by: Masayoshi Mizuma <m.mizuma@jp.fujitsu.com>
Signed-off-by: QI Fuli <qi.fuli@jp.fujitsu.com>
---
.gitignore | 1 +
test/Makefile.am | 14 +++-
test/list-smart-dimm.c | 117 +++++++++++++++++++++++++++
test/monitor.sh | 176 +++++++++++++++++++++++++++++++++++++++++
4 files changed, 306 insertions(+), 2 deletions(-)
create mode 100644 test/list-smart-dimm.c
create mode 100755 test/monitor.sh
diff --git a/.gitignore b/.gitignore
index 1016b3b..0baace4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -56,3 +56,4 @@ test/smart-notify
test/fio.job
test/local-write-0-verify.state
test/ack-shutdown-count-set
+test/list-smart-dimm
diff --git a/test/Makefile.am b/test/Makefile.am
index cd451e9..8c55056 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -21,7 +21,8 @@ TESTS =\
btt-pad-compat.sh \
firmware-update.sh \
ack-shutdown-count-set \
- rescan-partitions.sh
+ rescan-partitions.sh \
+ monitor.sh
check_PROGRAMS =\
libndctl \
@@ -34,7 +35,8 @@ check_PROGRAMS =\
smart-listen \
hugetlb \
daxdev-errors \
- ack-shutdown-count-set
+ ack-shutdown-count-set \
+ list-smart-dimm
if ENABLE_DESTRUCTIVE
TESTS +=\
@@ -151,3 +153,11 @@ multi_pmem_LDADD = \
$(UUID_LIBS) \
$(KMOD_LIBS) \
../libutil.a
+
+list_smart_dimm_SOURCES = \
+ list-smart-dimm.c \
+ ../util/json.c
+list_smart_dimm_LDADD = \
+ $(LIBNDCTL_LIB) \
+ $(JSON_LIBS) \
+ ../libutil.a
diff --git a/test/list-smart-dimm.c b/test/list-smart-dimm.c
new file mode 100644
index 0000000..c9982d5
--- /dev/null
+++ b/test/list-smart-dimm.c
@@ -0,0 +1,117 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2018, FUJITSU LIMITED. All rights reserved. */
+
+#include <stdio.h>
+#include <errno.h>
+#include <util/json.h>
+#include <util/filter.h>
+#include <json-c/json.h>
+#include <ndctl/libndctl.h>
+#include <util/parse-options.h>
+#include <ndctl.h>
+
+struct util_filter_params param;
+static int did_fail;
+static int jflag = JSON_C_TO_STRING_PRETTY;
+
+#define fail(fmt, ...) \
+do { \
+ did_fail = 1; \
+ fprintf(stderr, "ndctl-%s:%s:%d: " fmt, \
+ VERSION, __func__, __LINE__, ##__VA_ARGS__); \
+} while (0)
+
+static bool filter_region(struct ndctl_region *region,
+ struct util_filter_ctx *ctx)
+{
+ return true;
+}
+
+static void filter_dimm(struct ndctl_dimm *dimm, struct util_filter_ctx *ctx)
+{
+ struct list_filter_arg *lfa = ctx->list;
+ struct json_object *jdimm;
+
+ if (!ndctl_dimm_is_cmd_supported(dimm, ND_CMD_SMART))
+ return;
+ if (!ndctl_dimm_is_cmd_supported(dimm, ND_CMD_SMART_THRESHOLD))
+ return;
+ if (!ndctl_dimm_is_flag_supported(dimm, ND_SMART_ALARM_VALID))
+ return;
+
+ if (!lfa->jdimms) {
+ lfa->jdimms = json_object_new_array();
+ if (!lfa->jdimms) {
+ fail("\n");
+ return;
+ }
+ }
+
+ jdimm = util_dimm_to_json(dimm, lfa->flags);
+ if (!jdimm) {
+ fail("\n");
+ return;
+ }
+
+ json_object_array_add(lfa->jdimms, jdimm);
+}
+
+static bool filter_bus(struct ndctl_bus *bus, struct util_filter_ctx *ctx)
+{
+ return true;
+}
+
+static int list_display(struct list_filter_arg *lfa)
+{
+ struct json_object *jdimms = lfa->jdimms;
+
+ if (jdimms)
+ util_display_json_array(stdout, jdimms, jflag);
+ return 0;
+}
+
+int main(int argc, const char *argv[])
+{
+ struct ndctl_ctx *ctx;
+ int i, rc;
+ const struct option options[] = {
+ OPT_STRING('b', "bus", ¶m.bus, "bus-id", "filter by bus"),
+ OPT_STRING('r', "region", ¶m.region, "region-id",
+ "filter by region"),
+ OPT_STRING('d', "dimm", ¶m.dimm, "dimm-id",
+ "filter by dimm"),
+ OPT_STRING('n', "namespace", ¶m.namespace, "namespace-id",
+ "filter by namespace id"),
+ OPT_END(),
+ };
+ const char * const u[] = {
+ "list-smart-dimm [<options>]",
+ NULL
+ };
+ struct util_filter_ctx fctx = { 0 };
+ struct list_filter_arg lfa = { 0 };
+
+ rc = ndctl_new(&ctx);
+ if (rc < 0)
+ return EXIT_FAILURE;
+ argc = parse_options(argc, argv, options, u, 0);
+ for (i = 0; i < argc; i++)
+ error("unknown parameter \"%s\"\n", argv[i]);
+ if (argc)
+ usage_with_options(u, options);
+
+ fctx.filter_bus = filter_bus;
+ fctx.filter_dimm = filter_dimm;
+ fctx.filter_region = filter_region;
+ fctx.filter_namespace = NULL;
+ fctx.list = &lfa;
+ lfa.flags = 0;
+
+ rc = util_filter_walk(ctx, &fctx, ¶m);
+ if (rc)
+ return rc;
+
+ if (list_display(&lfa) || did_fail)
+ return -ENOMEM;
+ return 0;
+}
diff --git a/test/monitor.sh b/test/monitor.sh
new file mode 100755
index 0000000..1bbfd14
--- /dev/null
+++ b/test/monitor.sh
@@ -0,0 +1,176 @@
+#!/bin/bash -Ex
+
+# SPDX-License-Identifier: GPL-2.0
+# Copyright(c) 2018, FUJITSU LIMITED. All rights reserved.
+
+rc=77
+monitor_pid=65536
+logfile=""
+conf_file=""
+monitor_dimms=""
+monitor_regions=""
+monitor_namespace=""
+smart_supported_bus=""
+
+. ./common
+
+trap 'err $LINENO' ERR
+
+check_min_kver "4.15" || do_skip "kernel $KVER may not support monitor service"
+
+init()
+{
+ $NDCTL disable-region -b $NFIT_TEST_BUS0 all
+ $NDCTL zero-labels -b $NFIT_TEST_BUS0 all
+ $NDCTL enable-region -b $NFIT_TEST_BUS0 all
+}
+
+start_monitor()
+{
+ logfile=$(mktemp)
+ $NDCTL monitor -l $logfile $1 &
+ monitor_pid=$!
+ sync; sleep 3
+ truncate --size 0 $logfile #remove startup log
+}
+
+set_smart_supported_bus()
+{
+ smart_supported_bus=$NFIT_TEST_BUS0
+ monitor_dimms=$(./list-smart-dimm -b $smart_supported_bus | jq -r .[0].dev)
+ if [ -z $monitor_dimms ]; then
+ smart_supported_bus=$NFIT_TEST_BUS1
+ fi
+}
+
+get_monitor_dimm()
+{
+ jlist=$(./list-smart-dimm -b $smart_supported_bus $1)
+ monitor_dimms=$(jq '.[]."dev"?, ."dev"?' <<<$jlist | sort | uniq | xargs)
+ echo $monitor_dimms
+}
+
+call_notify()
+{
+ ./smart-notify $smart_supported_bus
+ sync; sleep 3
+}
+
+inject_smart()
+{
+ $NDCTL inject-smart $monitor_dimms $1
+ sync; sleep 3
+}
+
+check_result()
+{
+ jlog=$(cat $logfile)
+ notify_dimms=$(jq ."dimm"."dev" <<<$jlog | sort | uniq | xargs)
+ [[ $1 == $notify_dimms ]]
+}
+
+stop_monitor()
+{
+ kill $monitor_pid
+ rm $logfile
+}
+
+test_filter_dimm()
+{
+ monitor_dimms=$(get_monitor_dimm | awk '{print $1}')
+ start_monitor "-d $monitor_dimms"
+ call_notify
+ check_result "$monitor_dimms"
+ stop_monitor
+}
+
+test_filter_bus()
+{
+ monitor_dimms=$(get_monitor_dimm)
+ start_monitor "-b $smart_supported_bus"
+ call_notify
+ check_result "$monitor_dimms"
+ stop_monitor
+}
+
+test_filter_region()
+{
+ count=$($NDCTL list -R -b $smart_supported_bus | jq -r .[].dev | wc -l)
+ i=0
+ while [ $i -lt $count ]; do
+ monitor_region=$($NDCTL list -R -b $smart_supported_bus | jq -r .[$i].dev)
+ monitor_dimms=$(get_monitor_dimm "-r $monitor_region")
+ [ ! -z $monitor_dimms ] && break
+ i=$((i + 1))
+ done
+ start_monitor "-r $monitor_region"
+ call_notify
+ check_result "$monitor_dimms"
+ stop_monitor
+}
+
+test_filter_namespace()
+{
+ init
+ monitor_namespace=$($NDCTL create-namespace -b $smart_supported_bus | jq -r .dev)
+ monitor_dimms=$(get_monitor_dimm "-n $monitor_namespace")
+ start_monitor "-n $monitor_namespace"
+ call_notify
+ check_result "$monitor_dimms"
+ stop_monitor
+ $NDCTL destroy-namespace $monitor_namespace -f
+}
+
+test_conf_file()
+{
+ monitor_dimms=$(get_monitor_dimm)
+ conf_file=$(mktemp)
+ echo "dimm = $monitor_dimms" > $conf_file
+ start_monitor "-c $conf_file"
+ call_notify
+ check_result "$monitor_dimms"
+ stop_monitor
+ rm $conf_file
+}
+
+test_filter_dimmevent()
+{
+ monitor_dimms="$(get_monitor_dimm | awk '{print $1}')"
+
+ start_monitor "-d $monitor_dimms -D dimm-unclean-shutdown"
+ inject_smart "-U"
+ check_result "$monitor_dimms"
+ stop_monitor
+
+ inject_value=$($NDCTL list -H -d $monitor_dimms | jq -r .[]."health"."spares_threshold")
+ inject_value=$((inject_value - 1))
+ start_monitor "-d $monitor_dimms -D dimm-spares-remaining"
+ inject_smart "-s $inject_value"
+ check_result "$monitor_dimms"
+ stop_monitor
+
+ inject_value=$($NDCTL list -H -d $monitor_dimms | jq -r .[]."health"."temperature_threshold")
+ inject_value=$((inject_value + 1))
+ start_monitor "-d $monitor_dimms -D dimm-media-temperature"
+ inject_smart "-s $inject_value"
+ check_result "$monitor_dimms"
+ stop_monitor
+}
+
+do_tests()
+{
+ test_filter_dimm
+ test_filter_bus
+ test_filter_region
+ test_filter_namespace
+ test_conf_file
+ test_filter_dimmevent
+}
+
+modprobe nfit_test
+rc=1
+init
+set_smart_supported_bus
+do_tests
+_cleanup
+exit 0
--
2.18.0
_______________________________________________
Linux-nvdimm mailing list
Linux-nvdimm@lists.01.org
https://lists.01.org/mailman/listinfo/linux-nvdimm
^ permalink raw reply related [flat|nested] 11+ messages in thread