All of lore.kernel.org
 help / color / mirror / Atom feed
From: hare@suse.de (Hannes Reinecke)
Subject: [PATCH nvme-cli 3/3] nvme-list-subsys: Add device name argument and print out ANA state
Date: Fri, 16 Nov 2018 08:35:01 +0100	[thread overview]
Message-ID: <20181116073501.7867-4-hare@suse.de> (raw)
In-Reply-To: <20181116073501.7867-1-hare@suse.de>

Update the 'nvme list-subsys' command to accept a device name and
print out the ANA state for all paths to that device.

Signed-off-by: Hannes Reinecke <hare at suse.com>
---
 Documentation/nvme-list-subsys.txt |   4 +-
 fabrics.c                          |   2 +-
 nvme-print.c                       |  10 ++-
 nvme.c                             | 135 +++++++++++++++++++++++++++++++++++--
 nvme.h                             |   3 +-
 5 files changed, 143 insertions(+), 11 deletions(-)

diff --git a/Documentation/nvme-list-subsys.txt b/Documentation/nvme-list-subsys.txt
index c7de7ef..c40b708 100644
--- a/Documentation/nvme-list-subsys.txt
+++ b/Documentation/nvme-list-subsys.txt
@@ -8,12 +8,14 @@ nvme-list-subsys - List all NVMe subsystems
 SYNOPSIS
 --------
 [verse]
-'nvme list-subsys' [-o <fmt> | --output-format=<fmt>]
+'nvme list-subsys' [-o <fmt> | --output-format=<fmt>] <device>
 
 DESCRIPTION
 -----------
 Scan the sysfs tree for NVM Express subsystems and return the controllers
 for those subsystems as well as some pertinent information about them.
+If a device is given, print out only the values for the controllers
+and subsystems leading to the device.
 
 OPTIONS
 -------
diff --git a/fabrics.c b/fabrics.c
index 711a755..f2bbd92 100644
--- a/fabrics.c
+++ b/fabrics.c
@@ -1102,7 +1102,7 @@ int disconnect_all(const char *desc, int argc, char **argv)
 	if (ret)
 		return ret;
 
-	slist = get_subsys_list(&subcnt);
+	slist = get_subsys_list(&subcnt, NULL, NVME_NSID_ALL);
 	for (i = 0; i < subcnt; i++) {
 		struct subsys_list_item *subsys = &slist[i];
 
diff --git a/nvme-print.c b/nvme-print.c
index 5cdfabe..ee3ceb3 100644
--- a/nvme-print.c
+++ b/nvme-print.c
@@ -2772,10 +2772,12 @@ static void show_nvme_subsystem(struct subsys_list_item *item)
 	printf("\\\n");
 
 	for (i = 0; i < item->nctrls; i++) {
-		printf(" +- %s %s %s %s\n", item->ctrls[i].name,
+		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].state,
+				item->ctrls[i].ana_state ?
+					item->ctrls[i].ana_state : "");
 	}
 
 }
@@ -2823,6 +2825,10 @@ void json_print_nvme_subsystem_list(struct subsys_list_item *slist, int n)
 					slist[i].ctrls[j].address);
 			json_object_add_value_string(path_attrs, "State",
 					slist[i].ctrls[j].state);
+			if (slist[i].ctrls[j].ana_state)
+				json_object_add_value_string(path_attrs,
+						"ANAState",
+						slist[i].ctrls[j].ana_state);
 			json_array_add_value_object(paths, path_attrs);
 		}
 		if (j) {
diff --git a/nvme.c b/nvme.c
index c3295c5..0e53472 100644
--- a/nvme.c
+++ b/nvme.c
@@ -1342,6 +1342,85 @@ err_free_path:
 	return NULL;
 }
 
+static int scan_ctrl_paths_filter(const struct dirent *d)
+{
+	int id, cntlid, nsid;
+
+	if (d->d_name[0] == '.')
+		return 0;
+
+	if (strstr(d->d_name, "nvme")) {
+		if (sscanf(d->d_name, "nvme%dc%dn%d", &id, &cntlid, &nsid) == 3)
+			return 1;
+		if (sscanf(d->d_name, "nvme%dn%d", &id, &nsid) == 2)
+			return 1;
+	}
+
+	return 0;
+}
+
+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;
+}
+
 static int scan_ctrls_filter(const struct dirent *d)
 {
 	int id, nsid;
@@ -1364,10 +1443,11 @@ static void free_ctrl_list_item(struct ctrl_list_item *ctrls)
 	free(ctrls->transport);
 	free(ctrls->address);
 	free(ctrls->state);
+	free(ctrls->ana_state);
 }
 
 static int get_nvme_subsystem_info(char *name, char *path,
-				struct subsys_list_item *item)
+				struct subsys_list_item *item, __u32 nsid)
 {
 	char ctrl_path[512];
 	struct dirent **ctrls;
@@ -1425,6 +1505,9 @@ static int get_nvme_subsystem_info(char *name, char *path,
 			continue;
 		}
 
+		if (nsid != NVME_NSID_ALL)
+			item->ctrls[ccnt].ana_state =
+				get_nvme_ctrl_path_ana_state(ctrl_path, nsid);
 		ccnt++;
 	}
 
