|
20 | 20 | #include "nvme-models.h" |
21 | 21 | #include "util/suffix.h" |
22 | 22 | #include "util/types.h" |
| 23 | +#include "util/table.h" |
23 | 24 | #include "logging.h" |
24 | 25 | #include "common.h" |
25 | 26 |
|
@@ -5589,6 +5590,127 @@ static void stdout_list_items(nvme_root_t r) |
5589 | 5590 | stdout_simple_list(r); |
5590 | 5591 | } |
5591 | 5592 |
|
| 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 | + |
5592 | 5714 | static void stdout_subsystem_topology_multipath(nvme_subsystem_t s, |
5593 | 5715 | enum nvme_cli_topo_ranking ranking) |
5594 | 5716 | { |
@@ -5693,6 +5815,69 @@ static void stdout_subsystem_topology_multipath(nvme_subsystem_t s, |
5693 | 5815 | } |
5694 | 5816 | } |
5695 | 5817 |
|
| 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 | + |
5696 | 5881 | static void stdout_subsystem_topology(nvme_subsystem_t s, |
5697 | 5882 | enum nvme_cli_topo_ranking ranking) |
5698 | 5883 | { |
@@ -5745,6 +5930,38 @@ static void stdout_subsystem_topology(nvme_subsystem_t s, |
5745 | 5930 | } |
5746 | 5931 | } |
5747 | 5932 |
|
| 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 | + |
5748 | 5965 | static void stdout_simple_topology(nvme_root_t r, |
5749 | 5966 | enum nvme_cli_topo_ranking ranking) |
5750 | 5967 | { |
@@ -6363,6 +6580,7 @@ static struct print_ops stdout_print_ops = { |
6363 | 6580 | .topology_ctrl = stdout_topology_ctrl, |
6364 | 6581 | .topology_namespace = stdout_topology_namespace, |
6365 | 6582 | .topology_multipath = stdout_topology_multipath, |
| 6583 | + .topology_tabular = stdout_topology_tabular, |
6366 | 6584 |
|
6367 | 6585 | /* status and error messages */ |
6368 | 6586 | .connect_msg = stdout_connect_msg, |
|
0 commit comments