Skip to content

Improve unique identifier support to include NVMe devices#557

Open
tasleson wants to merge 6 commits into
libstorage:mainfrom
tasleson:hpsa
Open

Improve unique identifier support to include NVMe devices#557
tasleson wants to merge 6 commits into
libstorage:mainfrom
tasleson:hpsa

Conversation

@tasleson
Copy link
Copy Markdown
Member

@tasleson tasleson commented May 27, 2026

#135 discussed the lack of NVMe support. This pull request addresses this need.

Additionally, a small update to hpsa plugin was done, so that we could have this information available when it's not available once the storage devices are part of a RAID group.

Summary by CodeRabbit

  • New Features

    • Enhanced NVMe device support with improved serial number and VPD 0x83 identification.
  • Bug Fixes

    • Improved disk VPD 0x83 format validation to support additional identifier formats.
    • Fixed NVMe device classification for RPM and link type detection.
    • Enhanced disk identification in HPSa plugin using Drive Unique ID fallback.
  • Documentation

    • Updated installation guide and API documentation for disk identification functions.

Review Change Stack

tasleson added 6 commits May 26, 2026 14:16
NVMe devices were discovered by lsm_local_disk_list() and health
status worked, but vpd83_get, serial_num_get, link_type_get, and
rpm_get all rejected NVMe paths with "only support /dev/sd" errors.

NVMe devices don't expose SCSI VPD pages, but the kernel provides
native namespace identifiers via sysfs: nguid (128-bit) and eui
(64-bit) for disk ID, and device/serial for serial number.

For vpd83_get, try nguid first (/sys/block/<name>/nguid), falling
back to eui (/sys/block/<name>/eui) if nguid is absent or all zeros.
For serial_num_get, read /sys/block/<name>/device/serial.
For link_type_get, return LSM_DISK_LINK_TYPE_PCIE.
For rpm_get, return LSM_DISK_RPM_NON_ROTATING_MEDIUM.

Tested on RHEL 10.1 (hpe-dl560gen11) against /dev/nvme0n1 (EUI
fallback path exercised, nguid absent) and /dev/sd[abcd].

Resolves: libstorage#135

Assisted-by: Claude Code (Claude Opus 4.6)
Some controllers (e.g. HPE Smart Array on DL560 Gen11) expose
VPD page 83 with only EUI-64 designator type (0x2) and no NAA
(0x3). The existing code only matched NAA, causing these disks
to fail with "SCSI VPD 83 NAA logical unit ID is not supported".

Add a second pass that looks for EUI-64 designators when no NAA
is found. NAA remains preferred when both are present.

Tested on HPE DL560 Gen11 with /dev/sd[abcd] (EUI-64 only) and
/dev/nvme0n1 — all five disks now return valid identifiers.

Assisted-by: Claude Code (Claude Opus 4.6)
The Disk constructor reused Volume.vpd83_verify() which only accepts
NAA-format identifiers (leading 2/3/5 for 16-char, leading 6 for
32-char). EUI-64 identifiers from VPD page 83 designator type 0x2
don't follow NAA format — they're raw hex with no prefix constraint.

Add a separate _disk_regex_vpd83 that accepts any 16, 24, or 32
character hex string (covering EUI-64 8/12/16-byte variants and
NAA identifiers). The Volume validator remains strict since volumes
should always have NAA-format IDs from array controllers.

Assisted-by: Claude Code (Claude Opus 4.6)
The vpd83_get and vpd83_search header docs still promised NAA-only
format, but we now return EUI-64 and NVMe NGUID/EUI identifiers too.
Update the documented formats to match the actual behavior.

The man pages are generated from these header comments.

Assisted-by: Claude Code (Claude Opus 4.6)
When disks are members of a RAID array, ssacli no longer reports
the "Disk Name" (block device path), so LocalDisk.vpd83_get()
cannot be called. Fall back to the controller-reported
"Drive Unique ID" field which contains the EUI-64 identifier.

Assisted-by: Claude Code (Claude Opus 4.6)
$ make format

Signed-off-by: Tony Asleson <tasleson@redhat.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 27, 2026

📝 Walkthrough

Walkthrough

This PR extends libstoragemgmt to recognize and retrieve VPD 0x83 disk identifiers from NVMe devices via sysfs, alongside existing SCSI support. It updates API documentation, introduces NVMe parsing helpers, integrates NVMe branching into device serial and VPD lookup paths, optimizes NVMe device classification, and broadens Python validation to accept multiple identifier formats.

