new file mode 100644
@@ -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;
+}
new file mode 100644
@@ -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
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