All of lore.kernel.org
 help / color / mirror / Atom feed
From: QI Fuli <qi.fuli@jp.fujitsu.com>
To: linux-nvdimm@lists.01.org
Subject: [RFC PATCH v3 2/5] ndctl: monitor: add ndctl create-monitor command
Date: Fri,  9 Feb 2018 17:02:22 +0900	[thread overview]
Message-ID: <20180209080225.5137-3-qi.fuli@jp.fujitsu.com> (raw)
In-Reply-To: <20180209080225.5137-1-qi.fuli@jp.fujitsu.com>

This patch is used to add $ndctl create-monitor command, by which users can
create a new monitor. Users can select the DIMMS to be monitored by using
[--dimm] [--bus] [--region] [--namespace] options. The notifications can
be outputed to a special file or syslog by using [--output] option, the
special file will be placed under /var/log/ndctl. A name is also required for
a monitor,so users can destroy the monitor by the name. When a monitor is
created successfully, a file with same name will be created under
/var/ndctl/monitor.
Example: 
#ndctl create-monitor --monitor m_nmem1 --dimm nmem1 --output m_nmem.log

Signed-off-by: QI Fuli <qi.fuli@jp.fujitsu.com>
---
 builtin.h         |   1 +
 configure.ac      |   3 +
 ndctl/Makefile.am |   3 +-
 ndctl/monitor.c   | 342 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 ndctl/ndctl.c     |   1 +
 5 files changed, 349 insertions(+), 1 deletion(-)
 create mode 100644 ndctl/monitor.c