Changes

NVMe VPD 0x83 Support Throughout Stack

Layer / File(s) Summary
API documentation and VPD designator constants
c_binding/include/libstoragemgmt/libstoragemgmt_local_disk.h, c_binding/libsg.h
Public headers document VPD 0x83 search and retrieval for SCSI and NVMe disks, and new SPC-5 VPD designator type macros (_SG_T10_SPC_VPD_DI_DESIGNATOR_TYPE_EUI64, _SG_T10_SPC_VPD_DI_DESIGNATOR_TYPE_NAA) are introduced.
NVMe sysfs parsing infrastructure
c_binding/lsm_local_disk.cpp
New sysfs path constants for NVMe nguid, eui, and serial attributes; <ctype.h> support for normalization; forward-declared NVMe helpers; and implementations to read, filter delimiters, lowercase, and validate NVMe identifiers from sysfs.
SCSI VPD83 fallback and serial/VPD device integration
c_binding/lsm_local_disk.cpp
SCSI VPD83 extraction now falls back to EUI-64 when NAA is absent; lsm_local_disk_serial_num_get() and lsm_local_disk_vpd83_get() now branch by device type (/dev/nvme* vs /dev/sd*) and use NVMe sysfs helpers while preserving existing SCSI fallback chains.
Device classification shortcuts for NVMe
c_binding/lsm_local_disk.cpp
lsm_local_disk_rpm_get() and lsm_local_disk_link_type_get() short-circuit NVMe disks to LSM_DISK_RPM_NON_ROTATING_MEDIUM and LSM_DISK_LINK_TYPE_PCIE respectively, bypassing VPD and MODE SENSE probing.
Python validation and plugin VPD83 extraction
python_binding/lsm/_data.py, plugin/hpsa_plugin/hpsa.py
Python Disk.__init__ switches VPD 0x83 validation to a new regex accepting 16, 24, or 32 hex characters; HPSA plugin derives vpd83 from Drive Unique ID (lowercased) when Disk Name is absent.
Documentation updates and minor maintenance
INSTALL, c_binding/lsm_mgmt.cpp, plugin/arcconf_plugin/arcconf.py
INSTALL examples now prefer ./bootstrap over ./autogen.sh; log_exception calls in lsm_mgmt.cpp are reformatted; excess whitespace in arcconf_plugin is removed.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

A rabbit hops through NVMe lanes,
Where nguid and eui IDs reign,
SCSI grace with fallback EUI-64 chains,
Python's regex accepts the broader VPD domain—
No more single-drive constraints, the storage gains! 🐰✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 21.43% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding NVMe device support for unique disk identifiers, which aligns with the PR objectives and substantial code changes across multiple components.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

Review ran into problems

🔥 Problems

