Make more things static helps reduce what exports need to be tracked.
Signed-off-by: Keith Busch <kbusch@kernel.org>
#define NVMF_HOSTID_SIZE 36
+const char *conarg_nqn = "nqn";
+const char *conarg_transport = "transport";
+const char *conarg_traddr = "traddr";
+const char *conarg_trsvcid = "trsvcid";
+const char *conarg_host_traddr = "host_traddr";
+
static struct config {
char *nqn;
char *transport;
bool quiet;
} cfg = { NULL };
+struct connect_args {
+ char *subsysnqn;
+ char *transport;
+ char *traddr;
+ char *trsvcid;
+ char *host_traddr;
+};
+
#define BUF_SIZE 4096
#define PATH_NVME_FABRICS "/dev/nvme-fabrics"
#define PATH_NVMF_DISC "/etc/nvme/discovery.conf"
* If field found, return string containing field value. If field
* not found, return an empty string.
*/
-char *__parse_connect_arg(char *conargs, const char delim, const char *fieldnm)
+static char *parse_conn_arg(char *conargs, const char delim, const char *field)
{
char *s, *e;
size_t cnt;
* However, better to be prepared.
*/
do {
- s = strstr(conargs, fieldnm);
+ s = strstr(conargs, field);
if (!s)
goto empty_field;
/* validate prior character is delimiter */
if (s == conargs || *(s - 1) == delim) {
/* match requires next character to be assignment */
- s += strlen(fieldnm);
+ s += strlen(field);
if (*s == '=')
/* match */
break;
return instance;
}
+/*
+ * Given a controller name, create a connect_args with its
+ * attributes and compare the attributes against the connect args
+ * given.
+ * Return true/false based on whether it matches
+ */
+static bool ctrl_matches_connectargs(char *name, struct connect_args *args)
+{
+ struct connect_args cargs;
+ bool found = false;
+ char *path, *addr;
+ int ret;
+
+ ret = asprintf(&path, "%s/%s", SYS_NVME, name);
+ if (ret < 0)
+ return found;
+
+ addr = nvme_get_ctrl_attr(path, "address");
+ cargs.subsysnqn = nvme_get_ctrl_attr(path, "subsysnqn");
+ cargs.transport = nvme_get_ctrl_attr(path, "transport");
+ cargs.traddr = parse_conn_arg(addr, ' ', conarg_traddr);
+ cargs.trsvcid = parse_conn_arg(addr, ' ', conarg_trsvcid);
+ cargs.host_traddr = parse_conn_arg(addr, ' ', conarg_host_traddr);
+
+ if (!strcmp(cargs.subsysnqn, args->subsysnqn) &&
+ !strcmp(cargs.transport, args->transport) &&
+ (!strcmp(cargs.traddr, args->traddr) ||
+ !strcmp(args->traddr, "none")) &&
+ (!strcmp(cargs.trsvcid, args->trsvcid) ||
+ !strcmp(args->trsvcid, "none")) &&
+ (!strcmp(cargs.host_traddr, args->host_traddr) ||
+ !strcmp(args->host_traddr, "none")))
+ found = true;
+
+ free(cargs.subsysnqn);
+ free(cargs.transport);
+ free(cargs.traddr);
+ free(cargs.trsvcid);
+ free(cargs.host_traddr);
+
+ return found;
+}
+
+/*
+ * Look through the system to find an existing controller whose
+ * attributes match the connect arguments specified
+ * If found, a string containing the controller name (ex: "nvme?")
+ * is returned.
+ * If not found, a NULL is returned.
+ */
+static char *find_ctrl_with_connectargs(struct connect_args *args)
+{
+ struct dirent **devices;
+ char *devname = NULL;
+ int i, n;
+
+ n = scandir(SYS_NVME, &devices, scan_ctrls_filter, alphasort);
+ if (n < 0) {
+ fprintf(stderr, "no NVMe controller(s) detected.\n");
+ return NULL;
+ }
+
+ for (i = 0; i < n; i++) {
+ if (ctrl_matches_connectargs(devices[i]->d_name, args)) {
+ devname = strdup(devices[i]->d_name);
+ if (devname == NULL)
+ fprintf(stderr, "no memory for ctrl name %s\n",
+ devices[i]->d_name);
+ goto cleanup_devices;
+ }
+ }
+
+cleanup_devices:
+ for (i = 0; i < n; i++)
+ free(devices[i]);
+ free(devices);
+
+ return devname;
+}
+
static int add_ctrl(const char *argstr)
{
substring_t args[MAX_OPT_ARGS];
return ret;
}
-static const char delim_comma = ',';
-
static int do_discover(char *argstr, bool connect)
{
struct nvmf_disc_rsp_page_hdr *log = NULL;
struct connect_args cargs;
memset(&cargs, 0, sizeof(cargs));
- cargs.subsysnqn = __parse_connect_arg(argstr, delim_comma,
- conarg_nqn);
- cargs.transport = __parse_connect_arg(argstr, delim_comma,
- conarg_transport);
- cargs.traddr = __parse_connect_arg(argstr, delim_comma,
- conarg_traddr);
- cargs.trsvcid = __parse_connect_arg(argstr, delim_comma,
- conarg_trsvcid);
- cargs.host_traddr = __parse_connect_arg(argstr, delim_comma,
- conarg_host_traddr);
+ cargs.subsysnqn = parse_conn_arg(argstr, '.', conarg_nqn);
+ cargs.transport = parse_conn_arg(argstr, '.', conarg_transport);
+ cargs.traddr = parse_conn_arg(argstr, '.', conarg_traddr);
+ cargs.trsvcid = parse_conn_arg(argstr, '.', conarg_trsvcid);
+ cargs.host_traddr = parse_conn_arg(argstr, '.', conarg_host_traddr);
/*
* if the cfg.device passed in matches the connect args
int disconnect_all(const char *desc, int argc, char **argv)
{
- struct subsys_list_item *slist;
- int i, j, ret, subcnt = 0;
+ struct nvme_topology t = { };
+ int i, j, err;
OPT_ARGS(opts) = {
OPT_END()
};
- ret = argconfig_parse(argc, argv, desc, opts);
- if (ret)
+ err = argconfig_parse(argc, argv, desc, opts);
+ if (err)
+ goto out;
+
+ err = scan_subsystems(&t, NULL, 0);
+ if (err) {
+ fprintf(stderr, "Failed to scan namespaces\n");
goto out;
+ }
- slist = get_subsys_list(&subcnt, NULL, NVME_NSID_ALL);
- for (i = 0; i < subcnt; i++) {
- struct subsys_list_item *subsys = &slist[i];
+ for (i = 0; i < t.nr_subsystems; i++) {
+ struct nvme_subsystem *s = &t.subsystems[i];
- for (j = 0; j < subsys->nctrls; j++) {
- struct ctrl_list_item *ctrl = &subsys->ctrls[j];
- if (!strcmp(ctrl->transport, "pcie"))
- continue;
+ for (j = 0; j < s->nr_ctrls; j++) {
+ struct nvme_ctrl *c = &s->ctrls[j];
- ret = disconnect_by_device(ctrl->name);
- if (ret)
+ if (!strcmp(c->transport, "pcie"))
+ continue;
+ err = disconnect_by_device(c->name);
+ if (err)
goto free;
}
}
-
free:
- free_subsys_list(slist, subcnt);
+ free_topology(&t);
out:
- return nvme_status_to_errno(ret, true);
+ return nvme_status_to_errno(err, true);
}
} uuid_t;
#endif
+#ifdef __CHECKER__
+#define __force __attribute__((force))
+#else
+#define __force
+#endif
+
+static inline __le16 cpu_to_le16(uint16_t x)
+{
+ return (__force __le16)htole16(x);
+}
+static inline __le32 cpu_to_le32(uint32_t x)
+{
+ return (__force __le32)htole32(x);
+}
+static inline __le64 cpu_to_le64(uint64_t x)
+{
+ return (__force __le64)htole64(x);
+}
+
+static inline uint16_t le16_to_cpu(__le16 x)
+{
+ return le16toh((__force __u16)x);
+}
+static inline uint32_t le32_to_cpu(__le32 x)
+{
+ return le32toh((__force __u32)x);
+}
+static inline uint64_t le64_to_cpu(__le64 x)
+{
+ return le64toh((__force __u64)x);
+}
/* NQN names in commands fields specified one size */
#define NVMF_NQN_FIELD_LEN 256
return false;
}
-#ifdef __CHECKER__
-#define __force __attribute__((force))
-#else
-#define __force
-#endif
-
-static inline __le16 cpu_to_le16(uint16_t x)
-{
- return (__force __le16)htole16(x);
-}
-static inline __le32 cpu_to_le32(uint32_t x)
-{
- return (__force __le32)htole32(x);
-}
-static inline __le64 cpu_to_le64(uint64_t x)
-{
- return (__force __le64)htole64(x);
-}
-
-static inline uint16_t le16_to_cpu(__le16 x)
-{
- return le16toh((__force __u16)x);
-}
-static inline uint32_t le32_to_cpu(__le32 x)
-{
- return le32toh((__force __u32)x);
-}
-static inline uint64_t le64_to_cpu(__le64 x)
-{
- return le64toh((__force __u64)x);
-}
-
enum {
NVME_SCT_GENERIC = 0x0,
NVME_SCT_CMD_SPECIFIC = 0x1,
json_free_object(root);
}
-static void nvme_show_subsystem(struct subsys_list_item *item)
+static void nvme_show_subsystem(struct nvme_subsystem *s)
{
int i;
- printf("%s - NQN=%s\n", item->name, item->subsysnqn);
+ printf("%s - NQN=%s\n", s->name, s->subsysnqn);
printf("\\\n");
- for (i = 0; i < item->nctrls; i++) {
- printf(" +- %s %s %s %s %s\n", item->ctrls[i].name,
- item->ctrls[i].transport,
- item->ctrls[i].address,
- item->ctrls[i].state,
- item->ctrls[i].ana_state ?
- item->ctrls[i].ana_state : "");
+ for (i = 0; i < s->nr_ctrls; i++) {
+ printf(" +- %s %s %s %s %s\n", s->ctrls[i].name,
+ s->ctrls[i].transport,
+ s->ctrls[i].address,
+ s->ctrls[i].state,
+ s->ctrls[i].ana_state ? : "");
}
}
-static void json_print_nvme_subsystem_list(struct subsys_list_item *slist,
- int n)
+static void json_print_nvme_subsystem_list(struct nvme_topology *t)
{
+ struct json_object *subsystem_attrs, *path_attrs;
+ struct json_array *subsystems, *paths;
struct json_object *root;
- struct json_array *subsystems;
- struct json_object *subsystem_attrs;
- struct json_array *paths;
- struct json_object *path_attrs;
int i, j;
root = json_create_object();
subsystems = json_create_array();
- for (i = 0; i < n; i++) {
- subsystem_attrs = json_create_object();
+ for (i = 0; i < t->nr_subsystems; i++) {
+ struct nvme_subsystem *s = &t->subsystems[i];
+ subsystem_attrs = json_create_object();
json_object_add_value_string(subsystem_attrs,
- "Name", slist[i].name);
+ "Name", s->name);
json_object_add_value_string(subsystem_attrs,
- "NQN", slist[i].subsysnqn);
+ "NQN", s->subsysnqn);
json_array_add_value_object(subsystems, subsystem_attrs);
paths = json_create_array();
+ for (j = 0; j < s->nr_ctrls; j++) {
+ struct nvme_ctrl *c = &s->ctrls[j];
- for (j = 0; j < slist[i].nctrls; j++) {
path_attrs = json_create_object();
json_object_add_value_string(path_attrs, "Name",
- slist[i].ctrls[j].name);
+ c->name);
json_object_add_value_string(path_attrs, "Transport",
- slist[i].ctrls[j].transport);
+ c->transport);
json_object_add_value_string(path_attrs, "Address",
- slist[i].ctrls[j].address);
+ c->address);
json_object_add_value_string(path_attrs, "State",
- slist[i].ctrls[j].state);
- if (slist[i].ctrls[j].ana_state)
+ c->state);
+ if (c->ana_state)
json_object_add_value_string(path_attrs,
- "ANAState",
- slist[i].ctrls[j].ana_state);
+ "ANAState", c->ana_state);
json_array_add_value_object(paths, path_attrs);
}
if (j)
json_free_object(root);
}
-void nvme_show_subsystem_list(struct subsys_list_item *slist, int n,
- enum nvme_print_flags flags)
+void nvme_show_subsystem_list(struct nvme_topology *t,
+ enum nvme_print_flags flags)
{
int i;
if (flags & JSON)
- return json_print_nvme_subsystem_list(slist, n);
+ return json_print_nvme_subsystem_list(t);
- for (i = 0; i < n; i++)
- nvme_show_subsystem(&slist[i]);
+ for (i = 0; i < t->nr_subsystems; i++)
+ nvme_show_subsystem(&t->subsystems[i]);
}
static void nvme_show_registers_cap(struct nvme_bar_cap *cap)
return;
if (block) {
+ struct nvme_topology t = { };
char *subsysnqn;
- struct subsys_list_item *slist;
- int subcnt = 0;
+ int err;
subsysnqn = get_nvme_subsnqn(path);
- if (!subsysnqn)
+ if (!subsysnqn) {
+ free(path);
return;
- slist = get_subsys_list(&subcnt, subsysnqn, nsid);
- if (subcnt != 1) {
+ }
+ err = scan_subsystems(&t, subsysnqn, 0);
+ if (err || t.nr_subsystems != 1) {
free(subsysnqn);
free(path);
return;
}
fprintf(stderr, "Namespace %s has parent controller(s):", name);
- for (i = 0; i < slist[0].nctrls; i++)
+ for (i = 0; i < t.subsystems[0].nr_ctrls; i++)
fprintf(stderr, "%s%s", i ? ", " : "",
- slist[0].ctrls[i].name);
+ t.subsystems[0].ctrls[i].name);
fprintf(stderr, "\n\n");
free(subsysnqn);
+ free_topology(&t);
} else {
struct dirent **paths;
bool comma = false;
void nvme_show_lba_status(struct nvme_lba_status *list, unsigned long len,
enum nvme_print_flags flags);
void nvme_show_list_items(struct nvme_topology *t, enum nvme_print_flags flags);
-void nvme_show_subsystem_list(struct subsys_list_item *slist, int n,
- enum nvme_print_flags flags);
+void nvme_show_subsystem_list(struct nvme_topology *t,
+ enum nvme_print_flags flags);
void nvme_show_id_nvmset(struct nvme_id_nvmset *nvmset, unsigned nvmset_id,
enum nvme_print_flags flags);
void nvme_show_list_secondary_ctrl(const struct nvme_secondary_controllers_list *sc_list,
#include "nvme.h"
#include "nvme-ioctl.h"
-static const char delim_space = ' ';
-
-int get_nsid(int fd)
-{
- int nsid = nvme_get_nsid(fd);
-
- if (nsid <= 0) {
- fprintf(stderr,
- "%s: failed to return namespace id\n",
- devicename);
- }
- return nsid < 0 ? 0 : nsid;
-}
+static const char *dev = "/dev/";
+static const char *subsys_dir = "/sys/class/nvme-subsystem/";
char *get_nvme_subsnqn(char *path)
{
- char sspath[320];
- char *subsysnqn;
- int fd;
- int ret;
+ char sspath[320], *subsysnqn;
+ int fd, ret;
snprintf(sspath, sizeof(sspath), "%s/subsysnqn", path);
close_fd:
close(fd);
-
return subsysnqn;
}
-char *get_nvme_ctrl_attr(char *path, const char *attr)
+char *nvme_get_ctrl_attr(char *path, const char *attr)
{
- char *attrpath;
- char *value;
- int fd;
+ char *attrpath, *value;
ssize_t ret;
- int i;
+ int fd, i;
ret = asprintf(&attrpath, "%s/%s", path, attr);
if (ret < 0)
close(fd);
free(attrpath);
-
return value;
-
err_close_fd:
close(fd);
err_free_value:
free(value);
err_free_path:
free(attrpath);
-
return NULL;
}
if (fd < 0)
goto free;
- n->nsid = get_nsid(fd);
+ n->nsid = nvme_get_nsid(fd);
+ if (n->nsid < 0)
+ goto close_fd;
+
ret = nvme_identify_ns(fd, n->nsid, 0, &n->ns);
if (ret < 0)
goto close_fd;
return 0;
}
-static int scan_ctrl(struct nvme_ctrl *c, char *p)
+static char *get_nvme_ctrl_path_ana_state(char *path, int nsid)
+{
+ struct dirent **paths;
+ char *ana_state;
+ int i, n;
+
+ ana_state = calloc(1, 16);
+ if (!ana_state)
+ return NULL;
+
+ n = scandir(path, &paths, scan_ctrl_paths_filter, alphasort);
+ if (n <= 0) {
+ free(ana_state);
+ return NULL;
+ }
+ for (i = 0; i < n; i++) {
+ int id, cntlid, ns, fd;
+ char *ctrl_path;
+ ssize_t ret;
+
+ if (sscanf(paths[i]->d_name, "nvme%dc%dn%d",
+ &id, &cntlid, &ns) != 3) {
+ if (sscanf(paths[i]->d_name, "nvme%dn%d",
+ &id, &ns) != 2) {
+ continue;
+ }
+ }
+ if (ns != nsid)
+ continue;
+
+ ret = asprintf(&ctrl_path, "%s/%s/ana_state",
+ path, paths[i]->d_name);
+ if (ret < 0) {
+ free(ana_state);
+ ana_state = NULL;
+ break;
+ }
+ fd = open(ctrl_path, O_RDONLY);
+ if (fd < 0) {
+ free(ctrl_path);
+ free(ana_state);
+ ana_state = NULL;
+ break;
+ }
+ ret = read(fd, ana_state, 16);
+ if (ret < 0) {
+ fprintf(stderr, "Failed to read ANA state from %s\n",
+ ctrl_path);
+ free(ana_state);
+ ana_state = NULL;
+ } else if (ana_state[strlen(ana_state) - 1] == '\n')
+ ana_state[strlen(ana_state) - 1] = '\0';
+ close(fd);
+ free(ctrl_path);
+ break;
+ }
+ for (i = 0; i < n; i++)
+ free(paths[i]);
+ free(paths);
+ return ana_state;
+}
+
+static int scan_ctrl(struct nvme_ctrl *c, char *p, __u32 ns_instance)
{
struct nvme_namespace *n;
struct dirent **ns;
if (ret < 0)
return ret;
- c->address = get_nvme_ctrl_attr(path, "address");
- c->transport = get_nvme_ctrl_attr(path, "transport");
- c->state = get_nvme_ctrl_attr(path, "state");
+ c->address = nvme_get_ctrl_attr(path, "address");
+ c->transport = nvme_get_ctrl_attr(path, "transport");
+ c->state = nvme_get_ctrl_attr(path, "state");
+
+ if (ns_instance)
+ c->ana_state = get_nvme_ctrl_path_ana_state(path, ns_instance);
ret = scandir(path, &ns, scan_namespace_filter, alphasort);
if (ret == -1) {
return 0;
}
-static int scan_subsystem(struct nvme_subsystem *s)
+static int scan_subsystem(struct nvme_subsystem *s, __u32 ns_instance)
{
struct dirent **ctrls, **ns;
struct nvme_namespace *n;
c = &s->ctrls[i];
c->name = strdup(ctrls[i]->d_name);
c->subsys = s;
- scan_ctrl(c, path);
+ scan_ctrl(c, path, ns_instance);
}
while (i--)
return ret;
}
-int scan_subsystems(struct nvme_topology *t)
+static void free_ctrl(struct nvme_ctrl *c)
+{
+ int i;
+
+ for (i = 0; i < c->nr_namespaces; i++) {
+ struct nvme_namespace *n = &c->namespaces[i];
+ free(n->name);
+ }
+ free(c->name);
+ free(c->transport);
+ free(c->address);
+ free(c->state);
+ free(c->ana_state);
+ free(c->namespaces);
+}
+
+static void free_subsystem(struct nvme_subsystem *s)
+{
+ int i;
+
+ for (i = 0; i < s->nr_ctrls; i++)
+ free_ctrl(&s->ctrls[i]);
+ for (i = 0; i < s->nr_namespaces; i++) {
+ struct nvme_namespace *n = &s->namespaces[i];
+ free(n->name);
+ }
+ free(s->name);
+ free(s->subsysnqn);
+ free(s->ctrls);
+ free(s->namespaces);
+}
+
+int scan_subsystems(struct nvme_topology *t, const char *subsysnqn,
+ __u32 ns_instance)
{
struct nvme_subsystem *s;
struct dirent **subsys;
- int i;
+ int i, j = 0;
- t->nr_subsystems = scandir(subsys_dir, &subsys, scan_subsys_filter, alphasort);
+ t->nr_subsystems = scandir(subsys_dir, &subsys, scan_subsys_filter,
+ alphasort);
if (t->nr_subsystems < 0)
return legacy_list(t);
t->subsystems = calloc(t->nr_subsystems, sizeof(*s));
for (i = 0; i < t->nr_subsystems; i++) {
- s = &t->subsystems[i];
+ s = &t->subsystems[j];
s->name = strdup(subsys[i]->d_name);
- scan_subsystem(s);
+ scan_subsystem(s, ns_instance);
+
+ if (!subsysnqn || !strcmp(s->subsysnqn, subsysnqn))
+ j++;
+ else
+ free_subsystem(s);
}
+ t->nr_subsystems = j;
while (i--)
free(subsys[i]);
}
void free_topology(struct nvme_topology *t)
-{
- int i, j, k;
-
- for (i = 0; i < t->nr_subsystems; i++) {
- struct nvme_subsystem *s = &t->subsystems[i];
-
- for (j = 0; j < s->nr_ctrls; j++) {
- struct nvme_ctrl *c = &s->ctrls[j];
-
- for (k = 0; k < c->nr_namespaces; k++) {
- struct nvme_namespace *n = &c->namespaces[k];
- free(n->name);
- }
- free(c->name);
- if (c->transport)
- free(c->transport);
- if (c->address)
- free(c->address);
- if (c->state)
- free(c->state);
- if (c->namespaces)
- free(c->namespaces);
- }
- free(s->name);
- free(s->subsysnqn);
- free(s->ctrls);
- free(s->namespaces);
- }
- free(t->subsystems);
-}
-
-static char *get_nvme_ctrl_path_ana_state(char *path, int nsid)
-{
- struct dirent **paths;
- char *ana_state;
- int i, n;
-
- ana_state = calloc(1, 16);
- if (!ana_state)
- return NULL;
-
- n = scandir(path, &paths, scan_ctrl_paths_filter, alphasort);
- if (n <= 0) {
- free(ana_state);
- return NULL;
- }
- for (i = 0; i < n; i++) {
- int id, cntlid, ns, fd;
- ssize_t ret;
- char *ctrl_path;
-
- if (sscanf(paths[i]->d_name, "nvme%dc%dn%d",
- &id, &cntlid, &ns) != 3) {
- if (sscanf(paths[i]->d_name, "nvme%dn%d",
- &id, &ns) != 2) {
- continue;
- }
- }
- if (ns != nsid)
- continue;
-
- ret = asprintf(&ctrl_path, "%s/%s/ana_state",
- path, paths[i]->d_name);
- if (ret < 0) {
- free(ana_state);
- ana_state = NULL;
- break;
- }
- fd = open(ctrl_path, O_RDONLY);
- if (fd < 0) {
- free(ctrl_path);
- free(ana_state);
- ana_state = NULL;
- break;
- }
- ret = read(fd, ana_state, 16);
- if (ret < 0) {
- fprintf(stderr, "Failed to read ANA state from %s\n",
- ctrl_path);
- free(ana_state);
- ana_state = NULL;
- } else if (ana_state[strlen(ana_state) - 1] == '\n')
- ana_state[strlen(ana_state) - 1] = '\0';
- close(fd);
- free(ctrl_path);
- break;
- }
- for (i = 0; i < n; i++)
- free(paths[i]);
- free(paths);
- return ana_state;
-}
-
-void free_ctrl_list_item(struct ctrl_list_item *ctrls)
-{
- free(ctrls->name);
- free(ctrls->transport);
- free(ctrls->address);
- free(ctrls->state);
- free(ctrls->ana_state);
- free(ctrls->subsysnqn);
- free(ctrls->traddr);
- free(ctrls->trsvcid);
- free(ctrls->host_traddr);
-}
-
-int get_nvme_ctrl_info(char *name, char *path, struct ctrl_list_item *ctrl,
- __u32 nsid)
-{
- char ctrl_path[512];
-
- ctrl->name = strdup(name);
-
- snprintf(ctrl_path, sizeof(ctrl_path), "%s/%s", path, ctrl->name);
-
- ctrl->address = get_nvme_ctrl_attr(ctrl_path, "address");
- if (!ctrl->address) {
- fprintf(stderr, "%s: failed to get controller address.\n",
- ctrl->name);
- goto free_ctrl_items;
- }
-
- ctrl->transport = get_nvme_ctrl_attr(ctrl_path, "transport");
- if (!ctrl->transport) {
- fprintf(stderr, "%s: failed to get controller transport.\n",
- ctrl->name);
- goto free_ctrl_items;
- }
-
- ctrl->state = get_nvme_ctrl_attr(ctrl_path, "state");
- if (!ctrl->state) {
- fprintf(stderr, "%s: failed to get controller state.\n",
- ctrl->name);
- goto free_ctrl_items;
- }
-
- if (nsid != NVME_NSID_ALL)
- ctrl->ana_state = get_nvme_ctrl_path_ana_state(ctrl_path, nsid);
-
- ctrl->subsysnqn = get_nvme_ctrl_attr(ctrl_path, "subsysnqn");
- if (!ctrl->subsysnqn) {
- fprintf(stderr, "%s: failed to get controller subsysnqn.\n",
- ctrl->name);
- goto free_ctrl_items;
- }
-
- ctrl->traddr = __parse_connect_arg(ctrl->address, delim_space,
- conarg_traddr);
- ctrl->trsvcid = __parse_connect_arg(ctrl->address, delim_space,
- conarg_trsvcid);
- ctrl->host_traddr = __parse_connect_arg(ctrl->address, delim_space,
- conarg_host_traddr);
-
- return 0; /* success */
-
-free_ctrl_items:
- free_ctrl_list_item(ctrl);
-
- return 1; /* failure */
-}
-
-static int get_nvme_subsystem_info(char *name, char *path,
- struct subsys_list_item *item, __u32 nsid)
-{
- struct dirent **ctrls;
- int n, i, ret = 1, ccnt = 0;
-
- item->subsysnqn = get_nvme_subsnqn(path);
- if (!item->subsysnqn) {
- fprintf(stderr, "failed to get subsystem nqn.\n");
- return ret;
- }
-
- item->name = strdup(name);
-
- n = scandir(path, &ctrls, scan_ctrls_filter, alphasort);
- if (n < 0) {
- fprintf(stderr, "failed to scan controller(s).\n");
- return ret;
- }
-
- item->ctrls = calloc(n, sizeof(struct ctrl_list_item));
- if (!item->ctrls) {
- fprintf(stderr, "failed to allocate subsystem controller(s)\n");
- goto free_ctrls;
- }
-
- item->nctrls = n;
-
- for (i = 0; i < n; i++) {
- if (get_nvme_ctrl_info(ctrls[i]->d_name, path,
- &item->ctrls[ccnt], nsid)) {
- fprintf(stderr, "failed to get controller[%d] info.\n",
- i);
- }
- ccnt++;
- }
-
- item->nctrls = ccnt;
-
- ret = 0;
-
-free_ctrls:
- for (i = 0; i < n; i++)
- free(ctrls[i]);
- free(ctrls);
-
- return ret;
-
-}
-
-static void free_subsys_list_item(struct subsys_list_item *item)
{
int i;
- for (i = 0; i < item->nctrls; i++)
- free_ctrl_list_item(&item->ctrls[i]);
-
- free(item->ctrls);
- free(item->subsysnqn);
- free(item->name);
-}
-
-void free_subsys_list(struct subsys_list_item *slist, int n)
-{
- int i;
-
- for (i = 0; i < n; i++)
- free_subsys_list_item(&slist[i]);
-
- free(slist);
-}
-
-struct subsys_list_item *get_subsys_list(int *subcnt, char *subsysnqn,
- __u32 nsid)
-{
- char path[310];
- struct dirent **subsys;
- struct subsys_list_item *slist;
- int n, i, ret = 0;
-
- n = scandir(subsys_dir, &subsys, scan_subsys_filter, alphasort);
- if (n < 0) {
- fprintf(stderr, "no NVMe subsystem(s) detected.\n");
- return NULL;
- }
-
- slist = calloc(n, sizeof(struct subsys_list_item));
- if (!slist)
- goto free_subsys;
-
- for (i = 0; i < n; i++) {
- snprintf(path, sizeof(path), "%s%s", subsys_dir,
- subsys[i]->d_name);
- ret = get_nvme_subsystem_info(subsys[i]->d_name, path,
- &slist[*subcnt], nsid);
- if (ret) {
- fprintf(stderr,
- "%s: failed to get subsystem info: %s\n",
- path, strerror(errno));
- free_subsys_list_item(&slist[*subcnt]);
- } else if (subsysnqn &&
- strncmp(slist[*subcnt].subsysnqn, subsysnqn, 255))
- free_subsys_list_item(&slist[*subcnt]);
- else
- (*subcnt)++;
- }
-
-free_subsys:
- for (i = 0; i < n; i++)
- free(subsys[i]);
- free(subsys);
-
- return slist;
+ for (i = 0; i < t->nr_subsystems; i++)
+ free_subsystem(&t->subsystems[i]);
+ free(t->subsystems);
}
char *nvme_char_from_block(char *dev)
#include "argconfig.h"
#include "fabrics.h"
+#define CREATE_CMD
+#include "nvme-builtin.h"
+
static struct stat nvme_stat;
const char *devicename;
static const char nvme_version_string[] = NVME_VERSION;
-#define CREATE_CMD
-#include "nvme-builtin.h"
-
static struct plugin builtin = {
.commands = commands,
.name = NULL,
.extensions = &builtin,
};
-
static const char *output_format = "Output format: normal|json|binary";
static const char *output_format_no_binary = "Output format: normal|json";
-const char *conarg_nqn = "nqn";
-const char *conarg_transport = "transport";
-const char *conarg_traddr = "traddr";
-const char *conarg_trsvcid = "trsvcid";
-const char *conarg_host_traddr = "host_traddr";
-const char *dev = "/dev/";
-const char *subsys_dir = "/sys/class/nvme-subsystem/";
-
static void *__nvme_alloc(size_t len, bool *huge)
{
void *p;
goto ret;
if (S_ISBLK(nvme_stat.st_mode)) {
- cfg.namespace_id = get_nsid(fd);
- if (cfg.namespace_id == 0) {
- err = -EINVAL;
+ cfg.namespace_id = nvme_get_nsid(fd);
+ if (cfg.namespace_id < 0) {
+ err = cfg.namespace_id;
goto close_fd;
}
} else if (!cfg.namespace_id) {
static int list_subsys(int argc, char **argv, struct command *cmd,
struct plugin *plugin)
{
- struct subsys_list_item *slist;
+ struct nvme_topology t = { };
enum nvme_print_flags flags;
- int err, subcnt = 0;
char *subsysnqn = NULL;
const char *desc = "Retrieve information for subsystems";
- __u32 namespace_id;
+ const char *verbose = "Increase output verbosity";
+ __u32 ns_instance = 0;
+ int err;
struct config {
char *output_format;
+ int verbose;
};
struct config cfg = {
.output_format = "normal",
+ .verbose = 0,
};
OPT_ARGS(opts) = {
- OPT_FMT("output-format", 'o', &cfg.output_format, "Output Format: normal|json"),
+ OPT_FMT("output-format", 'o', &cfg.output_format, output_format_no_binary),
+ OPT_FLAG("verbose", 'v', &cfg.verbose, verbose),
OPT_END()
};
int id;
devicename = basename(argv[optind]);
- if (sscanf(devicename, "nvme%dn%d", &id, &namespace_id) != 2) {
+ if (sscanf(devicename, "nvme%dn%d", &id, &ns_instance) != 2) {
fprintf(stderr, "%s is not a NVMe namespace device\n",
argv[optind]);
err = -EINVAL;
err = -EINVAL;
goto free;
}
+ if (cfg.verbose)
+ flags |= VERBOSE;
- slist = get_subsys_list(&subcnt, subsysnqn, namespace_id);
- nvme_show_subsystem_list(slist, subcnt, flags);
- free_subsys_list(slist, subcnt);
+ err = scan_subsystems(&t, subsysnqn, ns_instance);
+ if (err) {
+ fprintf(stderr, "Failed to scan namespaces\n");
+ goto free;
+ }
+ nvme_show_subsystem_list(&t, flags);
free:
+ free_topology(&t);
if (subsysnqn)
free(subsysnqn);
ret:
{
const char *desc = "Retrieve basic information for all NVMe namespaces";
const char *verbose = "Increase output verbosity";
- struct nvme_topology t;
+ struct nvme_topology t = { };
enum nvme_print_flags flags;
int err = 0;
if (cfg.verbose)
flags |= VERBOSE;
- err = scan_subsystems(&t);
+ err = scan_subsystems(&t, NULL, 0);
if (err) {
fprintf(stderr, "Failed to scan namespaces\n");
return err;
return 0;
}
-/*
- * Given a controller name, create a ctrl_list_item with its
- * attributes and compare the attributes against the connect args
- * given.
- * Return true/false based on whether it matches
- */
-bool ctrl_matches_connectargs(char *name, struct connect_args *args)
-{
- struct ctrl_list_item *ctrl;
- bool found = false;
-
- ctrl = malloc(sizeof(*ctrl));
- if (!ctrl) {
- fprintf(stderr, "Failed to allocate controller list element\n");
- return false;
- }
- memset(ctrl, 0, sizeof(*ctrl));
-
- if (get_nvme_ctrl_info(name, SYS_NVME, ctrl, NVME_NSID_ALL))
- goto cleanup_exit;
-
- if (!strcmp(ctrl->subsysnqn, args->subsysnqn) &&
- !strcmp(ctrl->transport, args->transport) &&
- (!strcmp(ctrl->traddr, args->traddr) ||
- !strcmp(args->traddr, "none")) &&
- (!strcmp(ctrl->trsvcid, args->trsvcid) ||
- !strcmp(args->trsvcid, "none")) &&
- (!strcmp(ctrl->host_traddr, args->host_traddr) ||
- !strcmp(args->host_traddr, "none")))
- found = true;
-
-cleanup_exit:
- free_ctrl_list_item(ctrl);
- free(ctrl);
-
- return found;
-}
-
-/*
- * Look through the system to find an existing controller whose
- * attributes match the connect arguments specified
- * If found, a string containing the controller name (ex: "nvme?")
- * is returned.
- * If not found, a NULL is returned.
- */
-char *find_ctrl_with_connectargs(struct connect_args *args)
-{
- struct dirent **devices;
- char *devname = NULL;
- int i, n;
-
- n = scandir(SYS_NVME, &devices, scan_ctrls_filter, alphasort);
- if (n < 0) {
- fprintf(stderr, "no NVMe controller(s) detected.\n");
- return NULL;
- }
-
- for (i = 0; i < n; i++) {
- if (ctrl_matches_connectargs(devices[i]->d_name, args)) {
- devname = strdup(devices[i]->d_name);
- if (devname == NULL)
- fprintf(stderr, "no memory for ctrl name %s\n",
- devices[i]->d_name);
- goto cleanup_devices;
- }
- }
-
-cleanup_devices:
- for (i = 0; i < n; i++)
- free(devices[i]);
- free(devices);
-
- return devname;
-}
-
int __id_ctrl(int argc, char **argv, struct command *cmd, struct plugin *plugin,
void (*vs)(__u8 *vs, struct json_object *root))
{
flags = BINARY;
if (!cfg.namespace_id) {
- cfg.namespace_id = get_nsid(fd);
- if (cfg.namespace_id == 0) {
- err = -EINVAL;
+ cfg.namespace_id = nvme_get_nsid(fd);
+ if (cfg.namespace_id < 0) {
+ err = cfg.namespace_id;
goto close_fd;
}
}
flags |= VERBOSE;
if (!cfg.namespace_id && S_ISBLK(nvme_stat.st_mode)) {
- cfg.namespace_id = get_nsid(fd);
- if (cfg.namespace_id == 0) {
- err = -EINVAL;
+ cfg.namespace_id = nvme_get_nsid(fd);
+ if (cfg.namespace_id < 0) {
+ err = cfg.namespace_id;
goto close_fd;
}
} else if (!cfg.namespace_id) {
*/
cfg.namespace_id = NVME_NSID_ALL;
} else if (S_ISBLK(nvme_stat.st_mode)) {
- cfg.namespace_id = get_nsid(fd);
- if (cfg.namespace_id == 0) {
- err = -EINVAL;
+ cfg.namespace_id = nvme_get_nsid(fd);
+ if (cfg.namespace_id < 0) {
+ err = cfg.namespace_id;
goto close_fd;
}
}
goto ret;
if (!cfg.namespace_id) {
- cfg.namespace_id = get_nsid(fd);
- if (cfg.namespace_id == 0) {
- err = -EINVAL;
+ cfg.namespace_id = nvme_get_nsid(fd);
+ if (cfg.namespace_id < 0) {
+ err = cfg.namespace_id;
goto close_fd;
}
}
if (cfg.deac)
control |= NVME_RW_DEAC;
if (!cfg.namespace_id) {
- cfg.namespace_id = get_nsid(fd);
- if (cfg.namespace_id == 0) {
- err = -EINVAL;
+ cfg.namespace_id = nvme_get_nsid(fd);
+ if (cfg.namespace_id < 0) {
+ err = cfg.namespace_id;
goto close_fd;
}
}
}
if (!cfg.namespace_id) {
- cfg.namespace_id = get_nsid(fd);
- if (cfg.namespace_id == 0) {
- err = -EINVAL;
+ cfg.namespace_id = nvme_get_nsid(fd);
+ if (cfg.namespace_id < 0) {
+ err = cfg.namespace_id;
goto close_fd;
}
}
goto ret;
if (S_ISBLK(nvme_stat.st_mode)) {
- cfg.namespace_id = get_nsid(fd);
- if (cfg.namespace_id == 0) {
- err = -EINVAL;
+ cfg.namespace_id = nvme_get_nsid(fd);
+ if (cfg.namespace_id < 0) {
+ err = cfg.namespace_id;
goto close_fd;
}
}
goto ret;
if (!cfg.namespace_id) {
- cfg.namespace_id = get_nsid(fd);
- if (cfg.namespace_id == 0) {
- err = -EINVAL;
+ cfg.namespace_id = nvme_get_nsid(fd);
+ if (cfg.namespace_id < 0) {
+ err = cfg.namespace_id;
goto close_fd;
}
}
goto ret;
if (!cfg.namespace_id) {
- cfg.namespace_id = get_nsid(fd);
- if (cfg.namespace_id == 0) {
- err = -EINVAL;
+ cfg.namespace_id = nvme_get_nsid(fd);
+ if (cfg.namespace_id < 0) {
+ err = cfg.namespace_id;
goto close_fd;
}
}
goto ret;
if (!cfg.namespace_id) {
- cfg.namespace_id = get_nsid(fd);
- if (cfg.namespace_id == 0) {
- err = -EINVAL;
+ cfg.namespace_id = nvme_get_nsid(fd);
+ if (cfg.namespace_id < 0) {
+ err = cfg.namespace_id;
goto close_fd;
}
}
flags = BINARY;
if (!cfg.namespace_id) {
- cfg.namespace_id = get_nsid(fd);
- if (cfg.namespace_id == 0) {
- err = -ENOTBLK;
+ cfg.namespace_id = nvme_get_nsid(fd);
+ if (cfg.namespace_id < 0) {
+ err = cfg.namespace_id;
goto close_fd;
}
}
control |= NVME_RW_FUA;
if (!cfg.namespace_id) {
- cfg.namespace_id = get_nsid(fd);
- if (cfg.namespace_id == 0) {
- err = EINVAL;
+ cfg.namespace_id = nvme_get_nsid(fd);
+ if (cfg.namespace_id < 0) {
+ err = cfg.namespace_id;
goto close_fd;
}
}
BINARY = 1 << 3, /* binary dump raw bytes */
};
-
struct nvme_subsystem;
struct nvme_ctrl;
char *address;
char *transport;
char *state;
+ char *ana_state;
+ char *traddr;
+ char *trsvcid;
+ char *host_traddr;
struct nvme_id_ctrl id;
struct nvme_subsystem *subsystems;
};
-struct ctrl_list_item {
- char *name;
- char *address;
- char *transport;
- char *state;
- char *ana_state;
- char *subsysnqn;
- char *traddr;
- char *trsvcid;
- char *host_traddr;
-};
-
-struct subsys_list_item {
- char *name;
- char *subsysnqn;
- int nctrls;
- struct ctrl_list_item *ctrls;
-};
-
-struct connect_args {
- char *subsysnqn;
- char *transport;
- char *traddr;
- char *trsvcid;
- char *host_traddr;
-};
-
-#define SYS_NVME "/sys/class/nvme"
-
-bool ctrl_matches_connectargs(char *name, struct connect_args *args);
-char *find_ctrl_with_connectargs(struct connect_args *args);
-char *__parse_connect_arg(char *conargs, const char delim, const char *fieldnm);
-
-extern const char *conarg_nqn;
-extern const char *conarg_transport;
-extern const char *conarg_traddr;
-extern const char *conarg_trsvcid;
-extern const char *conarg_host_traddr;
-extern const char *dev;
-extern const char *subsys_dir;
+#define SYS_NVME "/sys/class/nvme"
void register_extension(struct plugin *plugin);
-
int parse_and_open(int argc, char **argv, const char *desc,
const struct argconfig_commandline_options *clo);
extern const char *devicename;
-int __id_ctrl(int argc, char **argv, struct command *cmd, struct plugin *plugin, void (*vs)(__u8 *vs, struct json_object *root));
enum nvme_print_flags validate_output_format(char *format);
-
-int get_nvme_ctrl_info(char *name, char *path, struct ctrl_list_item *ctrl,
- __u32 nsid);
-struct subsys_list_item *get_subsys_list(int *subcnt, char *subsysnqn, __u32 nsid);
-void free_subsys_list(struct subsys_list_item *slist, int n);
+int __id_ctrl(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin, void (*vs)(__u8 *vs, struct json_object *root));
char *nvme_char_from_block(char *block);
-int get_nsid(int fd);
-void free_ctrl_list_item(struct ctrl_list_item *ctrls);
void *mmap_registers(const char *dev);
extern int current_index;
int scan_subsys_filter(const struct dirent *d);
int scan_dev_filter(const struct dirent *d);
-int scan_subsystems(struct nvme_topology *t);
+int scan_subsystems(struct nvme_topology *t, const char *subsysnqn,
+ __u32 ns_instance);
void free_topology(struct nvme_topology *t);
char *get_nvme_subsnqn(char *path);
+char *nvme_get_ctrl_attr(char *path, const char *attr);
#endif /* _NVME_H */
if (fmt != JSON && fmt != NORMAL)
return -EINVAL;
- n = scandir(dev, &devices, scan_namespace_filter, alphasort);
+ n = scandir("/dev", &devices, scan_namespace_filter, alphasort);
if (n <= 0)
return n;
}
for (i = 0; i < n; i++) {
- snprintf(path, sizeof(path), "%s%s", dev, devices[i]->d_name);
+ snprintf(path, sizeof(path), "/dev/%s", devices[i]->d_name);
fd = open(path, O_RDONLY);
ret = huawei_get_nvme_info(fd, &list_items[huawei_num], path);
if (ret)