Skip to content

Commit e5a0a31

Browse files
shroffniigaw
authored andcommitted
nvme: add support for printing show-topology in tabular form
The nvme CLI command show-topology currently prints the topology output in a tree format. However, in some cases it is more convenient and easier to read or interpret the output when displayed in a tabular form. This patch adds support for printing the show-topology output in a tabular format. To achieve this, the --output-format option, which previously supported only normal and json formats, is extended to include a new tabular format. With this change, the user can now choose to print the topology in any of the following formats: normal, json, or tabular. The new tabular output leverages the recently introduced table APIs to produce well- aligned, easy-to-read output. Suggested-by: Daniel Wagner <[email protected]> Signed-off-by: Nilay Shroff <[email protected]> Signed-off-by: Daniel Wagner <[email protected]>
1 parent ebf0750 commit e5a0a31

File tree

5 files changed

+233
-1
lines changed

5 files changed

+233
-1
lines changed

nvme-print-stdout.c

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "nvme-models.h"
2121
#include "util/suffix.h"
2222
#include "util/types.h"
23+
#include "util/table.h"
2324
#include "logging.h"
2425
#include "common.h"
2526

@@ -5589,6 +5590,127 @@ static void stdout_list_items(nvme_root_t r)
55895590
stdout_simple_list(r);
55905591
}
55915592

5593+
static bool subsystem_iopolicy_filter(const char *name, void *arg)
5594+
{
5595+
nvme_subsystem_t s = arg;
5596+
const char *iopolicy = nvme_subsystem_get_iopolicy(s);
5597+
5598+
if (!strcmp(iopolicy, "queue-depth")) {
5599+
/* exclude "Nodes" for iopolicy queue-depth */
5600+
if (!strcmp(name, "Nodes"))
5601+
return false;
5602+
} else if (!strcmp(iopolicy, "numa")) {
5603+
/* exclude "Qdepth" for iopolicy numa */
5604+
if (!strcmp(name, "Qdepth"))
5605+
return false;
5606+
} else { /* round-robin */
5607+
/* exclude "Nodes" and "Qdepth" for iopolicy round-robin */
5608+
if (!strcmp(name, "Nodes") || !strcmp(name, "Qdepth"))
5609+
return false;
5610+
}
5611+
5612+
return true;
5613+
}
5614+
5615+
static void stdout_tabular_subsystem_topology_multipath(nvme_subsystem_t s)
5616+
{
5617+
nvme_ns_t n;
5618+
nvme_path_t p;
5619+
nvme_ctrl_t c;
5620+
int row, col;
5621+
bool first;
5622+
struct table *t;
5623+
const char *iopolicy = nvme_subsystem_get_iopolicy(s);
5624+
struct table_column columns[] = {
5625+
{"NSHead", LEFT, 0},
5626+
{"NSID", LEFT, 0},
5627+
{"NSPath", LEFT, 0},
5628+
{"ANAState", LEFT, 0},
5629+
{"Nodes", LEFT, 0},
5630+
{"Qdepth", LEFT, 0},
5631+
{"Controller", LEFT, 0},
5632+
{"TrType", LEFT, 0},
5633+
{"Address", LEFT, 0},
5634+
{"State", LEFT, 0},
5635+
};
5636+
5637+
t = table_init();
5638+
if (!t) {
5639+
printf("Failed to init table\n");
5640+
return;
5641+
}
5642+
5643+
if (table_add_columns_filter(t, columns, ARRAY_SIZE(columns),
5644+
subsystem_iopolicy_filter, (void *)s) < 0) {
5645+
printf("Failed to add columns\n");
5646+
goto free_tbl;
5647+
}
5648+
5649+
nvme_subsystem_for_each_ns(s, n) {
5650+
first = true;
5651+
nvme_namespace_for_each_path(n, p) {
5652+
c = nvme_path_get_ctrl(p);
5653+
5654+
row = table_get_row_id(t);
5655+
if (row < 0) {
5656+
printf("Failed to add row\n");
5657+
goto free_tbl;
5658+
}
5659+
/* For the first row we print actual NSHead name,
5660+
* however, for the subsequent rows we print "arrow"
5661+
* ("-->") symbol for NSHead. This "arrow" style makes
5662+
* it visually obvious that susequenet entries (if
5663+
* present) are a path under the first NSHead.
5664+
*/
5665+
col = -1;
5666+
/* col 0: NSHead */
5667+
if (first) {
5668+
table_set_value_str(t, ++col, row,
5669+
nvme_ns_get_name(n), LEFT);
5670+
first = false;
5671+
} else
5672+
table_set_value_str(t, ++col, row,
5673+
"-->", CENTERED);
5674+
/* col 1: NSID */
5675+
table_set_value_int(t, ++col, row,
5676+
nvme_ns_get_nsid(n), CENTERED);
5677+
/* col 2: NSPath */
5678+
table_set_value_str(t, ++col, row,
5679+
nvme_path_get_name(p), LEFT);
5680+
/* col 3: ANAState */
5681+
table_set_value_str(t, ++col, row,
5682+
nvme_path_get_ana_state(p), LEFT);
5683+
5684+
if (!strcmp(iopolicy, "numa"))
5685+
/* col 4: Nodes */
5686+
table_set_value_str(t, ++col, row,
5687+
nvme_path_get_numa_nodes(p), CENTERED);
5688+
else if (!strcmp(iopolicy, "queue-depth"))
5689+
/* col 4 : Qdepth */
5690+
table_set_value_int(t, ++col, row,
5691+
nvme_path_get_queue_depth(p), CENTERED);
5692+
5693+
/* col 5: Controller */
5694+
table_set_value_str(t, ++col, row,
5695+
nvme_ctrl_get_name(c), LEFT);
5696+
/* col 6: TrType */
5697+
table_set_value_str(t, ++col, row,
5698+
nvme_ctrl_get_transport(c), LEFT);
5699+
/* col 7: Address */
5700+
table_set_value_str(t, ++col, row,
5701+
nvme_ctrl_get_address(c), LEFT);
5702+
/* col 8: State */
5703+
table_set_value_str(t, ++col, row,
5704+
nvme_ctrl_get_state(c), LEFT);
5705+
5706+
table_add_row(t, row);
5707+
}
5708+
}
5709+
table_print(t);
5710+
free_tbl:
5711+
table_free(t);
5712+
}
5713+
55925714
static void stdout_subsystem_topology_multipath(nvme_subsystem_t s,
55935715
enum nvme_cli_topo_ranking ranking)
55945716
{
@@ -5693,6 +5815,69 @@ static void stdout_subsystem_topology_multipath(nvme_subsystem_t s,
56935815
}
56945816
}
56955817

