public inbox for linux-nvme@lists.infradead.org
 help / color / mirror / Atom feed
* [PATCH 0/2] extend nvme show-topology tabular output
@ 2026-03-31 14:12 Nilay Shroff
  2026-03-31 14:12 ` [PATCH 1/2] nvme-cli: extend show-topology tabular output for non-multipath subsys Nilay Shroff
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Nilay Shroff @ 2026-03-31 14:12 UTC (permalink / raw)
  To: linux-nvme; +Cc: dwagner, gjoyce

Hi,

This patchset extends the tabular output of the "nvme show-topology"
command.

Currently, the tabular output does not display controller information
if a controller has no associated namespaces or paths. However, it is
valid for a controller within a subsystem to have no namespaces or
paths attached.

In such cases, it is still useful to display controller information
such as the controller name, transport type, address, and state,
while leaving namespace and path-related fields (e.g., nsid, nshead,
anastate, nspath) empty.

This patchset is divided into two patches, first patch extends the output
for non-multipath subsystems while the second patch extends the output for 
multipath subsystems.

As usual, feedback/comments/suggestions are welcome!

Thanks!

Nilay Shroff (2):
  nvme-cli: extend show-topology tabular output for non-multipath subsys
  nvme-cli: extend show-topology tabular output for multipath subsys

 nvme-print-stdout.c | 256 +++++++++++++++++++++++++++++++-------------
 1 file changed, 181 insertions(+), 75 deletions(-)

-- 
2.53.0



^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 1/2] nvme-cli: extend show-topology tabular output for non-multipath subsys
  2026-03-31 14:12 [PATCH 0/2] extend nvme show-topology tabular output Nilay Shroff
@ 2026-03-31 14:12 ` Nilay Shroff
  2026-03-31 14:12 ` [PATCH 2/2] nvme-cli: extend show-topology tabular output for multipath subsys Nilay Shroff
  2026-04-01 14:05 ` [PATCH 0/2] extend nvme show-topology tabular output Daniel Wagner
  2 siblings, 0 replies; 4+ messages in thread
From: Nilay Shroff @ 2026-03-31 14:12 UTC (permalink / raw)
  To: linux-nvme; +Cc: dwagner, gjoyce

The current tabular output of show-topology command does not display a
controller if it has no associated namespaces. However, it is valid
for a controller within a subsystem to have no namespaces attached.

In such cases, it is still useful to display controller information
such as the controller name, transport type, address, and state, while
leaving the namespace-related fields (e.g., namespace and nsid) as "--".

Update the tabular output of show-topology command to include
controllers and their associated fields regardless of whether any
namespaces are present. While we are at it, also dispaly the error
message using nvme_show_error() instead of using printf().

This change applies to non-multipath subsystems. A subsequent commit
will extend this behavior to multipath subsystems.

Signed-off-by: Nilay Shroff <nilay@linux.ibm.com>
---
 nvme-print-stdout.c | 98 +++++++++++++++++++++++++++++++--------------
 1 file changed, 69 insertions(+), 29 deletions(-)

diff --git a/nvme-print-stdout.c b/nvme-print-stdout.c
index 2e469ea50..769afa695 100644
--- a/nvme-print-stdout.c
+++ b/nvme-print-stdout.c
@@ -6148,11 +6148,48 @@ static void stdout_subsystem_topology_multipath(nvme_subsystem_t s,
 	}
 }
 