Git: Failed to clone repository. Please run the @coderabbitai full review command to re-trigger a full review. If the issue persists, set path_filters to include or exclude specific files.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@c_binding/lsm_local_disk.cpp`:
- Around line 833-836: The NVMe fast-path currently treats any path starting
with "/dev/nvme" as valid; before setting *rpm =
LSM_DISK_RPM_NON_ROTATING_MEDIUM (and similarly before setting link_type=PCIE in
the other block), perform a proper existence check (e.g., stat() or access()) on
disk_path and verify it's a valid device; if the check fails return
LSM_ERR_NOT_FOUND_DISK instead of LSM_ERR_OK. Locate the strncmp(disk_path,
"/dev/nvme", strlen("/dev/nvme")) checks and wrap them with the
existence/device-type validation so only real disks are accepted.
- Around line 331-332: The current conditional that allows any designator_len
between 1 and 16 for the EUI-64 fallback (checking dps[i]->header.designator_len
> 0 && dps[i]->header.designator_len <= 16) is too permissive and can emit
malformed VPD83 strings; change this check to only accept supported EUI
identifier byte lengths (exactly 8, 12, or 16) by replacing the range test with
an explicit check (e.g., dps[i]->header.designator_len == 8 ||
dps[i]->header.designator_len == 12 || dps[i]->header.designator_len == 16) so
that the fallback path in the code that formats the EUI only runs for valid
descriptor sizes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: aefdd28a-bda2-4ec6-ad6f-1e4b28a53f4a

📥 Commits

Reviewing files that changed from the base of the PR and between 22464f2 and 06ada18.

📒 Files selected for processing (8)
  • INSTALL
  • c_binding/include/libstoragemgmt/libstoragemgmt_local_disk.h
  • c_binding/libsg.h
  • c_binding/lsm_local_disk.cpp
  • c_binding/lsm_mgmt.cpp
  • plugin/arcconf_plugin/arcconf.py
  • plugin/hpsa_plugin/hpsa.py
  • python_binding/lsm/_data.py
💤 Files with no reviewable changes (1)
  • plugin/arcconf_plugin/arcconf.py

Comment on lines +331 to +332
(dps[i]->header.designator_len > 0) &&
(dps[i]->header.designator_len <= 16)) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Restrict EUI-64 fallback lengths to valid descriptor sizes.

Line 331 and Line 332 currently accept any designator_len from 1 to 16. EUI identifiers should be constrained to supported byte lengths (8, 12, or 16), otherwise malformed VPD83 strings can be emitted.

Proposed fix
-                (dps[i]->header.designator_len > 0) &&
-                (dps[i]->header.designator_len <= 16)) {
+                ((dps[i]->header.designator_len == 8) ||
+                 (dps[i]->header.designator_len == 12) ||
+                 (dps[i]->header.designator_len == 16))) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@c_binding/lsm_local_disk.cpp` around lines 331 - 332, The current conditional
that allows any designator_len between 1 and 16 for the EUI-64 fallback
(checking dps[i]->header.designator_len > 0 && dps[i]->header.designator_len <=
16) is too permissive and can emit malformed VPD83 strings; change this check to
only accept supported EUI identifier byte lengths (exactly 8, 12, or 16) by
replacing the range test with an explicit check (e.g.,
dps[i]->header.designator_len == 8 || dps[i]->header.designator_len == 12 ||
dps[i]->header.designator_len == 16) so that the fallback path in the code that
formats the EUI only runs for valid descriptor sizes.

Comment on lines +833 to +836
if (strncmp(disk_path, "/dev/nvme", strlen("/dev/nvme")) == 0) {
*rpm = LSM_DISK_RPM_NON_ROTATING_MEDIUM;
goto out;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Validate disk existence before NVMe fast-path success.

Line 833 and Line 1099 return LSM_ERR_OK purely from /dev/nvme prefix matching. A nonexistent path like /dev/nvme999n999 can be reported as valid (rpm=non-rotating / link_type=PCIE) instead of LSM_ERR_NOT_FOUND_DISK.

Proposed fix
 int lsm_local_disk_rpm_get(const char *disk_path, int32_t *rpm,
                            lsm_error **lsm_err) {
@@
     _lsm_err_msg_clear(err_msg);
 
     *lsm_err = NULL;
 
+    if (!_file_exists(disk_path)) {
+        rc = LSM_ERR_NOT_FOUND_DISK;
+        _lsm_err_msg_set(err_msg, "Disk %s not found", disk_path);
+        goto out;
+    }
+
     if (strncmp(disk_path, "/dev/nvme", strlen("/dev/nvme")) == 0) {
         *rpm = LSM_DISK_RPM_NON_ROTATING_MEDIUM;
         goto out;
@@
 int lsm_local_disk_link_type_get(const char *disk_path,
                                  lsm_disk_link_type *link_type,
                                  lsm_error **lsm_err) {
@@
     *link_type = LSM_DISK_LINK_TYPE_NO_SUPPORT;
     *lsm_err = NULL;
 
+    if (!_file_exists(disk_path)) {
+        rc = LSM_ERR_NOT_FOUND_DISK;
+        _lsm_err_msg_set(err_msg, "Disk %s not found", disk_path);
+        goto out;
+    }
+
     if (strncmp(disk_path, "/dev/nvme", strlen("/dev/nvme")) == 0) {
         *link_type = LSM_DISK_LINK_TYPE_PCIE;
         goto out;
     }

Also applies to: 1099-1102

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@c_binding/lsm_local_disk.cpp` around lines 833 - 836, The NVMe fast-path
currently treats any path starting with "/dev/nvme" as valid; before setting
*rpm = LSM_DISK_RPM_NON_ROTATING_MEDIUM (and similarly before setting
link_type=PCIE in the other block), perform a proper existence check (e.g.,
stat() or access()) on disk_path and verify it's a valid device; if the check
fails return LSM_ERR_NOT_FOUND_DISK instead of LSM_ERR_OK. Locate the
strncmp(disk_path, "/dev/nvme", strlen("/dev/nvme")) checks and wrap them with
the existence/device-type validation so only real disks are accepted.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant