#include "fabrics.h"
#include "ioctl.h"
#include "util.h"
+#include "log.h"
#include "private.h"
#define NVMF_HOSTID_SIZE 37
UPDATE_CFG_OPTION(ctrl_cfg, cfg, disable_sqflow, false);
UPDATE_CFG_OPTION(ctrl_cfg, cfg, hdr_digest, false);
UPDATE_CFG_OPTION(ctrl_cfg, cfg, data_digest, false);
- UPDATE_CFG_OPTION(ctrl_cfg, cfg, verbose, false);
return ctrl_cfg;
}
{
struct nvme_fabrics_config *cfg = nvme_ctrl_get_config(c);
const char *transport = nvme_ctrl_get_transport(c);
+ const char *hostnqn, *hostid;
+
+ if (!transport) {
+ nvme_msg(LOG_ERR, "need a transport (-t) argument\n");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (strncmp(transport, "loop", 4)) {
+ if (!nvme_ctrl_get_traddr(c)) {
+ nvme_msg(LOG_ERR, "need a address (-a) argument\n");
+ errno = EINVAL;
+ return -1;
+ }
+ }
/* always specify nqn as first arg - this will init the string */
if (asprintf(argstr, "nqn=%s",
char buf[0x1000], *options, *p;
fd = open(nvmf_dev, O_RDWR);
- if (fd < 0)
+ if (fd < 0) {
+ nvme_msg(LOG_ERR, "Failed to open %s: %s\n",
+ nvmf_dev, strerror(errno));
return -1;
+ }
+ nvme_msg(LOG_DEBUG, "connect ctrl, '%s'\n", argstr);
ret = write(fd, argstr, len);
if (ret != len) {
+ nvme_msg(LOG_NOTICE, "Failed to write to %s: %s\n",
+ nvmf_dev, strerror(errno));
ret = -1;
goto out_close;
}
len = read(fd, buf, sizeof(buf));
if (len < 0) {
+ nvme_msg(LOG_ERR, "Failed to read from %s: %s\n",
+ nvmf_dev, strerror(errno));
ret = -1;
goto out_close;
}
-
+ nvme_msg(LOG_DEBUG, "connect ctrl, response '%s'\n", buf);
buf[len] = '\0';
options = buf;
while ((p = strsep(&options, ",\n")) != NULL) {
goto out_close;
}
+ nvme_msg(LOG_ERR, "Failed to parse ctrl info for \"%s\"\n", argstr);
errno = EINVAL;
ret = -1;
out_close:
if (ret)
return ret;
- if (cfg->verbose)
- fprintf(stderr, "nvmf connect %s\n", argstr);
ret = __nvmf_add_ctrl(argstr);
free(argstr);
- if (cfg->verbose) {
- if (ret < 0)
- fprintf(stderr, "failed to add ctrl, error %d\n", errno);
- else
- fprintf(stderr, "nvme%d: added ctrl\n", ret);
- }
+ if (ret >= 0)
+ nvme_msg(LOG_INFO, "nvme%d: ctrl connected\n", ret);
return ret;
}
if (ret)
return ret;
- if (cfg->verbose)
- fprintf(stderr, "nvmf connect %s\n", argstr);
ret = __nvmf_add_ctrl(argstr);
free(argstr);
- if (ret < 0) {
- if (cfg->verbose)
- fprintf(stderr, "failed to add ctrl, error %d\n", ret);
+ if (ret < 0)
return ret;
- }
- if (cfg->verbose)
- fprintf(stderr, "nvme%d: ctrl connected\n", ret);
+
+ nvme_msg(LOG_INFO, "nvme%d: ctrl connected\n", ret);
return nvme_init_ctrl(h, c, ret);
}
case NVME_NQN_NVME:
break;
default:
- if (cfg->verbose)
- fprintf(stderr, "skipping discovery entry, "
- "invalid subsystem type %d\n",
- e->subtype);
+ nvme_msg(LOG_ERR, "skipping unsupported subtype %d\n",
+ e->subtype);
errno = EINVAL;
return NULL;
}
trsvcid = e->trsvcid;
break;
default:
- if (cfg->verbose)
- fprintf(stderr, "skipping discovery entry, "
- "invalid address family %d\n",
- e->trtype);
+ nvme_msg(LOG_ERR, "skipping unsupported adrfam %d\n",
+ e->adrfam);
errno = EINVAL;
return NULL;
}
traddr = e->traddr;
trsvcid = NULL;
break;
+ default:
+ nvme_msg(LOG_ERR, "skipping unsupported adrfam %d\n",
+ e->adrfam);
+ errno = EINVAL;
+ return NULL;
}
case NVMF_TRTYPE_LOOP:
break;
default:
- if (cfg->verbose)
- fprintf(stderr, "skipping discovery entry, "
- "invalid transport type %d\n",
- e->trtype);
+ nvme_msg(LOG_ERR, "skipping unsupported transport %d\n",
+ e->trtype);
errno = EINVAL;
return NULL;
}
transport = nvmf_trtype_str(e->trtype);
- if (cfg->verbose)
- fprintf(stderr, "lookup ctrl %s %s %s\n",
- transport, traddr, trsvcid);
+ nvme_msg(LOG_DEBUG, "lookup ctrl "
+ "(transport: %s, traddr: %s, trsvcid %s)\n",
+ transport, traddr, trsvcid);
c = nvme_create_ctrl(e->subnqn, transport, traddr, NULL, trsvcid);
if (!c) {
- if (cfg->verbose)
- fprintf(stderr, "skipping discovery entry, "
- "failed to allocate controller on %s port %s\n",
- transport, traddr);
+ nvme_msg(LOG_DEBUG, "skipping discovery entry, "
+ "failed to allocate %s controller with traddr %s\n",
+ transport, traddr);
errno = ENOMEM;
return NULL;
}
if (errno == EINVAL && disable_sqflow) {
errno = 0;
/* disable_sqflow is unrecognized option on older kernels */
- if (cfg->verbose)
- fprintf(stderr, "failed to connect controller, "
- "retry with disabling SQ flow control\n");
+ nvme_msg(LOG_INFO, "failed to connect controller, "
+ "retry with disabling SQ flow control\n");
disable_sqflow = false;
ret = nvmf_add_ctrl(h, c, cfg, disable_sqflow);
if (!ret)
return c;
}
- if (cfg->verbose)
- fprintf(stderr, "failed to connect controller, "
- "error %d\n", errno);
+ nvme_msg(LOG_ERR, "failed to connect controller, error %d\n", errno);
nvme_free_ctrl(c);
return NULL;
}
hdr = sizeof(struct nvmf_discovery_log);
log = malloc(hdr);
if (!log) {
+ nvme_msg(LOG_ERR,
+ "could not allocate memory for discovery log header\n");
errno = ENOMEM;
return -1;
}
memset(log, 0, hdr);
- if (nvme_ctrl_is_verbose(c))
- fprintf(stderr, "%s: discover length %d\n", name, 0x100);
+ nvme_msg(LOG_DEBUG, "%s: discover length %d\n", name, 0x100);
ret = nvme_discovery_log(nvme_ctrl_get_fd(c), 0x100, log);
if (ret) {
- if (nvme_ctrl_is_verbose(c))
- fprintf(stderr, "%s: discover failed, error %d\n",
- name, errno);
+ nvme_msg(LOG_INFO, "%s: discover failed, error %d\n",
+ name, errno);
goto out_free_log;
}
free(log);
log = malloc(size);
if (!log) {
+ nvme_msg(LOG_ERR,
+ "could not alloc memory for discovery log page\n");
errno = ENOMEM;
return -1;
}
memset(log, 0, size);
- if (nvme_ctrl_is_verbose(c))
- fprintf(stderr, "%s: discover length %d\n", name, size);
-
+ nvme_msg(LOG_DEBUG, "%s: discover length %d\n", name, size);
ret = nvme_discovery_log(nvme_ctrl_get_fd(c), size, log);
if (ret) {
- if (nvme_ctrl_is_verbose(c))
- fprintf(stderr, "%s: discover "
- "try %d/%d failed, error %d\n",
- name, retries, max_retries, errno);
+ nvme_msg(LOG_INFO,
+ "%s: discover try %d/%d failed, error %d\n",
+ name, retries, max_retries, errno);
goto out_free_log;
}
genctr = le64_to_cpu(log->genctr);
- if (nvme_ctrl_is_verbose(c))
- fprintf(stderr, "%s: discover genctr %lu, retry\n",
- name, genctr);
+ nvme_msg(LOG_DEBUG, "%s: discover genctr %lu, retry\n",
+ name, genctr);
ret = nvme_discovery_log(nvme_ctrl_get_fd(c), hdr, log);
if (ret) {
- if (nvme_ctrl_is_verbose(c))
- fprintf(stderr, "%s: discover "
- "try %d/%d failed, error %d\n",
- name, retries, max_retries, errno);
+ nvme_msg(LOG_INFO,
+ "%s: discover try %d/%d failed, error %d\n",
+ name, retries, max_retries, errno);
goto out_free_log;
}
} while (genctr != le64_to_cpu(log->genctr) &&
++retries < max_retries);
if (genctr != le64_to_cpu(log->genctr)) {
- if (nvme_ctrl_is_verbose(c))
- fprintf(stderr, "%s: discover genctr mismatch\n", name);
+ nvme_msg(LOG_INFO, "%s: discover genctr mismatch\n", name);
errno = EAGAIN;
ret = -1;
} else if (numrec != le64_to_cpu(log->numrec)) {
- if (nvme_ctrl_is_verbose(c))
- fprintf(stderr,
- "%s: could only fetch %lu of %lu records\n",
- name, numrec, le64_to_cpu(log->numrec));
+ nvme_msg(LOG_INFO, "%s: could only fetch %lu of %lu records\n",
+ name, numrec, le64_to_cpu(log->numrec));
errno = EBADSLT;
ret = -1;
} else {
--- /dev/null
+/*
+ * Copyright (C) 2021 SUSE LLC
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This file implements basic logging functionality.
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <time.h>
+#define LOG_FUNCNAME 1
+#include "log.h"
+#include "cleanup.h"
+
+#ifndef LOG_CLOCK
+#define LOG_CLOCK CLOCK_MONOTONIC
+#endif
+
+int nvme_log_level = DEFAULT_LOGLEVEL;
+bool nvme_log_timestamp;
+bool nvme_log_pid;
+
+void __attribute__((format(printf, 3, 4)))
+__nvme_msg(int lvl, const char *func, const char *format, ...)
+{
+ va_list ap;
+ char pidbuf[16];
+ char timebuf[32];
+ static const char *const formats[] = {
+ "%s%s%s",
+ "%s%s%s: ",
+ "%s<%s>%s ",
+ "%s<%s> %s: ",
+ "[%s] %s%s ",
+ "[%s]%s %s: ",
+ "[%s] <%s>%s ",
+ "[%s] <%s> %s: ",
+ };
+ char *header __cleanup__(cleanup_charp) = NULL;
+ char *message __cleanup__(cleanup_charp) = NULL;
+ int idx;
+
+ if (lvl > nvme_log_level)
+ return;
+
+ if (nvme_log_timestamp) {
+ struct timespec now;
+
+ clock_gettime(LOG_CLOCK, &now);
+ snprintf(timebuf, sizeof(timebuf), "%6ld.%06ld",
+ (long)now.tv_sec, now.tv_nsec / 1000);
+ } else
+ *timebuf = '\0';
+
+ if (nvme_log_pid)
+ snprintf(pidbuf, sizeof(pidbuf), "%ld", (long)getpid());
+ else
+ *pidbuf = '\0';
+
+ idx = ((nvme_log_timestamp ? 1 : 0) << 2) |
+ ((nvme_log_pid ? 1 : 0) << 1) | (func ? 1 : 0);
+
+ if (asprintf(&header, formats[idx], timebuf, pidbuf, func ? func : "")
+ == -1)
+ header = NULL;
+
+ va_start(ap, format);
+ if (vasprintf(&message, format, ap) == -1)
+ message = NULL;
+ va_end(ap);
+
+ fprintf(stderr, "%s%s", header ? header : "<error>",
+ message ? message : "<error>");
+
+}