summaryrefslogtreecommitdiffstats
path: root/src/nvme/tree.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-08-05 08:35:48 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-08-05 08:35:48 +0000
commitfb4382cf6ceb11ce2c5781d14714e15e45022d03 (patch)
tree4d529e6152272fde35bc85955a300b4811f672ca /src/nvme/tree.c
parentReleasing debian version 1.9-1. (diff)
downloadlibnvme-fb4382cf6ceb11ce2c5781d14714e15e45022d03.tar.xz
libnvme-fb4382cf6ceb11ce2c5781d14714e15e45022d03.zip
Merging upstream version 1.10.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/nvme/tree.c')
-rw-r--r--src/nvme/tree.c179
1 files changed, 153 insertions, 26 deletions
diff --git a/src/nvme/tree.c b/src/nvme/tree.c
index eb9486d..3722461 100644
--- a/src/nvme/tree.c
+++ b/src/nvme/tree.c
@@ -117,16 +117,99 @@ static void cleanup_dirents(struct dirents *ents)
#define _cleanup_dirents_ __cleanup__(cleanup_dirents)
+static char *nvme_hostid_from_hostnqn(const char *hostnqn)
+{
+ const char *uuid;
+
+ uuid = strstr(hostnqn, "uuid:");
+ if (!uuid)
+ return NULL;
+
+ return strdup(uuid + strlen("uuid:"));
+}
+
+int nvme_host_get_ids(nvme_root_t r,
+ char *hostnqn_arg, char *hostid_arg,
+ char **hostnqn, char **hostid)
+{
+ _cleanup_free_ char *nqn = NULL;
+ _cleanup_free_ char *hid = NULL;
+ _cleanup_free_ char *hnqn = NULL;
+ nvme_host_t h;
+
+ /* command line argumments */
+ if (hostid_arg)
+ hid = strdup(hostid_arg);
+ if (hostnqn_arg)
+ hnqn = strdup(hostnqn_arg);
+
+ /* JSON config: assume the first entry is the default host */
+ h = nvme_first_host(r);
+ if (h) {
+ if (!hid)
+ hid = strdup(nvme_host_get_hostid(h));
+ if (!hnqn)
+ hnqn = strdup(nvme_host_get_hostnqn(h));
+ }
+
+ /* /etc/nvme/hostid and/or /etc/nvme/hostnqn */
+ if (!hid)
+ hid = nvmf_hostid_from_file();
+ if (!hnqn)
+ hnqn = nvmf_hostnqn_from_file();
+
+ /* incomplete configuration, thus derive hostid from hostnqn */
+ if (!hid && hnqn)
+ hid = nvme_hostid_from_hostnqn(hnqn);
+
+ /*
+ * fallback to use either DMI information or device-tree. If all
+ * fails generate one
+ */
+ if (!hid) {
+ hid = nvmf_hostid_generate();
+ if (!hid) {
+ errno = -ENOMEM;
+ return -1;
+ }
+
+ nvme_msg(r, LOG_DEBUG,
+ "warning: using auto generated hostid and hostnqn\n");
+ }
+
+ /* incomplete configuration, thus derive hostnqn from hostid */
+ if (!hnqn) {
+ hnqn = nvmf_hostnqn_generate_from_hostid(hid);
+ if (!hnqn) {
+ errno = -ENOMEM;
+ return -1;
+ }
+ }
+
+ /* sanity checks */
+ nqn = nvme_hostid_from_hostnqn(hnqn);
+ if (nqn && strcmp(nqn, hid)) {
+ nvme_msg(r, LOG_DEBUG,
+ "warning: use hostid '%s' which does not match uuid in hostnqn '%s'\n",
+ hid, hnqn);
+ }
+
+ *hostid = hid;
+ *hostnqn = hnqn;
+ hid = NULL;
+ hnqn = NULL;
+
+ return 0;
+}
+
nvme_host_t nvme_default_host(nvme_root_t r)
{
- struct nvme_host *h;
_cleanup_free_ char *hostnqn = NULL;
_cleanup_free_ char *hostid = NULL;
+ struct nvme_host *h;
- hostnqn = nvmf_hostnqn_from_file();
- if (!hostnqn)
- hostnqn = nvmf_hostnqn_generate();
- hostid = nvmf_hostid_from_file();
+ if (nvme_host_get_ids(r, NULL, NULL, &hostnqn, &hostid))
+ return NULL;
h = nvme_lookup_host(r, hostnqn, hostid);
@@ -187,25 +270,37 @@ int nvme_scan_topology(struct nvme_root *r, nvme_scan_filter_t f, void *f_args)
nvme_root_t nvme_create_root(FILE *fp, int log_level)
{
- struct nvme_root *r = calloc(1, sizeof(*r));
+ struct nvme_root *r;
+ int fd;
+ r = calloc(1, sizeof(*r));
if (!r) {
errno = ENOMEM;
return NULL;
}
- r->log_level = log_level;
- r->fp = stderr;
- if (fp)
- r->fp = fp;
+
+ if (fp) {
+ fd = fileno(fp);
+ if (fd < 0) {
+ free(r);
+ return NULL;
+ }
+ } else
+ fd = STDERR_FILENO;
+
+ r->log.fd = fd;
+ r->log.level = log_level;
+
list_head_init(&r->hosts);
list_head_init(&r->endpoints);
- nvme_set_root(r);
+
return r;
}
int nvme_read_config(nvme_root_t r, const char *config_file)
{
int err = -1;
+ int tmp;
if (!r || !config_file) {
errno = ENODEV;
@@ -217,13 +312,17 @@ int nvme_read_config(nvme_root_t r, const char *config_file)
errno = ENOMEM;
return err;
}
+
+ tmp = errno;
err = json_read_config(r, config_file);
/*
* The json configuration file is optional,
* so ignore errors when opening the file.
*/
- if (err < 0 && errno != EPROTO)
- err = 0;
+ if (err < 0 && errno != EPROTO) {
+ errno = tmp;
+ return 0;
+ }
return err;
}
@@ -270,6 +369,11 @@ void nvme_root_set_application(nvme_root_t r, const char *a)
r->application = strdup(a);
}
+void nvme_root_skip_namespaces(nvme_root_t r)
+{
+ r->create_only = true;
+}
+
nvme_host_t nvme_first_host(nvme_root_t r)
{
return list_top(&r->hosts, struct nvme_host, entry);
@@ -361,14 +465,17 @@ void nvme_free_tree(nvme_root_t r)
{
struct nvme_host *h, *_h;
- free(r->options);
+ if (!r)
+ return;
+
+ if (r->options)
+ free(r->options);
nvme_for_each_host_safe(r, h, _h)
__nvme_free_host(h);
if (r->config_file)
free(r->config_file);
if (r->application)
free(r->application);
- nvme_set_root(NULL);
free(r);
}
@@ -538,7 +645,7 @@ struct nvme_subsystem *nvme_alloc_subsystem(struct nvme_host *h,
list_head_init(&s->ctrls);
list_head_init(&s->namespaces);
list_node_init(&s->entry);
- list_add(&h->subsystems, &s->entry);
+ list_add_tail(&h->subsystems, &s->entry);
h->r->modified = true;
return s;
}
@@ -622,7 +729,7 @@ struct nvme_host *nvme_lookup_host(nvme_root_t r, const char *hostnqn,
list_head_init(&h->subsystems);
list_node_init(&h->entry);
h->r = r;
- list_add(&r->hosts, &h->entry);
+ list_add_tail(&r->hosts, &h->entry);
r->modified = true;
return h;
@@ -634,6 +741,12 @@ static int nvme_subsystem_scan_namespaces(nvme_root_t r, nvme_subsystem_t s,
_cleanup_dirents_ struct dirents namespaces = {};
int i, ret;
+ if (r->create_only) {
+ nvme_msg(r, LOG_DEBUG,
+ "skipping namespace scan for subsys %s\n",
+ s->subsysnqn);
+ return 0;
+ }
namespaces.num = nvme_scan_subsystem_namespaces(s, &namespaces.ents);
if (namespaces.num < 0) {
nvme_msg(r, LOG_DEBUG,
@@ -806,7 +919,7 @@ static void nvme_subsystem_set_path_ns(nvme_subsystem_t s, nvme_path_t p)
sprintf(n_name, "nvme%dn%d", i, nsid);
nvme_subsystem_for_each_ns(s, n) {
if (!strcmp(n_name, nvme_ns_get_name(n))) {
- list_add(&n->paths, &p->nentry);
+ list_add_tail(&n->paths, &p->nentry);
p->n = n;
}
}
@@ -852,7 +965,7 @@ static int nvme_ctrl_scan_path(nvme_root_t r, struct nvme_ctrl *c, char *name)
list_node_init(&p->nentry);
nvme_subsystem_set_path_ns(c->s, p);
list_node_init(&p->entry);
- list_add(&c->paths, &p->entry);
+ list_add_tail(&c->paths, &p->entry);
return 0;
}
@@ -1591,8 +1704,8 @@ nvme_ctrl_t __nvme_lookup_ctrl(nvme_subsystem_t s, const char *transport,
const char *host_iface, const char *trsvcid,
const char *subsysnqn, nvme_ctrl_t p)
{
+ _cleanup_candidate_ struct candidate_args candidate = {};
struct nvme_ctrl *c, *matching_c = NULL;
- _cleanup_candidate_ struct candidate_args candidate;
ctrl_match_t ctrl_match;
/* Init candidate and get the matching function to use */
@@ -1615,8 +1728,8 @@ bool nvme_ctrl_config_match(struct nvme_ctrl *c, const char *transport,
const char *subsysnqn, const char *host_traddr,
const char *host_iface)
{
+ _cleanup_candidate_ struct candidate_args candidate = {};
ctrl_match_t ctrl_match;
- _cleanup_candidate_ struct candidate_args candidate;
/* Init candidate and get the matching function to use */
ctrl_match = _candidate_init(&candidate, transport, traddr, trsvcid,
@@ -1655,7 +1768,7 @@ nvme_ctrl_t nvme_lookup_ctrl(nvme_subsystem_t s, const char *transport,
host_traddr, host_iface, trsvcid);
if (c) {
c->s = s;
- list_add(&s->ctrls, &c->entry);
+ list_add_tail(&s->ctrls, &c->entry);
s->h->r->modified = true;
}
return c;
@@ -1666,6 +1779,11 @@ static int nvme_ctrl_scan_paths(nvme_root_t r, struct nvme_ctrl *c)
_cleanup_dirents_ struct dirents paths = {};
int i;
+ if (r->create_only) {
+ nvme_msg(r, LOG_DEBUG,
+ "skipping path scan for ctrl %s\n", c->name);
+ return 0;
+ }
paths.num = nvme_scan_ctrl_namespace_paths(c, &paths.ents);
if (paths.num < 0)
return paths.num;
@@ -1681,6 +1799,11 @@ static int nvme_ctrl_scan_namespaces(nvme_root_t r, struct nvme_ctrl *c)
_cleanup_dirents_ struct dirents namespaces = {};
int i;
+ if (r->create_only) {
+ nvme_msg(r, LOG_DEBUG, "skipping namespace scan for ctrl %s\n",
+ c->name);
+ return 0;
+ }
namespaces.num = nvme_scan_ctrl_namespaces(c, &namespaces.ents);
for (i = 0; i < namespaces.num; i++)
nvme_ctrl_scan_namespace(r, c, namespaces.ents[i]->d_name);
@@ -1749,6 +1872,10 @@ static char *nvme_ctrl_lookup_phy_slot(nvme_root_t r, const char *address)
return NULL;
}
addr = nvme_get_attr(path, "address");
+
+ /* some directories don't have an address entry */
+ if (!addr)
+ continue;
if (strcmp(addr, target_addr) == 0)
return strdup(entry->d_name);
}
@@ -1861,7 +1988,7 @@ int nvme_init_ctrl(nvme_host_t h, nvme_ctrl_t c, int instance)
if (s->subsystype && !strcmp(s->subsystype, "discovery"))
c->discovery_ctrl = true;
c->s = s;
- list_add(&s->ctrls, &c->entry);
+ list_add_tail(&s->ctrls, &c->entry);
return ret;
}
@@ -2635,7 +2762,7 @@ static int nvme_ctrl_scan_namespace(nvme_root_t r, struct nvme_ctrl *c,
}
n->s = c->s;
n->c = c;
- list_add(&c->namespaces, &n->entry);
+ list_add_tail(&c->namespaces, &n->entry);
return 0;
}
@@ -2658,7 +2785,7 @@ static void nvme_subsystem_set_ns_path(nvme_subsystem_t s, nvme_ns_t n)
if (ret != 3)
continue;
if (ns_ctrl == p_subsys && ns_nsid == p_nsid) {
- list_add(&n->paths, &p->nentry);
+ list_add_tail(&n->paths, &p->nentry);
p->n = n;
}
}
@@ -2696,7 +2823,7 @@ static int nvme_subsystem_scan_namespace(nvme_root_t r, nvme_subsystem_t s,
__nvme_free_ns(_n);
}
n->s = s;
- list_add(&s->namespaces, &n->entry);
+ list_add_tail(&s->namespaces, &n->entry);
nvme_subsystem_set_ns_path(s, n);
return 0;
}