Skip to content

Commit 64bed0a

Browse files
shroffniigaw
authored andcommitted
nvme-list: fix verbose JSON output for 'nvme list' command
The verbose JSON output of the nvme list command is currently incorrect in both multipath and non-multipath configurations. Specifically, it prints empty Namespaces[] and Paths[] arrays in the wrong places, leading to confusion and invalid output. For example, on a system with single NVMe disk, signle controller and one namepsace created, 'nvme list --verbose --output json' prints the following output: With multipath disabled: { "Devices":[ { ... "Subsystems":[ { ... "Controllers":[ { "Controller":"nvme0", ... "Namespaces":[ { "NameSpace":"nvme0n1", ... } ], "Paths":[] <---- Incorrct: Path should not be present } ], "Namespaces":[] <-----Incorrect: Namespaces should not be here } ] } ] } With multipath enabled, the output changes, but still has misplaced or empty fields: { "Devices":[ { ... "Subsystems":[ { ... "Controllers":[ { "Controller":"nvme0", ... "Namespaces":[] <-----Incorrect: Namespaces should not be here "Paths":[ { "Path":"nvme0c0n1", "ANAState":"optimized" } ] } ], "Namespaces":[ { "NameSpace":"nvme0n1", ... } ] } ] } ] } So as we could see above in both multipath and non-multipath scenarios, the JSON formatted output is incorrect. The existing JSON formatting logic doesn't differentiate between multipath and non-multipath configurations. As a result: - "Paths" is printed even when multipath is disabled. - "Namespaces" appear at incorrect levels in the output tree. This patch updates the logic for verbose JSON output in nvme list to properly reflect the system configuration: - When multipath is enabled, each namespace entry includes its associated paths and controller attributes. - When multipath is disabled, namespaces are shown directly under the controller, and the "Paths" array is omitted. After this fix, JSON formatted output looks as below: Scenario1: multipath is enabled { Devices: [ { ... Subsystems: [ { ... Namespaces: [ { "NameSpace":"nvme0n1", ... Paths: [ { "Path":"nvme0c0n1", "ANAState":"optimized", "Controller":"nvme0", ... } ] } ] } ] } ] } Scenario2: multipath is disabled { Devices: [ { ... Subsystems: [ { ... Controllers: [ { "Controller":"nvme0", ... "Namespaces":[ { "NameSpace":"nvme0n1", ... } ] } ] } ] } ] } This fix ensures the JSON output is semantically accurate and easier to consume by tools that parse nvme list --verbose --output json. Reported-by: Maram Srimannarayana Murthy <[email protected]> Signed-off-by: Nilay Shroff <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Daniel Wagner <[email protected]>
1 parent 089c63d commit 64bed0a

File tree

3 files changed

+113
-81
lines changed

3 files changed

+113
-81
lines changed

nvme-print-json.c

Lines changed: 101 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -4423,16 +4423,110 @@ static void json_support_log(struct nvme_supported_log_pages *support_log,
44234423
json_print(r);
44244424
}
44254425

