diff mbox

[RFC,v2,3/7] ndctl: nvdimmd: add nvdimmd necessary functions

Message ID 20171114074704.3446-4-qi.fuli@jp.fujitsu.com (mailing list archive)
State New, archived
Headers show

Commit Message

QI Fuli Nov. 14, 2017, 7:47 a.m. UTC
Libnvdimmd is used to provide nvdimmd necessary functions.
The get_nvdimmd_conf() will read the nvdimmd.conf and set the
parameters' value as global variables when nvdimmd service starts.

Signed-off-by: QI Fuli <qi.fuli@jp.fujitsu.com>
---
 nvdimmd/libnvdimmd.c | 315 +++++++++++++++++++++++++++++++++++++++++++++++++++
 nvdimmd/libnvdimmd.h |  53 +++++++++
 2 files changed, 368 insertions(+)
 create mode 100644 nvdimmd/libnvdimmd.c
 create mode 100644 nvdimmd/libnvdimmd.h
diff mbox

Patch

diff --git a/nvdimmd/libnvdimmd.c b/nvdimmd/libnvdimmd.c
new file mode 100644
index 0000000..7e5d16b
--- /dev/null
+++ b/nvdimmd/libnvdimmd.c
@@ -0,0 +1,315 @@ 
+/*
+ * Copyright (c) 2017, 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.
+ */
+
+/*
+ * This program is used to provide nvdimm daemon necessary functions.
+ */
+
+#include <syslog.h>
+#include <json-c/json.h>
+#include <util/json.h>
+#include <util/filter.h>
+#include <ndctl/lib/private.h>
+#include <dirent.h>
+#include "libnvdimmd.h"
+
+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_SIZE];
+	struct log_ctx *log_ctx;
+
+	log_ctx = &ctx->ctx;
+	vsnprintf(buf, sizeof(buf), format, args);
+	syslog(priority, "%s: %s: %s", log_ctx->owner, fn, buf);
+}
+
+void log_file(struct ndctl_ctx *ctx, int priority, const char *file,
+	int line, const char *fn, const char *format, va_list args)
+{
+	DIR *dir;
+	FILE *f;
+	time_t c_time;
+	char date[32], buf[BUF_SIZE];
+	char *filename;
+	int len = strlen(nvdimmd_cf->logfile) + strlen("/var/log/nvdimmd/");
+
+	filename = (char *) malloc(len);
+	strcpy(filename, "/var/log/nvdimmd/");
+	strcat(filename, nvdimmd_cf->logfile);
+
+	dir = opendir("/var/log/nvdimmd");
+	if (dir) {
+		if (get_size(filename) >= 20000000)
+			logrotate(filename);
+	} else {
+		if (mkdir("/var/log/nvdimmd", 0744) == -1) {
+			syslog(LOG_ERR, "cannot make dir /var/log/nvdimmd\n");
+			exit(EXIT_FAILURE);
+		}
+	}
+
+	f = fopen(filename, "a+");
+	if (f == NULL) {
+		syslog(LOG_ERR, "%s cannot be opened\n", filename);
+		exit(EXIT_FAILURE);
+	}
+
+	c_time = time(NULL);
+	strftime(date, sizeof(date), "%Y/%m/%d %H:%M:%S", localtime(&c_time));
+	vsnprintf(buf, sizeof(buf), format, args);
+	fprintf(f, "%s [%u] %s: %s\n", date, (int)getpid(), fn, buf);
+	fclose(f);
+	free(filename);
+}
+
+static char *get_json_msg(struct ndctl_ctx *ctx, struct threshold_dimm *t_dimm)
+{
+	struct json_object *jdimm, *jhealth;
+	char *msg;
+
+	msg = (char *) malloc(1024);
+	msg[0] = '\0';
+	jdimm = util_dimm_to_json(t_dimm->dimm, 0);
+	if (!jdimm) {
+		printf("no jdimm");
+	}
+	jhealth = util_dimm_health_to_json(t_dimm->dimm);
+	if (jhealth)
+		json_object_object_add(jdimm, "health", jhealth);
+	else if (ndctl_dimm_is_cmd_supported(t_dimm->dimm, ND_CMD_SMART))
+		dbg(ctx, "dimm [%s] do not support smart", t_dimm->devname);
+	else
+		dbg(ctx, "dimm [%s] can not get health info", t_dimm->devname);
+
+	strcat(msg, json_object_to_json_string_ext(jdimm,
+			JSON_C_TO_STRING_PRETTY));
+	return msg;
+}
+
+static char *get_text_msg(struct ndctl_ctx *ctx, struct threshold_dimm *t_dimm)
+{
+	char *msg;
+	struct ndctl_cmd *cmd;
+	int rc;
+	unsigned int flags;
+
+	msg = (char *) malloc(1024);
+	msg[0] = '\0';
+	strcat(msg, "dev: ");
+	strcat(msg, t_dimm->devname);
+	strcat(msg, "\n health_state: ");
+
+	cmd = ndctl_dimm_cmd_new_smart(t_dimm->dimm);
+	if (!cmd) {
+		dbg(ctx, "new smart command error");
+		goto out;
+	}
+
+	rc = ndctl_cmd_submit(cmd);
+	if (rc || ndctl_cmd_get_firmware_status(cmd)) {
+		dbg(ctx, "subbmit smart command error");
+		goto out;
+	}
+
+	flags = ndctl_cmd_smart_get_flags(cmd);
+	if (flags & ND_SMART_HEALTH_VALID) {
+		unsigned int health = ndctl_cmd_smart_get_health(cmd);
+		if (health & ND_SMART_FATAL_HEALTH)
+			strcat(msg, "fatal");
+		else if (health & ND_SMART_CRITICAL_HEALTH)
+			strcat(msg, "critical");
+		else if (health & ND_SMART_NON_CRITICAL_HEALTH)
+			strcat(msg, "non-critical");
+		else
+			strcat(msg, "ok");
+	} else {
+		strcat(msg, "failed to get data");
+	}
+	strcat(msg, "\n spares_percentage: ");
+
+	if (flags & ND_SMART_SPARES_VALID) {
+		char buf[6];
+		snprintf(buf, 6, "%d", ndctl_cmd_smart_get_spares(cmd));
+		strcat(msg, buf);
+	}
+	else
+		strcat(msg, "failed to get data");
+
+	ndctl_cmd_unref(cmd);
+	return msg;
+
+ out:
+	strcat(msg, "failed to get data\n spares_percentage: failed to get data");
+	return msg;
+}
+
+static void get_notice_msg(struct ndctl_ctx *ctx, struct threshold_dimm *t_dimm,
+				char **log_msg)
+{
+	char *msg;
+	msg = (char *) malloc(2048);
+	msg[0] = '\0';
+	strcat(msg, "nvdimm dimm over threshold notify\n");
+
+	if (strcmp(nvdimmd_cf->logformat, "json") == 0)
+		strcat(msg, get_json_msg(ctx, t_dimm));
+	else
+		strcat(msg, get_text_msg(ctx, t_dimm));
+
+	*log_msg = msg;
+}
+
+int log_notify(struct ndctl_ctx *ctx, struct threshold_dimm *t_dimm,
+		int cnt_dimm, fd_set fds, int cnt_select)
+{
+	int log_notify = 0;
+	char *log_msg;
+
+	for (int i = 0; i < cnt_dimm; i++) {
+		if (log_notify >= cnt_select)
+			break;
+
+		if (!FD_ISSET(t_dimm[i].health_eventfd, &fds))
+			continue;
+		log_notify++;
+
+		get_notice_msg(ctx, &t_dimm[i], &log_msg);
+		notice(ctx, "%s", log_msg);
+		free(log_msg);
+	}
+	return log_notify;
+}
+
+int get_threshold_dimm(struct ndctl_ctx *ctx, struct threshold_dimm *t_dimm,
+			fd_set *fds, int *maxfd)
+{
+	struct ndctl_bus *bus;
+	struct ndctl_dimm *dimm;
+	bool flag = false;
+	int fd, cnt_dimm = 0;
+	char buf[BUF_SIZE];
+
+	ndctl_bus_foreach(ctx, bus) {
+		for (int i = 0; i < cnt_mbus; i++) {
+			if (util_bus_filter(bus, buslist[i])) {
+				flag = true;
+				break;
+			}
+		}
+		if (!flag)
+			continue;
+		flag = false;
+		ndctl_dimm_foreach(bus, dimm) {
+			for (int j = 0; j < cnt_mdimm; j++) {
+				if (util_dimm_filter(dimm, dimmlist[j])) {
+					flag = true;
+					break;
+				}
+			}
+			if (!flag)
+				continue;
+			flag = false;
+			if (!ndctl_dimm_is_cmd_supported(dimm,
+					ND_CMD_SMART_THRESHOLD))
+				continue;
+			t_dimm[cnt_dimm].dimm = dimm;
+			t_dimm[cnt_dimm].devname = ndctl_dimm_get_devname(dimm);
+			fd = ndctl_dimm_get_health_eventfd(dimm);
+			read(fd, buf, sizeof(buf));
+			t_dimm[cnt_dimm].health_eventfd = fd;
+
+			if (fds)
+				FD_SET(fd, fds);
+			if (maxfd) {
+				if (*maxfd < fd)
+					*maxfd = fd;
+			}
+			cnt_dimm++;
+		}
+	}
+	return cnt_dimm;
+}
+
+int get_nvdimmd_conf(const char *path)
+{
+	FILE *f;
+	char buf[BUF_SIZE];
+	struct nvdimmd_conf *conf;
+
+	f = fopen(path, "r");
+	if (f == NULL) {
+		syslog(LOG_ERR, "%s cannot be found\n", path);
+		return -1;
+	}
+
+	conf = calloc(1, sizeof(struct nvdimmd_conf));
+	if (conf == NULL)
+		goto file_err;
+
+	while (fgets(buf, BUF_SIZE, f) != NULL) {
+		char *key;
+		char *value;
+
+		key = trim_string(buf);
+
+		if (key[0] == '#' || key[0] == '\0'){
+			continue;
+		}
+
+		value = strchr(key, '=');
+		if (value == NULL)
+			continue;
+
+		value[0] = '\0';
+		value++;
+
+		key = trim_string(key);
+		if (key == NULL)
+			continue;
+		value = trim_string(value);
+		if (value == NULL)
+			continue;
+
+		if (strcmp(key, "LOGFILE") == 0) {
+			set_string(&conf->logfile, value);
+			continue;
+		}
+		if (strcmp(key, "LOGFORMAT") == 0) {
+			set_string(&conf->logformat, value);
+			continue;
+		}
+		if (strcmp(key, "MONITORBUS") == 0) {
+			set_string(&conf->mbus, value);
+			continue;
+		}
+		if (strcmp(key, "MONITORDIMM") == 0) {
+			set_string(&conf->mdimm, value);
+			continue;
+		}
+	}
+	fclose(f);
+
+	if (conf->logfile == NULL || conf->logformat == NULL
+		|| conf->mbus == NULL || conf->mdimm == NULL)
+		return -1;
+
+	nvdimmd_cf = conf;
+	cnt_mbus = split_string(nvdimmd_cf->mbus, ",", buslist);
+	cnt_mdimm = split_string(nvdimmd_cf->mdimm, ",", dimmlist);
+	return 0;
+
+file_err:
+	fclose(f);
+	return -1;
+}
diff --git a/nvdimmd/libnvdimmd.h b/nvdimmd/libnvdimmd.h
new file mode 100644
index 0000000..75317e0
--- /dev/null
+++ b/nvdimmd/libnvdimmd.h
@@ -0,0 +1,53 @@ 
+/*
+ * Copyright (c) 2017, 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.
+ */
+
+#ifndef _LIBNVDIMMD_H_
+#define _LIBBVDIMMD_H_
+
+#include <stdio.h>
+#include <util/log.h>
+#include <ndctl/libndctl.h>
+#include "util.h"
+#define BUF_SIZE 4096
+
+struct nvdimmd_conf {
+	char *logfile;
+	char *logformat;
+	char *mbus;
+	char *mdimm;
+};
+
+struct threshold_dimm {
+	struct ndctl_dimm *dimm;
+	const char *devname;
+	int health_eventfd;
+};
+
+struct nvdimmd_conf *nvdimmd_cf;
+char *buslist[NUM_MAX_DIMM];
+char *dimmlist[NUM_MAX_DIMM];
+int cnt_mbus, cnt_mdimm;
+
+void log_syslog(struct ndctl_ctx *ctx, int priority, const char *file, int line,
+		const char *fn, const char *format, va_list args);
+void log_file(struct ndctl_ctx *ctx, int priority, const char *file,
+	int line, const char *fn, const char *format, va_list args);
+
+int log_notify(struct ndctl_ctx *ctx, struct threshold_dimm *t_dimm,
+		int count_dimm, fd_set fds, int count_select);
+int get_threshold_dimm(struct ndctl_ctx *ctx,
+		struct threshold_dimm *t_dimm, fd_set *fds, int *maxfd);
+
+int get_nvdimmd_conf(const char *path);
+
+#endif