5818+
static void stdout_tabular_subsystem_topology(nvme_subsystem_t s)
5819+
{
5820+
nvme_ctrl_t c;
5821+
nvme_ns_t n;
5822+
int row;
5823+
struct table *t;
5824+
struct table_column columns[] = {
5825+
{"Namespace", LEFT, 0},
5826+
{"NSID", LEFT, 0},
5827+
{"Controller", LEFT, 0},
5828+
{"Trtype", LEFT, 0},
5829+
{"Address", LEFT, 0},
5830+
{"State", LEFT, 0},
5831+
};
5832+
5833+
t = table_init();
5834+
if (!t) {
5835+
printf("Failed to init table\n");
5836+
return;
5837+
}
5838+
5839+
if (table_add_columns(t, columns, ARRAY_SIZE(columns)) < 0) {
5840+
printf("Failed to add columns\n");
5841+
goto free_tbl;
5842+
}
5843+
5844+
nvme_subsystem_for_each_ctrl(s, c) {
5845+
nvme_ctrl_for_each_ns(c, n) {
5846+
c = nvme_ns_get_ctrl(n);
5847+
5848+
row = table_get_row_id(t);
5849+
if (row < 0) {
5850+
printf("Failed to add row\n");
5851+
goto free_tbl;
5852+
}
5853+
5854+
/* col 0: Namespace */
5855+
table_set_value_str(t, 0, row,
5856+
nvme_ns_get_name(n), LEFT);
5857+
/* col 1: NSID */
5858+
table_set_value_int(t, 1, row,
5859+
nvme_ns_get_nsid(n), CENTERED);
5860+
/* col 2: Controller */
5861+
table_set_value_str(t, 2, row,
5862+
nvme_ctrl_get_name(c), LEFT);
5863+
/* col 3: Trtype */
5864+
table_set_value_str(t, 3, row,
5865+
nvme_ctrl_get_transport(c), LEFT);
5866+
/* col 4: Address */
5867+
table_set_value_str(t, 4, row,
5868+
nvme_ctrl_get_address(c), LEFT);
5869+
/* col 5: State */
5870+
table_set_value_str(t, 5, row,
5871+
nvme_ctrl_get_state(c), LEFT);
5872+
5873+
table_add_row(t, row);
5874+
}
5875+
}
5876+
table_print(t);
5877+
free_tbl:
5878+
table_free(t);
5879+
}
5880+
56965881
static void stdout_subsystem_topology(nvme_subsystem_t s,
56975882
enum nvme_cli_topo_ranking ranking)
56985883
{
@@ -5745,6 +5930,38 @@ static void stdout_subsystem_topology(nvme_subsystem_t s,
57455930
}
57465931
}
57475932