+static int subsystem_topology_add_row(struct table *t,
+				      const char *ns,
+				      const char *nsid,
+				      const char *ctrl,
+				      const char *trtype,
+				      const char *address,
+				      const char *state)
+{
+	int row = table_get_row_id(t);
+	if (row < 0) {
+		nvme_show_error("Failed to add subsys topology row");
+		return row;
+	}
+
+	/* col 0: Namespace */
+	table_set_value_str(t, 0, row, ns, CENTERED);
+
+	/* col 1: NSID */
+	table_set_value_str(t, 1, row, nsid, CENTERED);
+
+	/* col 2: Controller */
+	table_set_value_str(t, 2, row, ctrl, CENTERED);
+
+	/* col 3: Trtype */
+	table_set_value_str(t, 3, row, trtype, CENTERED);
+
+	/* col 4: Address */
+	table_set_value_str(t, 4, row, address, CENTERED);
+
+	/* col 5: State */
+	table_set_value_str(t, 5, row, state, CENTERED);
+
+	table_add_row(t, row);
+
+	return 0;
+}
+
 static void stdout_tabular_subsystem_topology(nvme_subsystem_t s)
 {
 	nvme_ctrl_t c;
 	nvme_ns_t n;
-	int row;
+	int ret, num_ns;
 	struct table *t;
 	struct table_column columns[] = {
 		{"Namespace", LEFT, 0},
@@ -6165,45 +6202,48 @@ static void stdout_tabular_subsystem_topology(nvme_subsystem_t s)
 
 	t = table_create();
 	if (!t) {
-		printf("Failed to init table\n");
+		nvme_show_error("Failed to init subsys topology table");
 		return;
 	}
 
 	if (table_add_columns(t, columns, ARRAY_SIZE(columns)) < 0) {
-		printf("Failed to add columns\n");
+		nvme_show_error("Failed to add subsys topology columns");
 		goto free_tbl;
 	}
 
 	nvme_subsystem_for_each_ctrl(s, c) {
-		nvme_ctrl_for_each_ns(c, n) {
-			c = nvme_ns_get_ctrl(n);
-
-			row = table_get_row_id(t);
-			if (row < 0) {
-				printf("Failed to add row\n");
+		num_ns = 0;
+
+		nvme_ctrl_for_each_ns(c, n)
+			num_ns++;
+
+		if (!num_ns) {
+			ret = subsystem_topology_add_row(t,
+					"--",	/* Namespace */
+					"--",	/* NSID */
+					nvme_ctrl_get_name(c),
+					nvme_ctrl_get_transport(c),
+					nvme_ctrl_get_traddr(c),
+					nvme_ctrl_get_state(c));
+			if (ret < 0)
 				goto free_tbl;
-			}
+		} else {
+			nvme_ctrl_for_each_ns(c, n) {
+				char nsid[32];
 
-			/* col 0: Namespace */
-			table_set_value_str(t, 0, row,
-					nvme_ns_get_name(n), LEFT);
-			/* col 1: NSID */
-			table_set_value_int(t, 1, row,
-					nvme_ns_get_nsid(n), CENTERED);
-			/* col 2: Controller */
-			table_set_value_str(t, 2, row,
-					nvme_ctrl_get_name(c), LEFT);
-			/* col 3: Trtype */
-			table_set_value_str(t, 3, row,
-					nvme_ctrl_get_transport(c), LEFT);
-			/* col 4: Address */
-			table_set_value_str(t, 4, row,
-					nvme_ctrl_get_traddr(c), LEFT);
-			/* col 5: State */
-			table_set_value_str(t, 5, row,
-					nvme_ctrl_get_state(c), LEFT);
+				snprintf(nsid, sizeof(nsid), "%u",
+						nvme_ns_get_nsid(n));
 
-			table_add_row(t, row);
+				ret = subsystem_topology_add_row(t,
+						nvme_ns_get_name(n),
+						(const char *)nsid,
+						nvme_ctrl_get_name(c),
+						nvme_ctrl_get_transport(c),
+						nvme_ctrl_get_traddr(c),
+						nvme_ctrl_get_state(c));
+				if (ret < 0)
+					goto free_tbl;
+			}
 		}
 	}
 	table_print(t);
-- 
2.53.0



^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 2/2] nvme-cli: extend show-topology tabular output for multipath subsys
  2026-03-31 14:12 [PATCH 0/2] extend nvme show-topology tabular output Nilay Shroff
  2026-03-31 14:12 ` [PATCH 1/2] nvme-cli: extend show-topology tabular output for non-multipath subsys Nilay Shroff
@ 2026-03-31 14:12 ` Nilay Shroff
  2026-04-01 14:05 ` [PATCH 0/2] extend nvme show-topology tabular output Daniel Wagner
  2 siblings, 0 replies; 4+ messages in thread
From: Nilay Shroff @ 2026-03-31 14:12 UTC (permalink / raw)
  To: linux-nvme; +Cc: dwagner, gjoyce

The current tabular output of the show-topology command does not
display a controller if it has no associated nvme path or namespaces.
However, it is valid for a controller within a subsystem to have no
namespaces or paths attached.

In such cases, it is still useful to display controller information
such as the controller name, transport type, address, and state, while
leaving NVMe path and namespace-related fields (e.g., nsid, nshead,
nspath, anastate etc.) as "--".

Update the tabular output of the show-topology command to include
controllers and their associated fields regardless of whether any
namespaces are present. While we are at it, also dispaly the error
message using nvme_show_error() instead of using printf().

This change applies to NVMe multipath subsystems.

Signed-off-by: Nilay Shroff <nilay@linux.ibm.com>
---
 nvme-print-stdout.c | 156 +++++++++++++++++++++++++++++++-------------
 1 file changed, 111 insertions(+), 45 deletions(-)

diff --git a/nvme-print-stdout.c b/nvme-print-stdout.c
index 769afa695..064956138 100644
--- a/nvme-print-stdout.c
+++ b/nvme-print-stdout.c
@@ -5945,13 +5945,69 @@ static bool subsystem_iopolicy_filter(const char *name, void *arg)
 	return true;
 }
 
+static int subsystem_topology_multipath_add_row(struct table *t,
+						const char *iopolicy,
+						const char *nshead,
+						const char *nsid,
+						const char *nspath,
+						const char *anastate,
+						const char *iopolicy_info,
+						const char *ctrl,
+						const char *trtype,
+						const char *address,
+						const char *state)
+{
+	int row;
+	int col = -1;
+
+	row = table_get_row_id(t);
+	if (row < 0) {
+		nvme_show_error("Failed to add subsys topology multipath row");
+		return row;
+	}
+
+	/* col 0: NSHead */
+	table_set_value_str(t, ++col, row, nshead, CENTERED);
+
+	/* col 1: NSID */
+	table_set_value_str(t, ++col, row, nsid, CENTERED);
+
+	/* col 2: NSPath */
+	table_set_value_str(t, ++col, row, nspath, CENTERED);
+
+	/* col 3: ANAState */
+	table_set_value_str(t, ++col, row, anastate, CENTERED);
+
+	/* col 4: Nodes/Qdepth */
+	if (!strcmp(iopolicy, "numa") || !strcmp(iopolicy, "queue-depth"))
+		table_set_value_str(t, ++col, row, iopolicy_info, CENTERED);
+
+	/* col 5: Controller */
+	table_set_value_str(t, ++col, row, ctrl, CENTERED);
+
+	/* col 6: TrType */
+	table_set_value_str(t, ++col, row, trtype, CENTERED);
+
+	/* col 7: Address */
+	table_set_value_str(t, ++col, row, address, CENTERED);
+
+	/* col 8: State */
+	table_set_value_str(t, ++col, row, state, CENTERED);
+
+	table_add_row(t, row);
+
+	return 0;
+}
+
 static void stdout_tabular_subsystem_topology_multipath(nvme_subsystem_t s)
 {
 	nvme_ns_t n;
 	nvme_path_t p;
 	nvme_ctrl_t c;
-	int row, col;
 	bool first;
+	char nshead[32], nsid[32];
+	char iopolicy_info[256];
+	int ret, num_path;
 	struct table *t;
 	const char *iopolicy = nvme_subsystem_get_iopolicy(s);
 	struct table_column columns[] = {
@@ -5969,13 +6025,13 @@ static void stdout_tabular_subsystem_topology_multipath(nvme_subsystem_t s)
 
 	t = table_create();
 	if (!t) {
-		printf("Failed to init table\n");
+		nvme_show_error("Failed to init subsys topology multipath table");
 		return;
 	}
 
 	if (table_add_columns_filter(t, columns, ARRAY_SIZE(columns),
 			subsystem_iopolicy_filter, (void *)s) < 0) {
-		printf("Failed to add columns\n");
+		nvme_show_error("Failed to add subsys topology multipath columns");
 		goto free_tbl;
 	}
 
@@ -5984,61 +6040,71 @@ static void stdout_tabular_subsystem_topology_multipath(nvme_subsystem_t s)
 		nvme_namespace_for_each_path(n, p) {
 			c = nvme_path_get_ctrl(p);
 
-			row = table_get_row_id(t);
-			if (row < 0) {
-				printf("Failed to add row\n");
-				goto free_tbl;
-			}
-			/* For the first row we print actual NSHead name,
+			/*
+			 * For the first row we print actual NSHead name,
 			 * however, for the subsequent rows we print "arrow"
 			 * ("-->") symbol for NSHead. This "arrow" style makes
 			 * it visually obvious that susequenet entries (if
 			 * present) are a path under the first NSHead.
 			 */
-			col = -1;
-			/* col 0: NSHead */
 			if (first) {
-				table_set_value_str(t, ++col, row,
-						nvme_ns_get_name(n), LEFT);
+				snprintf(nshead, sizeof(nshead), "%s",
+						nvme_ns_get_name(n));
 				first = false;
 			} else
-				table_set_value_str(t, ++col, row,
-						"-->", CENTERED);
-			/* col 1: NSID */
-			table_set_value_int(t, ++col, row,
-					nvme_ns_get_nsid(n), CENTERED);
-			/* col 2: NSPath */
-			table_set_value_str(t, ++col, row,
-					nvme_path_get_name(p), LEFT);
-			/* col 3: ANAState */
-			table_set_value_str(t, ++col, row,
-					nvme_path_get_ana_state(p), LEFT);
+				snprintf(nshead, sizeof(nshead), "%s", "-->");
+
+			snprintf(nsid, sizeof(nsid), "%u", nvme_ns_get_nsid(n));
 
 			if (!strcmp(iopolicy, "numa"))
-				/* col 4: Nodes */
-				table_set_value_str(t, ++col, row,
-					nvme_path_get_numa_nodes(p), CENTERED);
+				snprintf(iopolicy_info, sizeof(iopolicy_info),
+					"%s", nvme_path_get_numa_nodes(p));
 			else if (!strcmp(iopolicy, "queue-depth"))
-				/* col 4 : Qdepth */
-				table_set_value_int(t, ++col, row,
-					nvme_path_get_queue_depth(p), CENTERED);
-
-			/* col 5: Controller */
-			table_set_value_str(t, ++col, row,
-					nvme_ctrl_get_name(c), LEFT);
-			/* col 6: TrType */
-			table_set_value_str(t, ++col, row,
-					nvme_ctrl_get_transport(c), LEFT);
-			/* col 7: Address */
-			table_set_value_str(t, ++col, row,
-					nvme_ctrl_get_traddr(c), LEFT);
-			/* col 8: State */
-			table_set_value_str(t, ++col, row,
-					nvme_ctrl_get_state(c), LEFT);
-
-			table_add_row(t, row);
+				snprintf(iopolicy_info, sizeof(iopolicy_info),
+					"%d", nvme_path_get_queue_depth(p));
+
+			ret = subsystem_topology_multipath_add_row(t,
+						    iopolicy,
+						    nshead,
+						    nsid,
+						    nvme_path_get_name(p),
+						    nvme_path_get_ana_state(p),
+						    iopolicy_info,
+						    nvme_ctrl_get_name(c),
+						    nvme_ctrl_get_transport(c),
+						    nvme_ctrl_get_traddr(c),
+						    nvme_ctrl_get_state(c));
+			if (ret < 0)
+				goto free_tbl;
 		}
 	}
+
+	/*
+	 * Next we print controller in the subsystem which may not have any
+	 * nvme path associated to it.
+	 */
+	nvme_subsystem_for_each_ctrl(s, c) {
+		num_path = 0;
+		nvme_ctrl_for_each_path(c, p)
+			num_path++;
+
+		if (!num_path) {
+			ret = subsystem_topology_multipath_add_row(t,
+					iopolicy,
+					"--", 	/* NSHead */
+					"--", 	/* NSID */
+					"--", 	/* NSPath */
+					"--", 	/* ANAState */
+					"--", 	/* Nodes/Qdepth */
+					nvme_ctrl_get_name(c),
+					nvme_ctrl_get_transport(c),
+					nvme_ctrl_get_traddr(c),
+					nvme_ctrl_get_state(c));
+			if (ret < 0)
+				goto free_tbl;
+		}
+	}
+
 	table_print(t);
 free_tbl:
 	table_free(t);
-- 
2.53.0



^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH 0/2] extend nvme show-topology tabular output
  2026-03-31 14:12 [PATCH 0/2] extend nvme show-topology tabular output Nilay Shroff
  2026-03-31 14:12 ` [PATCH 1/2] nvme-cli: extend show-topology tabular output for non-multipath subsys Nilay Shroff
  2026-03-31 14:12 ` [PATCH 2/2] nvme-cli: extend show-topology tabular output for multipath subsys Nilay Shroff
@ 2026-04-01 14:05 ` Daniel Wagner
  2 siblings, 0 replies; 4+ messages in thread
From: Daniel Wagner @ 2026-04-01 14:05 UTC (permalink / raw)
  To: linux-nvme, Nilay Shroff; +Cc: Daniel Wagner, dwagner, gjoyce


On Tue, 31 Mar 2026 19:42:07 +0530, Nilay Shroff wrote:
> This patchset extends the tabular output of the "nvme show-topology"
> command.
> 
> Currently, the tabular output does not display controller information
> if a controller has no associated namespaces or paths. However, it is
> valid for a controller within a subsystem to have no namespaces or
> paths attached.
> 
> [...]

I've reformatted the argument list for the functions and dropped
redunant comments.

Applied, thanks!

[1/2] nvme-cli: extend show-topology tabular output for non-multipath subsys
      commit: cb7974bfd9a62a59134d696c5f38150bc9e306d
[2/2] nvme-cli: extend show-topology tabular output for multipath subsys
      commit: ce97b2d804c31b93fac006d5202f4c62271087f4

Best regards,
-- 
Daniel Wagner <wagi@kernel.org>


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-04-01 14:06 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-31 14:12 [PATCH 0/2] extend nvme show-topology tabular output Nilay Shroff
2026-03-31 14:12 ` [PATCH 1/2] nvme-cli: extend show-topology tabular output for non-multipath subsys Nilay Shroff
2026-03-31 14:12 ` [PATCH 2/2] nvme-cli: extend show-topology tabular output for multipath subsys Nilay Shroff
2026-04-01 14:05 ` [PATCH 0/2] extend nvme show-topology tabular output Daniel Wagner

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox