Skip to content

Commit 8338780

Browse files
committed
utils/nvme: enhance get_ns_status with show-topology fallback
The 'nvme show-topology /dev/<controller>' form fails on some nvme-cli builds, returning {"error": "Invalid device name"} instead of a valid JSON topology. Additionally, in multi-path subsystems where two controllers (e.g. nvme0 and nvme3) share a namespace (e.g. nvme3n1), the namespace block device is named after only one of the controllers, making a namespace name constructed from controller_name unreliable. Enhance get_ns_status with a two-stage approach: Primary path (unchanged behaviour): nvme show-topology /dev/<controller_name> -o json Parses the original JSON structure where paths["Name"] matches the controller name. Returns immediately on success. Fallback path (new): nvme show-topology -o json (whole-system, no device argument) Triggered when the primary path returns an error payload (dict instead of list), raises JSONDecodeError, or yields no match. Locates the correct path by matching NSID and Controller.Name inside the Paths[].Controller[] array, which is unambiguous across multi-controller subsystems and avoids any namespace device name construction. Both paths return [State, ANAState] preserving the existing API. Signed-off-by: Maram Srimannarayana Murthy <msmurthy@linux.vnet.ibm.com>
1 parent 2454cd2 commit 8338780

2 files changed

Lines changed: 56 additions & 13 deletions

File tree

avocado/utils/nvme.py

Lines changed: 50 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
Nvme utilities
2222
"""
2323

24-
2524
import json
2625
import logging
2726
import os
@@ -652,24 +651,62 @@ def create_namespaces(controller_name, ns_count, shared_ns=False):
652651

653652
def get_ns_status(controller_name, ns_id):
654653
"""
655-
Returns the status of namespaces on the specified controller
654+
Returns the status of namespaces on the specified controller.
656655
657-
:param controller_name: name of the controller like nvme0
658-
:param ns_id: ID of namespace for which we need the status
656+
Tries ``nvme show-topology /dev/<controller_name>`` first; falls back to
657+
``nvme show-topology -o json`` (whole-system) on error or no match, locating
658+
the path by ``NSID`` and ``Controller.Name`` (handles multi-path, e.g. ``nvme0``/``nvme3`` both serving ``nvme3n1``).
659659
660-
:rtype: list
660+
:param controller_name: name of the controller, e.g. ``nvme0``
661+
:param ns_id: NSID of the namespace whose status is required (int)
662+
663+
:rtype: list -- ``[State, ANAState]`` for the matching path, or ``[]``
661664
"""
662665
stat = []
666+
663667
cmd = f"nvme show-topology /dev/{controller_name} -o json"
664668
data = process.run(cmd, ignore_status=True, sudo=True, shell=True).stdout_text
665-
json_data = json.loads(data)
666-
for data in json_data:
667-
for subsystem in data["Subsystems"]:
668-
for namespace in subsystem["Namespaces"]:
669-
nsid = namespace["NSID"]
670-
for paths in namespace["Paths"]:
671-
if nsid == ns_id and paths["Name"] == controller_name:
672-
stat.extend([paths["State"], paths["ANAState"]])
669+
try:
670+
json_data = json.loads(data)
671+
except json.JSONDecodeError:
672+
json_data = None
673+
674+
if isinstance(json_data, list):
675+
for entry in json_data:
676+
for subsystem in entry.get("Subsystems", []):
677+
for namespace in subsystem.get("Namespaces", []):
678+
nsid = namespace.get("NSID")
679+
for path in namespace.get("Paths", []):
680+
if nsid == ns_id and path.get("Name") == controller_name:
681+
stat.extend([path["State"], path["ANAState"]])
682+
if stat:
683+
return stat
684+
685+
LOGGER.debug(
686+
"get_ns_status: primary show-topology for %s failed or returned no "
687+
"match; retrying with whole-system show-topology",
688+
controller_name,
689+
)
690+
cmd = "nvme show-topology -o json"
691+
data = process.run(cmd, ignore_status=True, sudo=True, shell=True).stdout_text
692+
try:
693+
json_data = json.loads(data)
694+
except json.JSONDecodeError:
695+
LOGGER.warning(
696+
"get_ns_status: could not parse whole-system show-topology output"
697+
)
698+
return stat
699+
700+
if isinstance(json_data, list):
701+
for entry in json_data:
702+
for subsystem in entry.get("Subsystems", []):
703+
for namespace in subsystem.get("Namespaces", []):
704+
if namespace.get("NSID") != ns_id:
705+
continue
706+
for path in namespace.get("Paths", []):
707+
for controller in path.get("Controller", []):
708+
if controller.get("Name") == controller_name:
709+
stat.extend([controller["State"], path["ANAState"]])
673710
return stat
674711

675712

docs/source/releases/next.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ Bug Fixes
2323

2424
* The Podman spawner now resolves the default ``podman`` binary through
2525
``PATH``, supporting installations outside ``/usr/bin``.
26+
* :func:`avocado.utils.nvme.get_ns_status` now handles nvme-cli builds
27+
that reject a controller node argument to ``nvme show-topology``, and
28+
correctly resolves namespace status for peer controllers in multi-path
29+
subsystems (e.g. ``nvme0`` and ``nvme3`` both serving ``nvme3n1``).
30+
A whole-system ``nvme show-topology -o json`` fallback is used when
31+
the controller-addressed form fails or yields no match.
2632

2733
Internal changes
2834
================

0 commit comments

Comments
 (0)