diff --git a/builtin.h b/builtin.h
index 5e1b7ef..850f6a8 100644
--- a/builtin.h
+++ b/builtin.h
@@ -36,6 +36,7 @@ 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_create_monitor(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/configure.ac b/configure.ac
index 70ba360..e859e04 100644
--- a/configure.ac
+++ b/configure.ac
@@ -160,6 +160,9 @@ AC_CONFIG_FILES([
         Documentation/daxctl/Makefile
 ])
 
+AC_CONFIG_COMMANDS([monitorlogdir], [$MKDIR_P /var/log/ndctl])
+AC_CONFIG_COMMANDS([monitorprocdir], [$MKDIR_P /var/ndctl/monitor])
+
 AC_OUTPUT
 AC_MSG_RESULT([
         $PACKAGE $VERSION
diff --git a/ndctl/Makefile.am b/ndctl/Makefile.am
index 6677607..d9a484d 100644
--- a/ndctl/Makefile.am
+++ b/ndctl/Makefile.am
@@ -13,7 +13,8 @@ ndctl_SOURCES = ndctl.c \
 		test.c \
 		../util/json.c \
 		util/json-smart.c \
-		inject-error.c
+		inject-error.c \
+		monitor.c
 
 if ENABLE_DESTRUCTIVE
 ndctl_SOURCES += ../test/blk_namespaces.c \
diff --git a/ndctl/monitor.c b/ndctl/monitor.c
new file mode 100644
index 0000000..cf1cd6e
--- /dev/null
+++ b/ndctl/monitor.c
@@ -0,0 +1,342 @@
+/*
+ * Copyright (c) 2018, FUJITSU LIMITED. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
+ * more details.
+ */
+#include <stdio.h>
+#include <json-c/json.h>
+#include <signal.h>
+#include <dirent.h>
+#include <util/parse-options.h>
+#include <util/log.h>
+#include <util/filter.h>
+#include <util/json.h>
+#include <ndctl/lib/private.h>
+#include <ndctl/libndctl.h>
+#include <sys/stat.h>
+#define NUM_MAX_DIMM 1024
+#define BUF_SIZE 4096
+
+struct monitor_dimm {
+	struct ndctl_dimm *dimm;
+	const char *devname;
+	int health_eventfd;
+};
+
+static struct parameter {
+	const char *bus;
+	const char *region;
+	const char *dimm;
+	const char *namespace;
+	const char *event;
+	const char *output;
+	const char *monitor;
+	bool all;
+} param;
+
+static const char *proc_path = "/var/ndctl/monitor/";
+
+static char *get_full_path_filename(const char *path, const char *name)
+{
+	char *filename;
+	int len = strlen(path) + strlen (name) +1;
+	filename = (char *) malloc(len);
+	if (!filename)
+		return NULL;
+	filename[0] = '\0';
+	strcpy(filename, path);
+	strcat(filename, name);
+	return filename;
+}
+
+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;
+	buf = (char *)malloc(BUF_SIZE);
+	if (!buf) {
+		syslog(LOG_ERR, "could not get memory for log_syslog\n");
+		exit(EXIT_FAILURE);
+	}
+	vsnprintf(buf, BUF_SIZE, format, args);
+	syslog(priority, "%s", buf);
+	free(buf);
+}
+
+static void log_output(struct ndctl_ctx *ctx, int priority, const char *file,
+	int line, const char *fn, const char *format, va_list args)
+{
+	FILE *f;
+	char *filename, *buf;
+	const char *log_path = "/var/log/ndctl/";
+	filename = get_full_path_filename(log_path, param.output);
+
+	f = fopen(filename, "a+");
+	if (!f) {
+		syslog(LOG_ERR, "open %s failed\n", filename);
+		exit(EXIT_FAILURE);
+	}
+
+	buf = (char *)malloc(BUF_SIZE);
+	if (!buf) {
+		syslog(LOG_ERR, "could not get memory for log_output\n");
+		exit(EXIT_FAILURE);
+	}
+	vsnprintf(buf, BUF_SIZE, format, args);
+	fprintf(f, "%s\n", buf);
+	free(buf);
+	fclose(f);
+}
+
+static int notify_json_msg(struct ndctl_ctx *ctx, struct monitor_dimm *m_dimm)
+{
+	time_t c_time;
+	char date[32];
+	struct json_object *jmsg, *jdatetime, *jpid, *jdimm, *jhealth;
+
+	jmsg = json_object_new_object();
+
+	c_time = time(NULL);
+	strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&c_time));
+	jdatetime = json_object_new_string(date);
+	json_object_object_add(jmsg, "datetime", jdatetime);
+
+	jpid = json_object_new_int((int)getpid());
+	json_object_object_add(jmsg, "pid", jpid);
+
+	jdimm = util_dimm_to_json(m_dimm->dimm, 0);
+	json_object_object_add(jmsg, "dimm", jdimm);
+
+	jhealth = util_dimm_health_to_json(m_dimm->dimm);
+	if (jhealth)
+		json_object_object_add(jdimm, "health", jhealth);
+
+	notice(ctx, "%s",
+		json_object_to_json_string_ext(jmsg, JSON_C_TO_STRING_PLAIN));
+	return 0;
+}
+
+#define add_param_to_json(field) \
+if (param.field) { \
+	j##field = json_object_new_string(param.field); \
+	json_object_object_add(jmonitors, #field, j##field); \
+}
+
+static int create_monitor_proc(struct ndctl_ctx *ctx)
+{
+	time_t c_time;
+	char date[32];
+	char *filename;
+	struct json_object *jmonitors, *jmonitor, *jpid, *jcreate, *jbus,
+		*jdimm, *jregion, *jnamespace, *joutput, *jevent;
+	jmonitors = json_object_new_object();
+	add_param_to_json(monitor);
+	c_time = time(NULL);
+	strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&c_time));
+	jcreate = json_object_new_string(date);
+	json_object_object_add(jmonitors, "create", jcreate);
+	jpid = json_object_new_int((int)getpid());
+	json_object_object_add(jmonitors, "pid", jpid);
+	add_param_to_json(dimm);
+	add_param_to_json(bus);
+	add_param_to_json(region);
+	add_param_to_json(namespace);
+	add_param_to_json(event);
+	add_param_to_json(output);
+
+	filename = get_full_path_filename(proc_path, param.monitor);
+	return json_object_to_file(filename, jmonitors);
+}
+
+static int destroy_monitor_proc(void)
+{
+	char *filename;
+	filename = get_full_path_filename(proc_path, param.monitor);
+	return remove(filename);
+}
+
+static int set_monitor_dimm(struct ndctl_ctx *ctx, fd_set *fds, int *maxfd,
+				struct monitor_dimm *m_dimm)
+{
+	struct ndctl_bus *bus;
+	int fd, num_dimm = 0;
+	char buf[BUF_SIZE];
+
+	ndctl_bus_foreach(ctx, bus) {
+		struct ndctl_dimm *dimm;
+		if(!util_bus_filter(bus, param.bus)
+			|| !util_bus_filter_by_dimm(bus, param.dimm)
+			|| !util_bus_filter_by_region(bus, param.region)
+			|| !util_bus_filter_by_namespace(bus, param.namespace))
+			continue;
+		ndctl_dimm_foreach(bus, dimm) {
+			if(!util_dimm_filter(dimm, param.dimm)
+				|| !util_dimm_filter_by_region(dimm,
+						param.region)
+				|| !util_dimm_filter_by_namespace(dimm,
+						param.namespace))
+				continue;
+			if (!ndctl_dimm_is_cmd_supported(dimm,
+					ND_CMD_SMART_THRESHOLD))
+				continue;
+			m_dimm[num_dimm].dimm = dimm;
+			m_dimm[num_dimm].devname = ndctl_dimm_get_devname(dimm);
+			fd = ndctl_dimm_get_health_eventfd(dimm);
+			pread(fd, buf, sizeof(buf), 0);
+			m_dimm[num_dimm].health_eventfd = fd;
+
+			if (fds)
+				FD_SET(fd, fds);
+			if (maxfd) {
+				if (*maxfd < fd)
+					*maxfd = fd;
+			}
+			num_dimm++;
+		}
+	}
+	return num_dimm;
+}
+
+static bool check_monitor_exist(void)
+{
+	FILE *f;
+	char *filename;
+	filename = get_full_path_filename(proc_path, param.monitor);
+	f = fopen(filename, "r");
+	if (!f)
+		return false;
+	fclose(f);
+	return true;
+}
+static int monitor_dimm_event(struct ndctl_ctx *ctx)
+{
+	int rc, maxfd, num_dimm;
+	struct monitor_dimm *m_dimm;
+	char buf[BUF_SIZE];
+	m_dimm = calloc(NUM_MAX_DIMM, sizeof(struct monitor_dimm));
+	if (!m_dimm) {
+		error("monitor_dimm memory space cannot be allocated\n");
+		goto out;
+	}
+
+	fd_set fds;
+	FD_ZERO(&fds);
+
+	num_dimm = set_monitor_dimm(ctx, &fds, &maxfd, m_dimm);
+	if (num_dimm == 0) {
+		error("no monitor dimms can be found\n");
+		goto out;
+	}
+
+
+	if (daemon(0, 0) != 0) {
+		err(ctx, "daemon start failed\n");
+		goto out;
+	}
+
+	printf("ndctl create-monitor %s started\n", param.monitor);
+	if (create_monitor_proc(ctx) != 0) {
+		err(ctx, "daemon start failed\n");
+		goto out;
+	}
+
+	while(1){
+		rc = select(maxfd + 1, NULL, NULL, &fds, NULL);
+		if (rc < 1) {
+			if (rc == 0)
+				err(ctx, "select unexpected timeout\n");
+			else
+				err(ctx, "select %s\n", strerror(errno));
+			goto out_clean;
+		}
+		for (int i = 0; i < num_dimm; i++) {
+			if (!FD_ISSET(m_dimm[i].health_eventfd, &fds)){
+				FD_SET(m_dimm[i].health_eventfd, &fds);
+				continue;
+			}
+			if (notify_json_msg(ctx, &m_dimm[i]) != 0)
+				goto out_clean;
+			pread(m_dimm[i].health_eventfd, buf, sizeof(buf), 0);
+		}
+	}
+	free(m_dimm);
+	return 0;
+out:
+	printf("ndctl create-monitor %s failed\n", param.monitor);
+	return 1;
+
+out_clean:
+	err(ctx, "ndctl monitor %s stoped\n", param.monitor);
+	if (destroy_monitor_proc() != 0)
+		err(ctx, "failed to clean temp file");
+	return 1;
+
+}
+
+int cmd_create_monitor(int argc, const char **argv, void *ctx)
+{
+	const struct option options[] = {
+		OPT_STRING('b', "bus", &param.bus, "bus-id", "filter by bus"),
+		OPT_STRING('r', "region", &param.region, "region-id",
+				"filter by region"),
+		OPT_STRING('d', "dimm", &param.dimm, "dimm-id",
+				"filter by dimm"),
+		OPT_STRING('n', "namespace", &param.namespace,
+				"namespace-id", "filter by namespace id"),
+		OPT_STRING('e', "event", &param.event, "event-id",
+				"filter by event"),
+		OPT_STRING('o', "output", &param.output, "output file name",
+				"monitor output file name"),
+		OPT_STRING('m', "monitor", &param.monitor, "monitor name",
+				"monitor name")
+	};
+	const char * const u[] = {
+		"ndctl create-monitor <monitor> <output> [<options>]",
+		NULL
+	};
+	argc = parse_options(argc, argv, options, u, 0);
+	for (int i = 0; i < argc; i++) {
+		error("unknown parameter \"%s\"\n", argv[i]);
+		goto out;
+	}
+	if (!param.monitor) {
+		error("monitor name --monitor is required\n");
+		goto out;
+	}
+	if (check_monitor_exist()) {
+		error("monitor %s is exist\n", param.monitor);
+		goto out;
+	}
+	if (!param.output) {
+		error("output file name --output is required\n");
+		goto out;
+	}
+
+	ndctl_set_log_priority((struct ndctl_ctx*)ctx, LOG_NOTICE);
+
+	if (strcmp(param.output, "syslog") == 0)
+		ndctl_set_log_fn((struct ndctl_ctx*)ctx, log_syslog);
+	else
+		ndctl_set_log_fn((struct ndctl_ctx*)ctx, log_output);
+
+	if (monitor_dimm_event((struct ndctl_ctx*)ctx) != 0)
+		goto out;
+
+	char *filename;
+	filename = get_full_path_filename(proc_path, param.monitor);
+	if (remove(filename) != 0) {
+		err((struct ndctl_ctx*)ctx, "failed to delete %s\n", filename);
+		goto out;
+	}
+	return 0;
+
+out:
+	return 1;
+}
diff --git a/ndctl/ndctl.c b/ndctl/ndctl.c
index 0f748e1..6c63d79 100644
--- a/ndctl/ndctl.c
+++ b/ndctl/ndctl.c
@@ -84,6 +84,7 @@ static struct cmd_struct commands[] = {
 	{ "init-labels", cmd_init_labels },
 	{ "check-labels", cmd_check_labels },
 	{ "inject-error", cmd_inject_error },
+	{ "create-monitor", cmd_create_monitor },
 	{ "list", cmd_list },
 	{ "help", cmd_help },
 	#ifdef ENABLE_TEST
-- 
2.9.5


_______________________________________________
Linux-nvdimm mailing list
Linux-nvdimm@lists.01.org
https://lists.01.org/mailman/listinfo/linux-nvdimm

  parent reply	other threads:[~2018-02-09  7:56 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-02-09  8:02 [RFC PATCH v3 0/5] ndctl: monitor: monitor the smart events of QI Fuli
2018-02-09  8:02 ` [RFC PATCH v3 1/5] ndctl: nvdimmd: add LOG_NOTICE level to QI Fuli
2018-02-11 20:18   ` Dan Williams
2018-02-11 20:20     ` Dan Williams
2018-02-09  8:02 ` QI Fuli [this message]
2018-02-11 20:48   ` [RFC PATCH v3 2/5] ndctl: monitor: add ndctl create-monitor command Dan Williams
2018-02-13  0:54     ` Verma, Vishal L
2018-02-15  5:51       ` Qi, Fuli
2018-02-17  1:23         ` Dan Williams
2018-02-13  9:58     ` Yasunori Goto
2018-02-13 10:12       ` Yasunori Goto
2018-02-17  1:00         ` Dan Williams
2018-02-19  2:36           ` Yasunori Goto
2018-02-17  0:54       ` Dan Williams
2018-02-09  8:02 ` [RFC PATCH v3 3/5] ndctl: monitor: add ndclt list-monitor command QI Fuli
2018-02-09  8:02 ` [RFC PATCH v3 4/5] ndctl: monitor: add ndclt show-monitor command QI Fuli
2018-02-09  8:02 ` [RfC PATCH v3 5/5] ndctl: monitor: add ndclt destroy-monitor command QI Fuli
2018-02-09 18:06 ` [RFC PATCH v3 0/5] ndctl: monitor: monitor the smart events of Verma, Vishal L
2018-02-13  1:51   ` Qi, Fuli
2018-02-10  4:06 ` Dan Williams
2018-02-13  1:54   ` Qi, Fuli

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20180209080225.5137-3-qi.fuli@jp.fujitsu.com \
    --to=qi.fuli@jp.fujitsu.com \
    --cc=linux-nvdimm@lists.01.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.