When running list-subsys on a specific namespace, we output all the
controllers that belong to the subsystem regardless if the requested
namespace is actually attached to them.
Example:
$ nvme list-subsys /dev/nvme0n1
nvme-subsys0 - NQN=nqn.2016-01.com.lightbitslabs:uuid:
07cfffe6-5a4f-4151-b663-
e13cf835609b
\
+- nvme0 tcp traddr=10.113.5.1 trsvcid=4420 live optimized
+- nvme1 tcp traddr=10.133.3.1 trsvcid=4420 live
+- nvme2 tcp traddr=10.133.1.1 trsvcid=4420 live
+- nvme3 tcp traddr=10.113.1.1 trsvcid=4420 live inaccessible
+- nvme4 tcp traddr=10.133.5.1 trsvcid=4420 live
+- nvme5 tcp traddr=10.113.4.1 trsvcid=4420 live
+- nvme6 tcp traddr=10.133.4.1 trsvcid=4420 live
+- nvme7 tcp traddr=10.113.2.1 trsvcid=4420 live
+- nvme8 tcp traddr=10.133.2.1 trsvcid=4420 live
+- nvme9 tcp traddr=10.113.3.1 trsvcid=4420 live
This output is somewhat confusing and makes the user think the namespace
is actually attached to all of these controllers, instead we want the
output which provided by the change introduced here:
$ nvme list-subsys /dev/nvme0n1
nvme-subsys0 - NQN=nqn.2016-01.com.lightbitslabs:uuid:
07cfffe6-5a4f-4151-b663-
e13cf835609b
\
+- nvme0 tcp traddr=10.113.5.1 trsvcid=4420 live optimized
+- nvme3 tcp traddr=10.113.1.1 trsvcid=4420 live inaccessible
Do the same trick as we do in scan_subsystems, we add the ctrl to the
topology if either ns_instance wasn't passed (see all controllers) or
it was pased _and_ the controller has this namespace is attached to
the controller (to do that we add nsid down the call chain for that).
Reviewed-by: Chaitanya Kulkarni <chaitanya.kulkarni@wdc.com>
Signed-off-by: Sagi Grimberg <sagi@grimberg.me>
Signed-off-by: Keith Busch <kbusch@kernel.org>
if (err)
goto out;
- err = scan_subsystems(&t, NULL, 0, NULL);
+ err = scan_subsystems(&t, NULL, 0, 0, NULL);
if (err) {
fprintf(stderr, "Failed to scan namespaces\n");
goto out;
free(path);
return;
}
- err = scan_subsystems(&t, subsysnqn, 0, NULL);
+ err = scan_subsystems(&t, subsysnqn, 0, 0, NULL);
if (err || t.nr_subsystems != 1) {
free(subsysnqn);
free(path);
static const char *dev = "/dev/";
static const char *subsys_dir = "/sys/class/nvme-subsystem/";
+static void free_ctrl(struct nvme_ctrl *c);
char *get_nvme_subsnqn(char *path)
{
return ana_state;
}
+static bool ns_attached_to_ctrl(int nsid, struct nvme_ctrl *ctrl)
+{
+ struct nvme_namespace *n;
+ int i;
+
+ for (i = 0; i < ctrl->nr_namespaces; i++) {
+ n = &ctrl->namespaces[i];
+ if (nsid == n->nsid)
+ return true;
+ }
+ return false;
+}
+
static int scan_ctrl(struct nvme_ctrl *c, char *p, __u32 ns_instance)
{
struct nvme_namespace *n;
return 0;
}
-static int scan_subsystem(struct nvme_subsystem *s, __u32 ns_instance)
+static int scan_subsystem(struct nvme_subsystem *s, __u32 ns_instance, int nsid)
{
struct dirent **ctrls, **ns;
struct nvme_namespace *n;
struct nvme_ctrl *c;
- int i, ret;
+ int i, j = 0, ret;
char *path;
ret = asprintf(&path, "%s%s", subsys_dir, s->name);
s->nr_ctrls = ret;
s->ctrls = calloc(s->nr_ctrls, sizeof(*c));
for (i = 0; i < s->nr_ctrls; i++) {
- c = &s->ctrls[i];
+ c = &s->ctrls[j];
c->name = strdup(ctrls[i]->d_name);
c->path = strdup(dev);
c->subsys = s;
scan_ctrl(c, path, ns_instance);
+
+ if (!ns_instance || ns_attached_to_ctrl(nsid, c))
+ j++;
+ else
+ free_ctrl(c);
}
+ s->nr_ctrls = j;
while (i--)
free(ctrls[i]);
}
int scan_subsystems(struct nvme_topology *t, const char *subsysnqn,
- __u32 ns_instance, char *dev_dir)
+ __u32 ns_instance, int nsid, char *dev_dir)
{
struct nvme_subsystem *s;
struct dirent **subsys;
for (i = 0; i < t->nr_subsystems; i++) {
s = &t->subsystems[j];
s->name = strdup(subsys[i]->d_name);
- scan_subsystem(s, ns_instance);
+ scan_subsystem(s, ns_instance, nsid);
if (!subsysnqn || !strcmp(s->subsysnqn, subsysnqn))
j++;
const char *desc = "Retrieve information for subsystems";
const char *verbose = "Increase output verbosity";
__u32 ns_instance = 0;
- int err;
+ int err, nsid = 0;
struct config {
char *output_format;
devicename = NULL;
if (optind < argc) {
char path[512];
- int id;
+ int id, fd;
devicename = basename(argv[optind]);
if (sscanf(devicename, "nvme%dn%d", &id, &ns_instance) != 2) {
err = -EINVAL;
goto ret;
}
+ sprintf(path, "/dev/%s", devicename);
+ fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "Cannot read nsid from %s\n",
+ devicename);
+ err = -EINVAL;
+ goto ret;
+ }
+ nsid = nvme_get_nsid(fd);
+ close(fd);
+ if (nsid < 0) {
+ fprintf(stderr, "Cannot read nsid from %s\n",
+ devicename);
+ err = -EINVAL;
+ goto ret;
+ }
sprintf(path, "/sys/block/%s/device", devicename);
subsysnqn = get_nvme_subsnqn(path);
if (!subsysnqn) {
if (cfg.verbose)
flags |= VERBOSE;
- err = scan_subsystems(&t, subsysnqn, ns_instance, NULL);
+ err = scan_subsystems(&t, subsysnqn, ns_instance, nsid, NULL);
if (err) {
fprintf(stderr, "Failed to scan namespaces\n");
goto free;
if (cfg.verbose)
flags |= VERBOSE;
- err = scan_subsystems(&t, NULL, 0, cfg.device_dir);
+ err = scan_subsystems(&t, NULL, 0, 0, cfg.device_dir);
if (err) {
fprintf(stderr, "Failed to scan namespaces\n");
return err;
int scan_dev_filter(const struct dirent *d);
int scan_subsystems(struct nvme_topology *t, const char *subsysnqn,
- __u32 ns_instance, char *dev_dir);
+ __u32 ns_instance, int nsid, char *dev_dir);
void free_topology(struct nvme_topology *t);
char *get_nvme_subsnqn(char *path);
char *nvme_get_ctrl_attr(char *path, const char *attr);