Skip to content

Commit a4697f1

Browse files
committed
utils/nvme: Enhanced get_ns_status to support ns 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 a4697f1

2 files changed

Lines changed: 61 additions & 12 deletions

File tree

avocado/utils/nvme.py

Lines changed: 55 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -652,24 +652,67 @@ def create_namespaces(controller_name, ns_count, shared_ns=False):
652652

653653
def get_ns_status(controller_name, ns_id):
654654
"""
655-
Returns the status of namespaces on the specified controller
655+
Returns the status of namespaces on the specified controller.
656656
657-
:param controller_name: name of the controller like nvme0
658-
:param ns_id: ID of namespace for which we need the status
657+
Tries ``nvme show-topology /dev/<controller_name>`` first. If that
658+
command returns an error payload (observed with some nvme-cli builds
659+
where passing a controller node is rejected) or yields no match, the
660+
function falls back to ``nvme show-topology -o json`` (whole-system)
661+
and locates the path by matching ``NSID`` and ``Controller.Name``.
662+
This correctly handles multi-path subsystems where the namespace block
663+
device is named after a peer controller (e.g. ``nvme0`` and ``nvme3``
664+
both serving ``nvme3n1``).
659665
660-
:rtype: list
666+
:param controller_name: name of the controller, e.g. ``nvme0``
667+
:param ns_id: NSID of the namespace whose status is required (int)
668+
669+
:rtype: list -- ``[State, ANAState]`` for the matching path, or ``[]``
661670
"""
662671
stat = []
672+
663673
cmd = f"nvme show-topology /dev/{controller_name} -o json"
664674
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"]])
675+
try:
676+
json_data = json.loads(data)
677+
except json.JSONDecodeError:
678+
json_data = None
679+
680+
if isinstance(json_data, list):
681+
for entry in json_data:
682+
for subsystem in entry.get("Subsystems", []):
683+
for namespace in subsystem.get("Namespaces", []):
684+
nsid = namespace.get("NSID")
685+
for path in namespace.get("Paths", []):
686+
if nsid == ns_id and path.get("Name") == controller_name:
687+
stat.extend([path["State"], path["ANAState"]])
688+
if stat:
689+
return stat
690+
691+
LOGGER.debug(
692+
"get_ns_status: primary show-topology for %s failed or returned no "
693+
"match; retrying with whole-system show-topology",
694+
controller_name,
695+
)
696+
cmd = "nvme show-topology -o json"
697+
data = process.run(cmd, ignore_status=True, sudo=True, shell=True).stdout_text
698+
try:
699+
json_data = json.loads(data)
700+
except json.JSONDecodeError:
701+
LOGGER.warning(
702+
"get_ns_status: could not parse whole-system show-topology output"
703+
)
704+
return stat
705+
706+
if isinstance(json_data, list):
707+
for entry in json_data:
708+
for subsystem in entry.get("Subsystems", []):
709+
for namespace in subsystem.get("Namespaces", []):
710+
if namespace.get("NSID") != ns_id:
711+
continue
712+
for path in namespace.get("Paths", []):
713+
for controller in path.get("Controller", []):
714+
if controller.get("Name") == controller_name:
715+
stat.extend([controller["State"], path["ANAState"]])
673716
return stat
674717

675718

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)