@@ -1489,7 +1572,8 @@ void free_subsys_list(struct subsys_list_item *slist, int n)
 	free(slist);
 }
 
-struct subsys_list_item *get_subsys_list(int *subcnt)
+struct subsys_list_item *get_subsys_list(int *subcnt, char *subsysnqn,
+					 __u32 nsid)
 {
 	char path[310];
 	struct dirent **subsys;
@@ -1510,13 +1594,16 @@ struct subsys_list_item *get_subsys_list(int *subcnt)
 		snprintf(path, sizeof(path), "%s%s", subsys_dir,
 			subsys[i]->d_name);
 		ret = get_nvme_subsystem_info(subsys[i]->d_name, path,
-				&slist[*subcnt]);
+				&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
+		} else if (subsysnqn &&
+			   strncmp(slist[*subcnt].subsysnqn, subsysnqn, 255))
+			free_subsys_list_item(&slist[*subcnt]);
+		else
 			(*subcnt)++;
 	}
 
@@ -1533,12 +1620,15 @@ static int list_subsys(int argc, char **argv, struct command *cmd,
 {
 	struct subsys_list_item *slist;
 	int fmt, ret, subcnt = 0;
+	char *subsysnqn = NULL;
 	const char *desc = "Retrieve information for subsystems";
 	struct config {
+		__u32 namespace_id;
 		char *output_format;
 	};
 
 	struct config cfg = {
+		.namespace_id  = NVME_NSID_ALL,
 		.output_format = "normal",
 	};
 
@@ -1552,11 +1642,42 @@ static int list_subsys(int argc, char **argv, struct command *cmd,
 	if (ret < 0)
 		return ret;
 
+	devicename = NULL;
+	if (optind < argc) {
+		char path[512];
+		int id;
+
+		devicename = basename(argv[optind]);
+		if (sscanf(devicename, "nvme%dn%d", &id,
+			   &cfg.namespace_id) != 2) {
+			fprintf(stderr, "%s is not a NVMe namespace device\n",
+				argv[optind]);
+			return -EINVAL;
+		}
+		sprintf(path, "/sys/block/%s/device", devicename);
+		subsysnqn = get_nvme_subsnqn(path);
+		if (!subsysnqn) {
+			fprintf(stderr, "Cannot read subsys NQN from %s\n",
+				devicename);
+			return -EINVAL;
+		}
+		optind++;
+	}
+
+	if (ret < 0) {
+		argconfig_print_help(desc, opts);
+		if (subsysnqn)
+			free(subsysnqn);
+		return ret;
+	}
 	fmt = validate_output_format(cfg.output_format);
-	if (fmt != JSON && fmt != NORMAL)
+	if (fmt != JSON && fmt != NORMAL) {
+		if (subsysnqn)
+			free(subsysnqn);
 		return -EINVAL;
+	}
 
-	slist = get_subsys_list(&subcnt);
+	slist = get_subsys_list(&subcnt, subsysnqn, cfg.namespace_id);
 
 	if (fmt == JSON)
 		json_print_nvme_subsystem_list(slist, subcnt);
@@ -1564,6 +1685,8 @@ static int list_subsys(int argc, char **argv, struct command *cmd,
 		show_nvme_subsystem_list(slist, subcnt);
 
 	free_subsys_list(slist, subcnt);
+	if (subsysnqn)
+		free(subsysnqn);
 	return ret;
 }
 
diff --git a/nvme.h b/nvme.h
index 668c6fd..685d179 100644
--- a/nvme.h
+++ b/nvme.h
@@ -130,6 +130,7 @@ struct ctrl_list_item {
 	char *address;
 	char *transport;
 	char *state;
+	char *ana_state;
 };
 
 struct subsys_list_item {
@@ -156,7 +157,7 @@ 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));
 int	validate_output_format(char *format);
 
-struct subsys_list_item *get_subsys_list(int *subcnt);
+struct subsys_list_item *get_subsys_list(int *subcnt, char *subsysnqn, __u32 nsid);
 void free_subsys_list(struct subsys_list_item *slist, int n);
 char *nvme_char_from_block(char *block);
 #endif /* _NVME_H */
-- 
2.13.7

      parent reply	other threads:[~2018-11-16  7:35 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-11-16  7:34 [PATCH nvme-cli 0/3] Print out controller and ANA state for list-subsys Hannes Reinecke
2018-11-16  7:34 ` [PATCH nvme-cli 1/3] nvme: introduce get_nvme_ctrl_attr() Hannes Reinecke
2018-11-16 16:59   ` Keith Busch
2018-11-16  7:35 ` [PATCH nvme-cli 2/3] nvme: print out controller state for 'list-subsys' Hannes Reinecke
2018-11-16  7:35 ` Hannes Reinecke [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20181116073501.7867-4-hare@suse.de \
    --to=hare@suse.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.