Skip to content

Commit c6a97d2

Browse files
Fix nvme device path fetch logic
1 parent a65190f commit c6a97d2

File tree

1 file changed

+275
-46
lines changed

1 file changed

+275
-46
lines changed

lisa/tools/nvmecli.py

Lines changed: 275 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -125,52 +125,281 @@ def get_devices(self, force_run: bool = False) -> Any:
125125
return nvme_devices["Devices"]
126126

127127
def get_disks(self, force_run: bool = False) -> List[str]:
128-
nvme_devices = self.get_devices(force_run=force_run)
129-
return [device["DevicePath"] for device in nvme_devices]
130-
131-
# NVME namespace ids are unique for each disk under any NVME controller.
132-
# These are useful in detecting the lun id of the remote azure disk disks.
133-
# Example output of nvme -list -o json and nvme -list
134-
# root@lisa--170-e0-n0:/home/lisa# nvme -list -o json
135-
# {
136-
# "Devices" : [
137-
# {
138-
# "NameSpace" : 1,
139-
# "DevicePath" : "/dev/nvme0n1",
140-
# "Firmware" : "v1.00000",
141-
# "Index" : 0,
142-
# "ModelNumber" : "MSFT NVMe Accelerator v1.0",
143-
# "ProductName" : "Non-Volatile memory controller: Microsoft Corporation Device 0x00a9", # noqa: E501
144-
# "SerialNumber" : "SN: 000001",
145-
# "UsedBytes" : 536870912000,
146-
# "MaximumLBA" : 1048576000,
147-
# "PhysicalSize" : 536870912000,
148-
# "SectorSize" : 512
149-
# },
150-
# {
151-
# "NameSpace" : 2,
152-
# "DevicePath" : "/dev/nvme0n2",
153-
# "Firmware" : "v1.00000",
154-
# "Index" : 0,
155-
# "ModelNumber" : "MSFT NVMe Accelerator v1.0",
156-
# "ProductName" : "Non-Volatile memory controller: Microsoft Corporation Device 0x00a9", # noqa: E501
157-
# "SerialNumber" : "SN: 000001",
158-
# "UsedBytes" : 4294967296,
159-
# "MaximumLBA" : 8388608,
160-
# "PhysicalSize" : 4294967296,
161-
# "SectorSize" : 512
162-
# }
163-
# ]
164-
# }
165-
# root@lisa--170-e0-n0:/home/lisa# nvme -list
166-
# Node SN Model Namespace Usage Format FW Rev # noqa: E501
167-
# --------------------- -------------------- ---------------------------------------- --------- -------------------------- ---------------- ------- # noqa: E501
168-
# /dev/nvme0n1 SN: 000001 MSFT NVMe Accelerator v1.0 1 536.87 GB / 536.87 GB 512 B + 0 B v1.0000 # noqa: E501
169-
# /dev/nvme0n2 SN: 000001 MSFT NVMe Accelerator v1.0 2 4.29 GB / 4.29 GB 512 B + 0 B v1.0000 # noqa: E501
170-
# /dev/nvme0n3 SN: 000001 MSFT NVMe Accelerator v1.0 15 44.02 GB / 44.02 GB 512 B + 0 B v1.0000 # noqa: E501
171-
# /dev/nvme0n4 SN: 000001 MSFT NVMe Accelerator v1.0 14 6.44 GB / 6.44 GB 512 B + 0 B v1.0000 # noqa: E501
172-
# /dev/nvme1n1 68e8d42a7ed4e5f90002 Microsoft NVMe Direct Disk v2 1 472.45 GB / 472.45 GB 512 B + 0 B NVMDV00 # noqa: E501
173-
# /dev/nvme2n1 68e8d42a7ed4e5f90001 Microsoft NVMe Direct Disk v2 1 472.45 GB / 472.45 GB 512 B + 0 B NVMDV00 # noqa: E501
128+
"""
129+
Return NVMe device nodes/paths (`/dev/...`) robustly across nvme-cli schemas.
130+
131+
Upstream change context:
132+
- nvme-cli reworked `nvme list -o json` around v2.11, removing the
133+
legacy top-level `.Devices[].DevicePath` and nesting device info under:
134+
Subsystems → Controllers → Namespaces.
135+
- Reference discussion and breakage report:
136+
https://github.com/linux-nvme/nvme-cli/issues/2749
137+
(thread points to commit 929f461 as the change introducing the new JSON)
138+
- Some distro builds (e.g., certain RHEL package revisions) may still
139+
emit `DevicePath`. This logic supports both.
140+
141+
Returns:
142+
List[str]: device nodes/paths like `/dev/nvme0n1`
143+
"""
144+
# NVME namespace ids are unique for each disk under any NVME controller.
145+
# These are useful in detecting the lun id of the remote azure disk disks.
146+
# Example output of nvme -list -o json and nvme -list
147+
# root@lisa--170-e0-n0:/home/lisa# nvme -list -o json
148+
# {
149+
# "Devices" : [
150+
# {
151+
# "NameSpace" : 1,
152+
# "DevicePath" : "/dev/nvme0n1",
153+
# "Firmware" : "v1.00000",
154+
# "Index" : 0,
155+
# "ModelNumber" : "MSFT NVMe Accelerator v1.0",
156+
# "ProductName" : "Non-Volatile memory controller: Microsoft Corporation Device 0x00a9", # noqa: E501
157+
# "SerialNumber" : "SN: 000001",
158+
# "UsedBytes" : 536870912000,
159+
# "MaximumLBA" : 1048576000,
160+
# "PhysicalSize" : 536870912000,
161+
# "SectorSize" : 512
162+
# },
163+
# {
164+
# "NameSpace" : 2,
165+
# "DevicePath" : "/dev/nvme0n2",
166+
# "Firmware" : "v1.00000",
167+
# "Index" : 0,
168+
# "ModelNumber" : "MSFT NVMe Accelerator v1.0",
169+
# "ProductName" : "Non-Volatile memory controller: Microsoft Corporation Device 0x00a9", # noqa: E501
170+
# "SerialNumber" : "SN: 000001",
171+
# "UsedBytes" : 4294967296,
172+
# "MaximumLBA" : 8388608,
173+
# "PhysicalSize" : 4294967296,
174+
# "SectorSize" : 512
175+
# }
176+
# ]
177+
# }
178+
# root@lisa--170-e0-n0:/home/lisa# nvme -list
179+
# Node SN Model Namespace Usage Format FW Rev # noqa: E501
180+
# --------------------- -------------------- ---------------------------------------- --------- -------------------------- ---------------- ------- # noqa: E501
181+
# /dev/nvme0n1 SN: 000001 MSFT NVMe Accelerator v1.0 1 536.87 GB / 536.87 GB 512 B + 0 B v1.0000 # noqa: E501
182+
# /dev/nvme0n2 SN: 000001 MSFT NVMe Accelerator v1.0 2 4.29 GB / 4.29 GB 512 B + 0 B v1.0000 # noqa: E501
183+
# /dev/nvme0n3 SN: 000001 MSFT NVMe Accelerator v1.0 15 44.02 GB / 44.02 GB 512 B + 0 B v1.0000 # noqa: E501
184+
# /dev/nvme0n4 SN: 000001 MSFT NVMe Accelerator v1.0 14 6.44 GB / 6.44 GB 512 B + 0 B v1.0000 # noqa: E501
185+
# /dev/nvme1n1 68e8d42a7ed4e5f90002 Microsoft NVMe Direct Disk v2 1 472.45 GB / 472.45 GB 512 B + 0 B NVMDV00 # noqa: E501
186+
# /dev/nvme2n1 68e8d42a7ed4e5f90001 Microsoft NVMe Direct Disk v2 1 472.45 GB / 472.45 GB 512 B + 0 B NVMDV00 # noqa: E501
187+
#
188+
# Another example output of nvme -list -o json without DevicePath key
189+
# cmd: ['sudo', 'sh', '-c', 'nvme list -o json 2>/dev/null']
190+
# "Devices":[
191+
# {
192+
# "HostNQN":"nqn.2014-08.org.nvmexpress:uuid:ec2bfbbc-632e-0494-048e-31ebc97bd499",
193+
# "HostID":"ec2bfbbc-632e-0494-048e-31ebc97bd499",
194+
# "Subsystems":[
195+
# {
196+
# "Subsystem":"nvme-subsys0",
197+
# "SubsystemNQN":"nqn.2014-08.org.nvmexpress:uuid:7ad35d50-c05b-47ab-b3a0-56a9a845852b",
198+
# "Controllers":[
199+
# {
200+
# "Controller":"nvme0",
201+
# "Cntlid":"0",
202+
# "SerialNumber":"SN: 00000",
203+
# "ModelNumber":"MSFT NVMe Accelerator v1.0",
204+
# "Firmware":"v1.00000",
205+
# "Transport":"pcie",
206+
# "Address":"c05b:00:00.0",
207+
# "Slot":"2060672336",
208+
# "Namespaces":[
209+
# {
210+
# "NameSpace":"nvme0n1",
211+
# "Generic":"ng0n1",
212+
# "NSID":1,
213+
# "UsedBytes":68719476736,
214+
# "MaximumLBA":134217728,
215+
# "PhysicalSize":68719476736,
216+
# "SectorSize":512
217+
# },
218+
# {
219+
# "NameSpace":"nvme0n10",
220+
# "Generic":"ng0n10",
221+
# "NSID":10,
222+
# "UsedBytes":1099511627776,
223+
# "MaximumLBA":2147483648,
224+
# "PhysicalSize":1099511627776,
225+
# "SectorSize":512
226+
# },
227+
# {
228+
# "NameSpace":"nvme0n11",
229+
# "Generic":"ng0n11",
230+
# "NSID":11,
231+
# "UsedBytes":1099511627776,
232+
# "MaximumLBA":2147483648,
233+
# "PhysicalSize":1099511627776,
234+
# "SectorSize":512
235+
# },
236+
# {
237+
# "NameSpace":"nvme0n12",
238+
# "Generic":"ng0n12",
239+
# "NSID":12,
240+
# "UsedBytes":1099511627776,
241+
# "MaximumLBA":2147483648,
242+
# "PhysicalSize":1099511627776,
243+
# "SectorSize":512
244+
# },
245+
# {
246+
# "NameSpace":"nvme0n13",
247+
# "Generic":"ng0n13",
248+
# "NSID":13,
249+
# "UsedBytes":1099511627776,
250+
# "MaximumLBA":2147483648,
251+
# "PhysicalSize":1099511627776,
252+
# "SectorSize":512
253+
# },
254+
# {
255+
# "NameSpace":"nvme0n14",
256+
# "Generic":"ng0n14",
257+
# "NSID":14,
258+
# "UsedBytes":1099511627776,
259+
# "MaximumLBA":2147483648,
260+
# "PhysicalSize":1099511627776,
261+
# "SectorSize":512
262+
# },
263+
# {
264+
# "NameSpace":"nvme0n15",
265+
# "Generic":"ng0n15",
266+
# "NSID":15,
267+
# "UsedBytes":1099511627776,
268+
# "MaximumLBA":2147483648,
269+
# "PhysicalSize":1099511627776,
270+
# "SectorSize":512
271+
# },
272+
# {
273+
# "NameSpace":"nvme0n16",
274+
# "Generic":"ng0n16",
275+
# "NSID":16,
276+
# "UsedBytes":1099511627776,
277+
# "MaximumLBA":2147483648,
278+
# "PhysicalSize":1099511627776,
279+
# "SectorSize":512
280+
# },
281+
# {
282+
# "NameSpace":"nvme0n17",
283+
# "Generic":"ng0n17",
284+
# "NSID":17,
285+
# "UsedBytes":1099511627776,
286+
# "MaximumLBA":2147483648,
287+
# "PhysicalSize":1099511627776,
288+
# "SectorSize":512
289+
# },
290+
# {
291+
# "NameSpace":"nvme0n2",
292+
# "Generic":"ng0n2",
293+
# "NSID":2,
294+
# "UsedBytes":1099511627776,
295+
# "MaximumLBA":2147483648,
296+
# "PhysicalSize":1099511627776,
297+
# "SectorSize":512
298+
# },
299+
# {
300+
# "NameSpace":"nvme0n3",
301+
# "Generic":"ng0n3",
302+
# "NSID":3,
303+
# "UsedBytes":1099511627776,
304+
# "MaximumLBA":2147483648,
305+
# "PhysicalSize":1099511627776,
306+
# "SectorSize":512
307+
# },
308+
# {
309+
# "NameSpace":"nvme0n4",
310+
# "Generic":"ng0n4",
311+
# "NSID":4,
312+
# "UsedBytes":1099511627776,
313+
# "MaximumLBA":2147483648,
314+
# "PhysicalSize":1099511627776,
315+
# "SectorSize":512
316+
# },
317+
# {
318+
# "NameSpace":"nvme0n5",
319+
# "Generic":"ng0n5",
320+
# "NSID":5,
321+
# "UsedBytes":1099511627776,
322+
# "MaximumLBA":2147483648,
323+
# "PhysicalSize":1099511627776,
324+
# "SectorSize":512
325+
# },
326+
# {
327+
# "NameSpace":"nvme0n6",
328+
# "Generic":"ng0n6",
329+
# "NSID":6,
330+
# "UsedBytes":1099511627776,
331+
# "MaximumLBA":2147483648,
332+
# "PhysicalSize":1099511627776,
333+
# "SectorSize":512
334+
# },
335+
# {
336+
# "NameSpace":"nvme0n7",
337+
# "Generic":"ng0n7",
338+
# "NSID":7,
339+
# "UsedBytes":1099511627776,
340+
# "MaximumLBA":2147483648,
341+
# "PhysicalSize":1099511627776,
342+
# "SectorSize":512
343+
# },
344+
# {
345+
# "NameSpace":"nvme0n8",
346+
# "Generic":"ng0n8",
347+
# "NSID":8,
348+
# "UsedBytes":1099511627776,
349+
# "MaximumLBA":2147483648,
350+
# "PhysicalSize":1099511627776,
351+
# "SectorSize":512
352+
# },
353+
# {
354+
# "NameSpace":"nvme0n9",
355+
# "Generic":"ng0n9",
356+
# "NSID":9,
357+
# "UsedBytes":1099511627776,
358+
# "MaximumLBA":2147483648,
359+
# "PhysicalSize":1099511627776,
360+
# "SectorSize":512
361+
# }
362+
# ],
363+
# "Paths":[
364+
# ]
365+
# }
366+
# ],
367+
# "Namespaces":[
368+
# ]
369+
# }
370+
# ]
371+
# }
372+
# ]
373+
# }
374+
nvme_devices = self.get_devices(force_run=force_run) # raw ["Devices"]
375+
device_paths = []
376+
377+
def _add(path: str) -> None:
378+
if isinstance(path, str) and path.startswith("/dev/") and len(path) > 5:
379+
device_paths.append(path)
380+
381+
for nvme_device in nvme_devices or []:
382+
# Legacy schema (flat fields):
383+
_add(nvme_device.get("DevicePath"))
384+
# _add(nvme_device.get("GenericPath"))
385+
386+
# New schema: Subsystems → Controllers → Namespaces
387+
for subsystem in nvme_device.get("Subsystems") or []:
388+
for controller in (subsystem or {}).get("Controllers") or []:
389+
for namespace in (controller or {}).get("Namespaces") or []:
390+
namespace_name = namespace.get("NameSpace") # e.g., "nvme0n1"
391+
# generic_name = namespace.get("Generic") # e.g., "ng0n1"
392+
if isinstance(namespace_name, str) and namespace_name:
393+
_add(f"/dev/{namespace_name}")
394+
# if isinstance(generic_name, str) and generic_name:
395+
# _add(f"/dev/{generic_name}")
396+
397+
device_paths = sorted(set(device_paths))
398+
if not device_paths:
399+
raise LisaException(
400+
"No NVMe device nodes could be derived from 'nvme list -o json'."
401+
)
402+
return device_paths
174403

175404
def get_namespace_ids(self, force_run: bool = False) -> List[Dict[str, int]]:
176405
nvme_devices = self.get_devices(force_run=force_run)

0 commit comments

Comments
 (0)