5933+
static void stdout_topology_tabular(nvme_root_t r)
5934+
{
5935+
nvme_host_t h;
5936+
nvme_subsystem_t s;
5937+
bool first = true;
5938+
5939+
nvme_for_each_host(r, h) {
5940+
nvme_for_each_subsystem(h, s) {
5941+
bool no_ctrl = true;
5942+
nvme_ctrl_t c;
5943+
5944+
nvme_subsystem_for_each_ctrl(s, c)
5945+
no_ctrl = false;
5946+
5947+
if (no_ctrl)
5948+
continue;
5949+
5950+
if (!first)
5951+
printf("\n");
5952+
first = false;
5953+
5954+
stdout_subsys_config(s);
5955+
printf("\n");
5956+
5957+
if (nvme_is_multipath(s))
5958+
stdout_tabular_subsystem_topology_multipath(s);
5959+
else
5960+
stdout_tabular_subsystem_topology(s);
5961+
}
5962+
}
5963+
}
5964+
57485965
static void stdout_simple_topology(nvme_root_t r,
57495966
enum nvme_cli_topo_ranking ranking)
57505967
{
@@ -6363,6 +6580,7 @@ static struct print_ops stdout_print_ops = {
63636580
.topology_ctrl = stdout_topology_ctrl,
63646581
.topology_namespace = stdout_topology_namespace,
63656582
.topology_multipath = stdout_topology_multipath,
6583+
.topology_tabular = stdout_topology_tabular,
63666584

63676585
/* status and error messages */
63686586
.connect_msg = stdout_connect_msg,

nvme-print.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1557,6 +1557,11 @@ void nvme_show_topology(nvme_root_t r,
15571557
nvme_print(topology_multipath, flags, r);
15581558
}
15591559

1560+
void nvme_show_topology_tabular(nvme_root_t r, nvme_print_flags_t flags)
1561+
{
1562+
nvme_print(topology_tabular, flags, r);
1563+
}
1564+
15601565
void nvme_show_message(bool error, const char *msg, ...)
15611566
{
15621567
struct print_ops *ops = nvme_print_ops(NORMAL);

nvme-print.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ struct print_ops {
107107
void (*topology_ctrl)(nvme_root_t r);
108108
void (*topology_namespace)(nvme_root_t r);
109109
void (*topology_multipath)(nvme_root_t r);
110+
void (*topology_tabular)(nvme_root_t r);
110111

111112
/* status and error messages */
112113
void (*connect_msg)(nvme_ctrl_t c);
@@ -251,6 +252,7 @@ void nvme_show_list_ns(struct nvme_ns_list *ns_list,
251252
void nvme_show_topology(nvme_root_t t,
252253
enum nvme_cli_topo_ranking ranking,
253254
nvme_print_flags_t flags);
255+
void nvme_show_topology_tabular(nvme_root_t t, nvme_print_flags_t flags);
254256

255257
void nvme_feature_show(enum nvme_features_id fid, int sel, unsigned int result);
256258
void nvme_feature_show_fields(enum nvme_features_id fid, unsigned int result, unsigned char *buf);

nvme.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,8 @@ int validate_output_format(const char *format, nvme_print_flags_t *flags)
545545
#endif /* CONFIG_JSONC */
546546
else if (!strcmp(format, "binary"))
547547
f = BINARY;
548+
else if (!strcmp(format, "tabular"))
549+
f = TABULAR;
548550
else
549551
return -EINVAL;
550552

@@ -10204,6 +10206,7 @@ static int tls_key(int argc, char **argv, struct command *command, struct plugin
1020410206
static int show_topology_cmd(int argc, char **argv, struct command *command, struct plugin *plugin)
1020510207
{
1020610208
const char *desc = "Show the topology\n";
10209+
const char *output_format = "Output format: normal|json|binary|tabular";
1020710210
const char *ranking = "Ranking order: namespace|ctrl|multipath";
1020810211
nvme_print_flags_t flags;
1020910212
_cleanup_nvme_root_ nvme_root_t r = NULL;
@@ -10272,7 +10275,10 @@ static int show_topology_cmd(int argc, char **argv, struct command *command, str
1027210275
return err;
1027310276
}
1027410277

10275-
nvme_show_topology(r, rank, flags);
10278+
if (flags & TABULAR)
10279+
nvme_show_topology_tabular(r, flags);
10280+
else
10281+
nvme_show_topology(r, rank, flags);
1027610282

1027710283
return err;
1027810284
}

nvme.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ enum nvme_print_flags {
3939
JSON = 1 << 1, /* display in json format */
4040
VS = 1 << 2, /* hex dump vendor specific data areas */
4141
BINARY = 1 << 3, /* binary dump raw bytes */
42+
TABULAR = 1 << 4, /* prints aligned columns for easy reading */
4243
};
4344

4445
typedef uint32_t nvme_print_flags_t;

0 commit comments

Comments
 (0)