4426+
static void json_print_detail_list_multipath(nvme_subsystem_t s,
4427+
struct json_object *jss)
4428+
{
4429+
nvme_ns_t n;
4430+
nvme_path_t p;
4431+
struct json_object *jnss = json_create_array();
4432+
4433+
nvme_subsystem_for_each_ns(s, n) {
4434+
struct json_object *jns = json_create_object();
4435+
struct json_object *jpaths = json_create_array();
4436+
4437+
int lba = nvme_ns_get_lba_size(n);
4438+
uint64_t nsze = nvme_ns_get_lba_count(n) * lba;
4439+
uint64_t nuse = nvme_ns_get_lba_util(n) * lba;
4440+
4441+
obj_add_str(jns, "NameSpace", nvme_ns_get_name(n));
4442+
obj_add_str(jns, "Generic", nvme_ns_get_generic_name(n));
4443+
obj_add_int(jns, "NSID", nvme_ns_get_nsid(n));
4444+
obj_add_uint64(jns, "UsedBytes", nuse);
4445+
obj_add_uint64(jns, "MaximumLBA", nvme_ns_get_lba_count(n));
4446+
obj_add_uint64(jns, "PhysicalSize", nsze);
4447+
obj_add_int(jns, "SectorSize", lba);
4448+
4449+
nvme_namespace_for_each_path(n, p) {
4450+
nvme_ctrl_t c;
4451+
struct json_object *jpath = json_create_object();
4452+
4453+
obj_add_str(jpath, "Path", nvme_path_get_name(p));
4454+
obj_add_str(jpath, "ANAState", nvme_path_get_ana_state(p));
4455+
4456+
/*
4457+
* For multipath, each path maps to one controller.
4458+
* So get the controller from the path and then add
4459+
* controller attributes.
4460+
*/
4461+
c = nvme_path_get_ctrl(p);
4462+
obj_add_str(jpath, "Controller", nvme_ctrl_get_name(c));
4463+
obj_add_str(jpath, "Cntlid", nvme_ctrl_get_cntlid(c));
4464+
obj_add_str(jpath, "SerialNumber", nvme_ctrl_get_serial(c));
4465+
obj_add_str(jpath, "ModelNumber", nvme_ctrl_get_model(c));
4466+
obj_add_str(jpath, "Firmware", nvme_ctrl_get_firmware(c));
4467+
obj_add_str(jpath, "Transport", nvme_ctrl_get_transport(c));
4468+
obj_add_str(jpath, "Address", nvme_ctrl_get_address(c));
4469+
obj_add_str(jpath, "Slot", nvme_ctrl_get_phy_slot(c));
4470+
4471+
array_add_obj(jpaths, jpath);
4472+
}
4473+
4474+
obj_add_obj(jns, "Paths", jpaths);
4475+
array_add_obj(jnss, jns);
4476+
}
4477+
obj_add_obj(jss, "Namespaces", jnss);
4478+
}
4479+
4480+
static void json_print_detail_list(nvme_subsystem_t s, struct json_object *jss)
4481+
{
4482+
nvme_ctrl_t c;
4483+
nvme_ns_t n;
4484+
struct json_object *jctrls = json_create_array();
4485+
4486+
nvme_subsystem_for_each_ctrl(s, c) {
4487+
struct json_object *jctrl = json_create_object();
4488+
struct json_object *jnss = json_create_array();
4489+
4490+
obj_add_str(jctrl, "Controller", nvme_ctrl_get_name(c));
4491+
obj_add_str(jctrl, "Cntlid", nvme_ctrl_get_cntlid(c));
4492+
obj_add_str(jctrl, "SerialNumber", nvme_ctrl_get_serial(c));
4493+
obj_add_str(jctrl, "ModelNumber", nvme_ctrl_get_model(c));
4494+
obj_add_str(jctrl, "Firmware", nvme_ctrl_get_firmware(c));
4495+
obj_add_str(jctrl, "Transport", nvme_ctrl_get_transport(c));
4496+
obj_add_str(jctrl, "Address", nvme_ctrl_get_address(c));
4497+
obj_add_str(jctrl, "Slot", nvme_ctrl_get_phy_slot(c));
4498+
4499+
nvme_ctrl_for_each_ns(c, n) {
4500+
struct json_object *jns = json_create_object();
4501+
int lba = nvme_ns_get_lba_size(n);
4502+
uint64_t nsze = nvme_ns_get_lba_count(n) * lba;
4503+
uint64_t nuse = nvme_ns_get_lba_util(n) * lba;
4504+
4505+
obj_add_str(jns, "NameSpace", nvme_ns_get_name(n));
4506+
obj_add_str(jns, "Generic", nvme_ns_get_generic_name(n));
4507+
obj_add_int(jns, "NSID", nvme_ns_get_nsid(n));
4508+
obj_add_uint64(jns, "UsedBytes", nuse);
4509+
obj_add_uint64(jns, "MaximumLBA", nvme_ns_get_lba_count(n));
4510+
obj_add_uint64(jns, "PhysicalSize", nsze);
4511+
obj_add_int(jns, "SectorSize", lba);
4512+
4513+
array_add_obj(jnss, jns);
4514+
}
4515+
4516+
obj_add_obj(jctrl, "Namespaces", jnss);
4517+
array_add_obj(jctrls, jctrl);
4518+
}
4519+
4520+
obj_add_obj(jss, "Controllers", jctrls);
4521+
}
4522+
44264523
static void json_detail_list(nvme_root_t t)
44274524
{
44284525
struct json_object *r = json_create_object();
44294526
struct json_object *jdev = json_create_array();
44304527

44314528
nvme_host_t h;
44324529
nvme_subsystem_t s;
4433-
nvme_ctrl_t c;
4434-
nvme_path_t p;
4435-
nvme_ns_t n;
44364530

44374531
nvme_for_each_host(t, h) {
44384532
struct json_object *hss = json_create_object();
@@ -4446,76 +4540,14 @@ static void json_detail_list(nvme_root_t t)
44464540

44474541
nvme_for_each_subsystem(h, s) {
44484542
struct json_object *jss = json_create_object();
4449-
struct json_object *jctrls = json_create_array();
4450-
struct json_object *jnss = json_create_array();
44514543

44524544
obj_add_str(jss, "Subsystem", nvme_subsystem_get_name(s));
44534545
obj_add_str(jss, "SubsystemNQN", nvme_subsystem_get_nqn(s));
44544546

4455-
nvme_subsystem_for_each_ctrl(s, c) {
4456-
struct json_object *jctrl = json_create_object();
4457-
struct json_object *jnss = json_create_array();
4458-
struct json_object *jpaths = json_create_array();
4459-
4460-
obj_add_str(jctrl, "Controller", nvme_ctrl_get_name(c));
4461-
obj_add_str(jctrl, "Cntlid", nvme_ctrl_get_cntlid(c));
4462-
obj_add_str(jctrl, "SerialNumber", nvme_ctrl_get_serial(c));
4463-
obj_add_str(jctrl, "ModelNumber", nvme_ctrl_get_model(c));
4464-
obj_add_str(jctrl, "Firmware", nvme_ctrl_get_firmware(c));
4465-
obj_add_str(jctrl, "Transport", nvme_ctrl_get_transport(c));
4466-
obj_add_str(jctrl, "Address", nvme_ctrl_get_address(c));
4467-
obj_add_str(jctrl, "Slot", nvme_ctrl_get_phy_slot(c));
4468-
4469-
nvme_ctrl_for_each_ns(c, n) {
4470-
struct json_object *jns = json_create_object();
4471-
int lba = nvme_ns_get_lba_size(n);
4472-
uint64_t nsze = nvme_ns_get_lba_count(n) * lba;
4473-
uint64_t nuse = nvme_ns_get_lba_util(n) * lba;
4474-
4475-
obj_add_str(jns, "NameSpace", nvme_ns_get_name(n));
4476-
obj_add_str(jns, "Generic", nvme_ns_get_generic_name(n));
4477-
obj_add_int(jns, "NSID", nvme_ns_get_nsid(n));
4478-
obj_add_uint64(jns, "UsedBytes", nuse);
4479-
obj_add_uint64(jns, "MaximumLBA", nvme_ns_get_lba_count(n));
4480-
obj_add_uint64(jns, "PhysicalSize", nsze);
4481-
obj_add_int(jns, "SectorSize", lba);
4482-
4483-
array_add_obj(jnss, jns);
4484-
}
4485-
obj_add_obj(jctrl, "Namespaces", jnss);
4486-
4487-
nvme_ctrl_for_each_path(c, p) {
4488-
struct json_object *jpath = json_create_object();
4489-
4490-
obj_add_str(jpath, "Path", nvme_path_get_name(p));
4491-
obj_add_str(jpath, "ANAState", nvme_path_get_ana_state(p));
4492-
4493-
array_add_obj(jpaths, jpath);
4494-
}
4495-
obj_add_obj(jctrl, "Paths", jpaths);
4496-
4497-
array_add_obj(jctrls, jctrl);
4498-
}
4499-
obj_add_obj(jss, "Controllers", jctrls);
4500-
4501-
nvme_subsystem_for_each_ns(s, n) {
4502-
struct json_object *jns = json_create_object();
4503-
4504-
int lba = nvme_ns_get_lba_size(n);
4505-
uint64_t nsze = nvme_ns_get_lba_count(n) * lba;
4506-
uint64_t nuse = nvme_ns_get_lba_util(n) * lba;
4507-
4508-
obj_add_str(jns, "NameSpace", nvme_ns_get_name(n));
4509-
obj_add_str(jns, "Generic", nvme_ns_get_generic_name(n));
4510-
obj_add_int(jns, "NSID", nvme_ns_get_nsid(n));
4511-
obj_add_uint64(jns, "UsedBytes", nuse);
4512-
obj_add_uint64(jns, "MaximumLBA", nvme_ns_get_lba_count(n));
4513-
obj_add_uint64(jns, "PhysicalSize", nsze);
4514-
obj_add_int(jns, "SectorSize", lba);
4515-
4516-
array_add_obj(jnss, jns);
4517-
}
4518-
obj_add_obj(jss, "Namespaces", jnss);
4547+
if (nvme_is_multipath(s))
4548+
json_print_detail_list_multipath(s, jss);
4549+
else
4550+
json_print_detail_list(s, jss);
45194551

45204552
array_add_obj(jsslist, jss);
45214553
}

nvme-print-stdout.c

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5589,18 +5589,6 @@ static void stdout_list_items(nvme_root_t r)
55895589
stdout_simple_list(r);
55905590
}
55915591

5592-
static bool nvme_is_multipath(nvme_subsystem_t s)
5593-
{
5594-
nvme_ns_t n;
5595-
nvme_path_t p;
5596-
5597-
nvme_subsystem_for_each_ns(s, n)
5598-
nvme_namespace_for_each_path(n, p)
5599-
return true;
5600-
5601-
return false;
5602-
}
5603-
56045592
static void stdout_subsystem_topology_multipath(nvme_subsystem_t s,
56055593
enum nvme_cli_topo_ranking ranking)
56065594
{

nvme.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,18 @@ static inline nvme_mi_ep_t dev_mi_ep(struct nvme_dev *dev)
122122
return dev->mi.ep;
123123
}
124124

125+
static inline bool nvme_is_multipath(nvme_subsystem_t s)
126+
{
127+
nvme_ns_t n;
128+
nvme_path_t p;
129+
130+
nvme_subsystem_for_each_ns(s, n)
131+
nvme_namespace_for_each_path(n, p)
132+
return true;
133+
134+
return false;
135+
}
136+
125137
void register_extension(struct plugin *plugin);
126138

127139
/*

0 commit comments

Comments
 (0)