NEWS
September 18, 2026 ยท View on GitHub
Changes in 3.1 (2026-09-18)
Feature removals and incompatible changes
-
The minimum required Meson version is now 1.0.0, up from 0.62.0. Meson 1.0.0 was released in December 2022, so any reasonably current build environment should already meet it.
-
nvme gen-hostnqnmust now be run as root. The DMI and device tree files it reads are readable by root only. An unprivileged run returned a random identifier instead. Seenvme-gen-hostnqn(1).
libnvme
-
libnvmf_generate_hostid()now falls back to the local machine ID, after DMI and the device tree and before a random UUID. The machine ID itself is never published. The UUID is derived from it with HMAC-SHA256 and a fixed application identifier. -
A system UUID of all zeros or all ones is now discarded as invalid.
-
A UUID-format host NQN read out of firmware-supplied NBFT data now has its UUID lower-cased on entry if the firmware got that wrong. All NQN comparisons remain plain, byte-exact, locale-independent string comparisons, per the Base Specification; only the value is normalized, at the one point it enters libnvme, not the comparison.
-
NVMe-oF URI parsing now normalizes the
nvme+<transport>scheme to lower case regardless of how it was spelled, matching the Boot Specification's requirement for that token. DHCP root-path and NBFT data are not consistent about its case. -
The API name
NVME_CAP_NSSRC()changed toNVME_CAP_NSSRS(). Since the CAP property NVM Subsystem Reset Supported bit symbol name is described as NSSRS by the spec then the API name was not correct.
Build
-
-Ddocs=manand-Ddocs=allinstall the man pages shipped inDocumentation/unless-Ddocs-build=trueis also given. The section 5 and 8 pages were never written there, so those builds failed to configure. They are regenerated from now on, and a release aborts if any page is missing. -
Building the man pages now requires
xmlto. It was optional, so a build with-Ddocs=man -Ddocs-build=trueand noxmltoinstalled succeeded and produced no man pages at all.
Changes in 3.0 (2026-09-07)
Feature removals and incompatible changes
-
A new INI-format connection configuration parser and writer have been added (
nvme-fabrics.conf+nvme-fabrics.conf.d/drop-ins, replacingconfig.json/discovery.conf). Seelibnvme/design/CONFIG.mdfor the format. Existing configuration can be explicietly converted by 'nvme config convert' or implicitly by the first call of any fabric command. -
Key management has moved into a new
nvme keysplugin.gen-dhchap-key,check-dhchap-key,gen-tls-key,check-tls-key, andtls-keyare nownvme keys gen-kxchap-secret,check-kxchap-secret,gen-tls-psk,check-tls-psk,insert-tls-psk,import,export, andrevoke. The old commands still work as deprecated aliases, exceptcheck-tls-key --insert, which has no equivalent there. Usenvme keys insert-tls-pskinstead. TheDH-HMAC-CHAPnaming is also renamed toKX-HMAC-CHAPthroughout, matching TP4201. Seenvme-keys-gen-kxchap-secret(1)andnvme-keys-check-kxchap-secret(1). -
NVMe Base Specification 2.4 (ECN122) renames the Reservation Report data structures from "Registered Controller" to "Registrant" throughout.
struct nvme_registered_ctrlandstruct nvme_registered_ctrl_extare nowstruct nvme_registrantandstruct nvme_registrant_ext; theregctl/regctl_ds/regctl_edsfields ofstruct nvme_resv_statusare nowregstrnt/registrant_ds/registrant_eds.nvme resv-reportoutput changes to match: theregctl/regctls/regctlextlabels and JSON keys are nowregstrnt/registrants/registrantext. Update any code or scripts that reference the old names. -
NVMe Base Specification 2.4 (TP4150) renames the "Namespace Attribute Changed" asynchronous event to "Attached Namespace Attribute Changed", the "Changed Namespace List" log page to "Changed Attached Namespace List", and the "Namespace Attribute Notices" notice to "Attached Namespace Attribute Notices" (to distinguish them from the new Allocated Namespace variants added alongside them).
NVME_AER_NOTICE_NS_CHANGEDis nowNVME_AER_NOTICE_ATTACHED_NS_CHANGED,NVME_LOG_LID_CHANGED_NSis nowNVME_LOG_LID_CHANGED_ATTACHED_NS, andNVME_CTRL_OAES_NA*is nowNVME_CTRL_OAES_NSAN*(matching the spec's new OAES mnemonic).nvme discover --log-id=changed-nsstill works as a deprecated alias for the newchanged-attached-ns. -
NVMe Base Specification 2.4 (TP4193) renames the "Create Exported NVM Subsystem" and "Manage Exported NVM Subsystem" admin commands to "Manage Exported NVM Subsystem Receive" and "...Send" respectively.
nvme_admin_create_export_nvmsis nownvme_admin_manage_export_nvms_receive, andnvme_admin_manage_export_nvmsis nownvme_admin_manage_export_nvms_send. The opcode values (0x2a, 0x2d) are unchanged. -
NVMe Management Interface Specification 2.2 (TP6039) adds a Controller Health Status Changed Flags field to the Controller Health Data Structure, and renames the NVM Subsystem Health Data Structure's Composite Controller Status field to Composite Controller Status Flags, to distinguish per-bit change flags from the status/state bits they report. In libnvme,
struct nvme_mi_ctrl_health_statusgains achscffield (andenum nvme_mi_chscf) carved out of what was previously trailing reserved space, so its size is unchanged; andstruct nvme_mi_nvm_ss_health_status'sccsfield/enum nvme_mi_ccsare renamed toccsf/enum nvme_mi_ccsfwith bit names getting anFsuffix (e.g.NVME_MI_CCS_RDYis nowNVME_MI_CCSF_RDYF) and a newTCIDAFbit. -
nvme gen-dhchap-keyemits the secret it was given rather than the key transformed from it, so its output differs whenever--hmacis non-zero.--nqn/-nfed only that transform and is now accepted with a warning and ignored. Seenvme-gen-dhchap-key(1). -
nvme gen-dhchap-keyrejects a--secretwith an odd number of hexadecimal characters. nvme-cli 2.x padded the trailing one with a zero and emitted a secret that was never given: 63 characters ending...bababaproduced...ababab0a. -
nvme check-tls-keyused to print the TLS PSK identity as the only line on stdout; it now printsConfigured PSK is valid (HMAC <id>, length <len>)first, the identity second, and whether that identity is already in the keyring third, so a script reading the identity withhead -1gets the wrong line. Its--insert/--keyfileare gone; usenvme keys insert-tls-psk. Seenvme-check-tls-key(1). -
nvme gen-tls-keyrejects a--secretwith an odd number of hexadecimal characters, reportsInserted TLS PSK <serial>where 2.x saidInserted TLS key <serial>, and prints its--secretdiagnostics -- includingSkipping excess secret bytes-- to stdout ahead of the key rather than to stderr. Seenvme-gen-tls-key(1). -
nvme check-dhchap-keyreports on the secret rather than on the key:Key is valid,Key is loadedandKey is not loadedare nowSecret is ..., and the validation errors say secret where they said key. Exit codes are unchanged, but a script matching the old wording needs updating. Seenvme-check-dhchap-key(1). -
All
nvme *-logcommands (smart-log,ana-log,error-log,fw-log,telemetry-log,self-test-log,sanitize-log, and the rest of the get-log-page family,get-logexcepted) have moved into a newnvme logplugin, dropping the redundant-logsuffix, e.g.nvme smart-logis nownvme log smart. The old top-level commands still work as deprecated aliases. -
All
nvme id-*/nvm-id-*/list-*Identify commands (id-ctrl,id-ns,id-ns-granularity,id-ns-lba-format,list-ns,list-ctrl,nvm-id-ctrl,nvm-id-ns,nvm-id-ns-lba-format,primary-ctrl-caps,list-secondary,cmdset-ind-id-ns,ns-descs,id-nvmset,id-uuid,id-iocs,id-domain, andlist-endgrp) have moved into a newnvme idplugin, e.g.nvme id-ctrlis nownvme id ctrl. The old top-level commands still work as deprecated aliases. -
Namespace management commands (
create-ns,delete-ns,attach-ns,detach-ns,get-ns-id) have moved into a newnvme nsplugin, e.g.nvme create-nsis nownvme ns create. The old top-level commands still work as deprecated aliases. -
nvme ns create,nvme ns delete,nvme ns attach, andnvme ns detach(and their deprecatedcreate-ns/delete-ns/attach-ns/detach-nsaliases) no longer print a confirmation message on success by default;nvme ns createalso no longer prints the assignednsid. Both are now gated behind-v/--verbose. The exit code alone indicates success/failure; the assignednsidcan still be found withnvme ns listornvme id ctrl. Seenvme-ns-create(1). -
Reservation commands (
resv-acquire,resv-register,resv-release,resv-report) have moved into a newnvme resvplugin, e.g.nvme resv-acquireis nownvme resv acquire. The old top-level commands still work as deprecated aliases. -
NVMe-MI commands (
nvme-mi-recv,nvme-mi-send) have moved into a newnvme nvme-miplugin, e.g.nvme nvme-mi-recvis nownvme nvme-mi recv. The old top-level commands still work as deprecated aliases. -
I/O Management commands (
io-mgmt-recv,io-mgmt-send) have moved into a newnvme io-mgmtplugin, e.g.nvme io-mgmt-recvis nownvme io-mgmt recv. The old top-level commands still work as deprecated aliases. -
Directive commands (
dir-receive,dir-send) have moved into a newnvme dirplugin, e.g.nvme dir-receiveis nownvme dir receive. The old top-level commands still work as deprecated aliases. -
Security Send/Receive commands (
security-send,security-recv) have moved into a newnvme securityplugin, e.g.nvme security-sendis nownvme security send. The old top-level commands still work as deprecated aliases. -
Firmware commands (
fw-commit,fw-download) have moved into a newnvme fwplugin, e.g.nvme fw-downloadis nownvme fw download. The old top-level commands still work as deprecated aliases. -
The RPMB command has moved into a new
nvme rpmbplugin and, since RPMB is not part of the NVMe base specification, has been split into one subcommand per action instead of a--cmd=<action>flag:nvme rpmb --cmd=infois nownvme rpmb info, and likewiseprogram-key,read-counter,read-data,write-data,read-config, andwrite-config. Unlike the other command moves above, the oldnvme rpmb --cmd=...form no longer works at all; there is no deprecated alias. Seenvme-rpmb-info(1)and friends. -
Deprecated commands (currently the old
nvme keys,nvme log,nvme id,nvme ns,nvme resv,nvme nvme-mi,nvme io-mgmt,nvme dir,nvme security, andnvme fwaliases above) are enabled by default; they can be turned off at build time with-Ddeprecated-cmds=disabled.nvme helpnow lists them in a separate "deprecated" section instead of alongside current commands, and running one prints a warning that it will be removed in the next major version. -
The project now builds with
-std=gnu11instead of-std=gnu99, raising the minimum required compiler support from C99 to C11. A toolchain new enough for C11 is now required to build nvme-cli and libnvme. -
nvme disconnect-allwith no options no longer disconnects every fabric controller. It now only disconnects controllers with no recorded owner in the new ownership registry. A controller owned by another orchestrator is silently skipped. To restore the old disconnect-everything behavior. -
libnvme itself no longer resolves hostnames.
libnvmf_add_ctrl()andlibnvmf_connect_ctrl()now fail immediately on a hostname traddr/host_traddr instead of resolving it internally. The caller is responsible for resolving first. -
--dump-confighas been removed fromnvme discover,connect-all, andconnect. -
In libnvme, the per-command
nvme_<cmd>()wrapper functions and theirstruct nvme_<cmd>_argsargument bundles have been replaced by annvme_init_<cmd>()helper that fills a caller-ownedstruct libnvme_passthru_cmd, submitted separately withlibnvme_exec_admin_passthru()/libnvme_exec_io_passthru()(or the async equivalents). -
The public NBFT parsing API has moved from the
libnvme_*namespace tolibnvmf_*, and every function now takes the global context as its first argument (for example,libnvmf_read_nbft(ctx, ...)). Update both the prefix and the call signature. -
The
-Dpdc-enabledmeson build option has been removed. Whether a discovery controller connection is kept persistent is now decided at runtime, via--persistent/nvme-fabrics.conf, not at build time.
New: Windows support
- nvme-cli and libnvme now build and run on Windows (MSYS2 UCRT64).
Direct PCIe access via ioctl works; NVMe-oF fabrics, MI,
nvme-discoverd, and
nvme topare not yet available on this platform.
New: nvme top
nvme topis a new interactive,top-like dashboard for NVMe devices. It lists subsystems and lets you drill into one to see live namespace, path, and controller stats, including command retry/error counts and multipath failover/reconnect counts.
New: ownership registry and exclusion list
-
A new ownership registry (
nvme registry, backed by/run/nvme/registry/) records which orchestrator owns each connected controller. This is what letsdisconnect-all(above) and future orchestrator tooling avoid tearing down a connection another component depends on. Seelibnvme/design/REGISTRY.md. -
A new system-wide exclusion list (
nvme exclusion, backed by/etc/nvme/exclusions.confandexclusions.conf.d/drop-ins) lets an administrator block specific controls from being auto-connected. It's aimed primarily at auto-discovered controllers, which have no config entry to remove in order to suppress an unwanted connection. Seelibnvme/design/EXCLUSIONS.md.
nvme-cli
-
A new global config file,
/etc/nvme/nvme-cli.conf, sets machine-wide defaults for global options like--timeout,--output-format,--no-retries, and--no-ioctl-probing. Seenvme-cli.conf(5). -
nvme disconnectnow accepts the same identifying options asnvme connect(--nqn,--transport,--traddr,--host-iface,--hostnqn,--hostid). A new-x/--excludealso writes a matching entry to the exclusion list before disconnecting. Seenvme-disconnect(1). -
nvme utils dump-command-metadataprints the full command and option tree as JSON. It is meant to drive shell-completion generation. -
nvme connectgained--idempotentand--devid-file.--idempotentmakes connecting to an already-connected controller succeed instead of erroring.--devid-filewrites the resultingnvmeXdevice name to the given file on success, so a caller that doesn't know the device name at connect time (for example, a systemd unit spawned before the device exists) can look it up afterward instead of scrapingdmesgor polling sysfs. -
nvme config-convertconverts the legacyconfig.jsonanddiscovery.conffiles to the new INI-formatnvme-fabrics.conf. By default it reads the system paths and writes to/etc/nvme/nvme-fabrics.conf.--configoverrides theconfig.jsonpath,--outputthe destination, and--forceallows overwriting an existing target. On success each converted legacy file is renamed to<name>.convertedso running the command again is a safe no-op. Seenvme-config-convert(1).
libnvme
-
The library has been renamed from libnvme to libnvme3, and the previously separate libnvme-mi has been merged into it. The shared library SONAME is
libnvme3.so.1. Headers install underinclude/libnvme3/and man pages under a versioned path, enabling parallel installation alongside libnvme v1 packages. The Python binding is now namedlibnvme3. Packages, build systems, and Python scripts that reference the library, its headers, or the Python module by name must update. -
nvme-fabrics.confentries can now record apersistentsetting per discovery controller, matching the--persistentCLI option. -
New diagnostic accessors report per-path, per-namespace, and per-controller command retry/error counts, multipath failover count, and controller reset/reconnect counts. These are always read live rather than cached, and back
nvme top. -
The Python bindings' object-oriented surface has been polished:
connected()andis_registration_supported()are now read-only properties (connected,registration_supported),registration_ctrl()is renamedregistration_control(), andset_symname()has been removed. Sethost.hostsymnamedirectly instead. -
The NBFT parser has been updated for NVMe Boot Specification rev. 1.3, including Security Profile Descriptors, and hardened against malformed or malicious NBFT ACPI tables.
-
ioctl version probing is now deferred until the first command on a transport handle, instead of happening eagerly on open. The probe prefers the 64-bit ioctl and falls back to the 32-bit one only if it isn't supported; the result is cached per handle. The new
--no-ioctl-probingglobal option skips probing and forces the 32-bit ioctl. -
Controller and namespace sysfs attributes are now read lazily, on first access, instead of all at once when the topology tree is scanned. This cuts overhead when scanning large fabric setups.
-
Connect and discover now share a common
struct libnvmf_contextinternally, replacing the old discovery-only context. Relevant to developers extending the fabrics API, not to CLI end users. -
A new internal
shared/static library holds code with no natural home in nvme-cli, libnvme, nvme-discoverd, or the Python bindings (INI parsing, base64, CRC32, filesystem/network helpers). -
Read-only Python bindings for the new config format (
config_read(),config_validate()) are available now for early adopters (e.g. nvme-stas) that want to start reading the new format ahead of the CLI's own switch-over. -
The accessor generator that produces libnvme's getter/setter boilerplate (
accessors.c/.h) has been rewritten in Python, with the struct annotations it reads now living in-source inprivate.hinstead of a separate spec file. Relevant to developers extending libnvme's public structs, not to CLI end users. -
<nvme/nvme-cmds.h>and<nvme/nvme-types.h>have each been split into per-spec-section sub-headers (nvme-cmds-base.h,nvme-cmds-fabrics.h,nvme-cmds-mi.h, similarly for nvme-types). The top-level headers still exist and include all sub-headers, so code that includes them is unaffected. Code that already included a sub-header by its old combined-file path must update the include path. -
nvme_root_thas been replaced bystruct libnvme_global_ctx *throughout the public API. Code that stored or passednvme_root_tmust update to the new type. -
A new transport handle abstraction (
struct nvme_transport_handle,libnvme_transport_handle_*) decouples command issuing from the underlying transport. A handle may wrap either a direct ioctl file descriptor or an MI endpoint. -
An explicit async passthru API has been added.
libnvme_submit_admin_passthru()/libnvme_submit_io_passthru()submit a command without waiting;libnvme_wait_passthru()/libnvme_reap_passthru()collect the result later. The synchronous path islibnvme_exec_admin_passthru()/libnvme_exec_io_passthru(). -
libnvmf_host_get_ids()has been promoted from an internal helper to a public API. It resolves the hostnqn and hostid from all available sources and is the recommended way for callers to obtain host identity before connect or discover. -
The implicit hostnqn/hostid lookup inside the fabrics connect and discover code paths has been removed. Callers must now resolve host identity before connecting; use the newly public
libnvmf_host_get_ids()helper or set values explicitly withlibnvme_global_ctx_set_hostnqn()/libnvme_global_ctx_set_hostid(). -
The
sizeof_argsbackward-compatibility macro and the old struct-based command-argument shim have been removed. The macro returned incorrect values on 32-bit architectures; there is no intention to fix it. -
The platform-specific filter helpers (
nvme_filter_*) are no longer exported from libnvme. Only thelibnvme_scan_*interfaces remain public. Plugins that called filter helpers directly must be updated to use the scan API. -
libnvme_ctrl_match_config()has been removed. It was exported but had no callers outside the library. -
libnvmf_ctrl_get_fabrics_config()has been removed. The individual field accessors generated by the new accessor machinery provide equivalent access without exposing the internal nested struct. -
nvme_mi_ctrl_thas been removed. MI functionality is now accessed throughstruct nvme_transport_handle, the same abstraction used for direct ioctl access; the transport is chosen at handle construction.nvme_mi_admin_identify()andnvme_mi_admin_identify_partial()are gone; uselibnvme_ctrl_identify()with a transport handle opened for MI. -
Several deprecated identifiers have been removed for 3.0: the duplicate
NVME_SC_FEAT_IOCS_COMBINATION_REJECTEDdefine, the old notification-mask enum names, MI backward-compatibility#defines, andnvme_cmd_get_log_telemetry_host_lsp(renamed tonvme_log_telemetry_host_lsp). Update any code using these names. -
The environment-variable configuration knobs for libnvme have been removed.
LIBNVME_MI_PROBE_ENABLED,LIBNVME_TEST_BASE_DIR, and similar variables no longer have any effect. Replace them with explicit setter calls on the global context:libnvme_set_probe_enabled(),libnvme_set_test_base_dir(),libnvme_set_test_sysfs_dir(),libnvme_set_force_4k(), etc.