-
The JSON output of
nvme show-regs,get-regandget-propertyhas one shape: the value of each register under its name, e.g.{"cc": 4587521}, with-van object of the value and its decoded fields. The values are unsigned. Before,get-regprinted{"register: 0x14": [{"name": "cc", "value": ...}]},get-propertythe value as a hex string,-vwrapped each register in a one element array, and a register with bit 31 set was negative. -
nvme show-regs,get-regandget-property -vdecode the fields of the registers as the specification names them, the same in the normal and the JSON output, which differed before. The composite fields CAP.CSS, CAP.AMS, CAP.CRMS and VS are split into their fields. The normal output ofshow-regsnames the Version registervs, like the JSON output and the options, instead ofversion. -
nvme set-regfalls back to a Property Set only for a controller whose registers can't be mapped, a fabrics controller. Before, it set the property after any failed write. It refuses a register the host may not write and a value too large for a 32 bit register, and fails without a register to write instead of doing nothing. -
nvme helpno longer lists the deprecated commands. They still work, with a warning. -
nvme-cli parses its command line itself instead of with getopt, so it behaves the same with every C library. Long options now need two dashes and their full name: single-dash long options such as
-verboseand abbreviations such as--namespacefor--namespace-idare no longer accepted. A single dash always starts short options, so-verboseis read as-v -e -r -b -o -s -e. Options and arguments can still be given in any order. -
Every command rejects an invalid
--output-formatvalue now, before it opens the device. Before, the commands which don't use the output format accepted any value. -
nvme <command> --help(also-hand-?) prints the help to stdout and exits with status 0. Before, it printed to stderr and exited with 1, like a usage error, which still does. -
Every command checks its operand: a command which takes a device fails without one, and an extra operand is an error. Before, extra operands were silently ignored, e.g. a device given to a command which takes none.
-
--persistent forcefails now. The value of an option which takes an optional value has to be attached to it:--persistent=forceor-pforce. A separate value was never applied:--persistent forceconnected in modeautoand droppedforcewithout a word, as the man pages ofdiscover,connect-allandconfig createsaid. Now it is an extra argument, which is an error. -
Options which take an unsigned number reject negative numbers now. Before,
-1wrapped around to the largest value. The values which have a special meaning got names instead: every namespace id option acceptsallfor 0xffffffff and--timeout(also innvme-cli.conf) acceptsinfinite. Both still accept-1. The help lists the names of an option.lm migration-recvrequires--selnow, like the other lm commands. -
--selofget-feature, thefeatcommands and theocpandshannoncommands which get a feature rejects numbers above 3 and accepts the namescurrent,default,savedandsupported. Before, it sent the reserved values 4 to 7 and truncated larger values.--output-format-version(also innvme-cli.conf) rejects versions other than 1 and 2. Before, every version but 2 printed version 1. -
Numbers on the command line and in
nvme-cli.confare parsed strictly:- Text after the number is rejected. Before, the rest was ignored:
--timeout=10sset a timeout of 10 milliseconds. - Leading whitespace, a
+and a leading zero are rejected, also in the lists of numbers. Before, a leading zero made a number octal:--namespace-id=010was namespace 8 and08was rejected. Write10, or0x10for hexadecimal;0itself is fine. - A signed option rejects a value out of its range instead of wrapping around.
- A floating point option takes a
.as decimal point in any locale and rejectsnanandinf. - Sizes with a suffix (
4Ki,1.5G) reject a value which overflows, take the digits after a.in decimal (1.09kwas rejected as octal,1.500kwas 1000), and use a.in any locale as well. - An empty value no longer selects a value name.
- Text after the number is rejected. Before, the rest was ignored:
-
Errors and warnings which repeat a command line argument or a line of a config file write its control characters as
\xNN, so it can't send escape sequences to the terminal. -
Global options mean the same for every command now: they are looked up before the options of a command, and no command uses their names any more.
- The own
--human-readable(-H) offdp configs,lm migration-recv,shannon get-additional-featureandzns id-ns, and the own--verbose(-V) ofsndkandwdc vs-internal-log,sed discoverandzns report-zonesare gone; the global--verbose(-v) does their job.-Vis no longer accepted by these commands. - These options lost their short name, which a global option uses:
config convert --outputandrpmb read-data/write-data --address(-o),feat arbitration --hpw,feat temp-thresh --thsel,feat host-behavior-support --hdisns,lm set-cdq --hp,nbft show --hfiandsamsung vs-internal-log --hide-progress(-H). --human-readableand-H, the old spelling of--verbose, print a deprecation warning.
- The own
-
A usage error prints the error, the synopsis and where to find the help instead of the whole help, which buried the error. A bad value names the option as it was given and the values it takes:
fw commit: invalid value 'x' for -s: expected a number from 0 to 255 Usage: nvme fw commit <device> [OPTIONS] Try 'nvme fw commit --help' for more information.The other errors of a command start with its name as well, e.g.
id ns: /dev/nvme0: Permission denied, and a device which can't be opened prints no help any more. An unknown command and a bad global option point tonvme --helpinstead of printing the general help, which also followed a command that failed with ENOTTY. On a terminal, that name is red and the WARNING of a warning yellow. SetNO_COLORto a non-empty value to turn colors off (https://no-color.org/). -
Options which take one of a few words check the word while parsing the command line, in any case and as a unique prefix like every value name, and the help and the completions list the words:
show-topology --ranking,memblaze select-download --select,micron select-download --select, the--optionof the micronvs-smbus-option,latency-trackingandvs-telemetry-controller-option, the micron--commandoflatency-trackingandlatency-stats,micron vs-internal-log --type,ocp internal-log --telemetry-type, the--typeof thesndkandwdcvs-internal-logandsolidigm internal-log --type. An unknown word is a usage error which lists the words.ocp internal-logwith an unknown telemetry type failed with status 0 before.samsung vs-internal-log --dump-typechecks its list of dump types the same way, before it opens the device, and may be given more than once; the completions complete the type after the last comma. -
The help of
connect,discover,connect-all,disconnectandconfig createlists the fabrics options they share under "Fabrics options", and the help of thefeatcommands--saveand--selunder "Feature options". -
The command metadata (
nvme utils dump-command-metadata) marks deprecated commands with the command which replaces them, deprecated options with the option which replaces them, and renamed options with their old name. -
The old option names
--dhchap-secret,--dhchap-ctrl-secretand--fast_io_fail_tmoof the fabrics commands and--forceofdiscoverandconnect-allprint a deprecation warning which names the option to use instead. -
The deprecated
tls-keycommand parses its options like every other command: it has a help, and abbreviated options such as--keyrare no longer accepted. It,gen-dhchap-keyandcheck-dhchap-keyreject extra operands now instead of dropping them. -
The human-readable stdout output of
id-ctrl,id-ns, and most other identify/log-page/feature commands is now rendered through a computed-width table instead of hand-alignedprintf()calls. Field names, values, and decoded bit breakdowns are unchanged, but column widths, spacing, and blank lines around them may differ from previous releases. stdout was never a stable, parseable interface; scripts that depend on its exact layout should switch to--output-format=json(-o json), which this change does not affect. -
The ScaleFlux plugin no longer supports the proprietary ScaleFlux kernel driver used with CSD 2000 drives. nvme-cli does not support proprietary kernel modules. The clean card feature is removed.
-
nvme discover,nvme connect-allandnvme config create --discoverynow default--persistenttoautoinstead ofno. With this, the discovery controller stays connected after the log page fetch wherever the target reports EPCSD for that discovery log page entry. That lets the host automatically react to discovery AENs received on that discovery connection. Targets without EPCSD enabled remain unaffected. Opt out with--persistent=no.config create --discoveryand converteddiscovery.conflines now recordpersistent = auto. Seenvme-discover(1)andnvme-config-create(1). -
nvme-discoverd is now built and installed by default, and it replaces the legacy udev/systemd NVMe-oF autoconnect. The daemon connects the controllers from the NBFT, from the fabrics configuration (
nvme-fabrics.conf(5)) and from the Discovery Log Pages of the Discovery Controllers it connects to, including FC kickstart. It also keeps them connected and retries failed connections with backoff. For a Discovery Controller without an owner, for example one connected withnvme discover --persistent, it runsnvme connect-allon its events, as70-nvmf-autoconnect.rulesdoes. The new connections have no owner either. Seenvme-discoverd(8).The
nvme-discoverdandnvmf-autoconnectbuild options now both default toauto. nvme-discoverd is built when libsystemd v253 or later is available. The legacy autoconnect is built only when nvme-discoverd is not. To keep the old behavior, build with-Dnvme-discoverd=disabled.When nvme-discoverd is built, these legacy files are not installed:
70-nvmf-autoconnect.rules,nvmf-connect@.service,nvmf-connect.target,nvmf-autoconnect.service,nvmefc-boot-connections.service,nvmf-connect-nbft.service, the dracut config70-nvmf-autoconnect.confand the NetworkManager dispatcher script80-nvmf-connect-nbft.sh. The key provisioning and vendor tuning udev rules are still installed.-Dnvmf-autoconnect=enabledinstalls both. The legacy udev rules are active as soon as they are installed. nvme-discoverd runs only whennvme-discoverd.serviceis enabled. While nvme-discoverd is active,nvmf-autoconnect.serviceand the FC kickstart skip their connect step. -
libnvme: the Identify Controller bit field constants for the OAES, BPCAP, MEC, OACS, FRMW, LPA and AVSCC fields now use the field names from the NVM Express Base Specification, Revision 2.4. The old names are removed. Code that uses them must be changed:
NVME_CTRL_OAES_*:FAis nowFAN,ANAisANACN,PLEAisPLEAN,LBASisLSIAN,EGEisEGEAN,NSisNNSS,TTHisTTHR,ZDisZDCNandDLisDLPCN. This also applies to the_SHIFTand_MASKvalues. The accessor macrosNVME_CTRL_OAES_PLEALCN(),NVME_CTRL_OAES_LBASIAN(),NVME_CTRL_OAES_EGEALPCN()andNVME_CTRL_OAES_NNVMSS()are nowNVME_CTRL_OAES_PLEAN(),NVME_CTRL_OAES_LSIAN(),NVME_CTRL_OAES_EGEAN()andNVME_CTRL_OAES_NNSS().NVME_CTRL_BACAP_*is nowNVME_CTRL_BPCAP_*.NVME_CTRL_MEC_SMBUSMEis nowNVME_CTRL_MEC_TWPME. The spec renamed the bit to 2-Wire Port Management Endpoint.NVME_CTRL_OACS_*:SECURITYis nowSSRS,FORMATisFNVMS,FWisFWDS,NS_MGMTisNMS,SELF_TESTisDSTS,DIRECTIVESisDIRS,NVME_MIisNSRS,VIRT_MGMTisVMS,DBBUF_CFGisDBCS,LBA_STATUSisGLSS,CMD_FEAT_LDisCFLS,HMLMisHMLMSandCTRL_SCOPED_CMD_FEAT_LDisCCFLS. The accessor macrosNVME_CTRL_OACS_NMS_M()andNVME_CTRL_OACS_VMS_M()are nowNVME_CTRL_OACS_NMS()andNVME_CTRL_OACS_VMS().NVME_CTRL_FRMW_*:1ST_ROis nowFFSRO,NR_SLOTSisNOFS,FW_ACT_NO_RESETisFAWRandMP_UP_DETECTIONisSMUD.NVME_CTRL_FRMW_NOFSalso covers bit 3 of the Number Of Firmware Slots field, whichNVME_CTRL_FRMW_NR_SLOTSmissed.NVME_CTRL_LPA_*:SMART_PER_NSis nowSMARTS,CMD_EFFECTSisCSES,EXTENDEDisLPEDS,TELEMETRYisTS,PERSETENT_EVENTisPES,LI0_LI5_LI12_LI13isMLPSandDA4_TELEMETRYisDA4S.NVME_CTRL_AVSCC_AVSis nowNVME_CTRL_AVSCC_VSCF.
-
The
docs-buildoption is removed.-Ddocsalways installs the docs committed in the tree. The newupdate-docstarget regenerates them and copies them into the tree. Drop-Ddocs-build=truefrom the meson arguments: meson rejects an unknown option.
- nvme-cli and libnvme now build and run on FreeBSD. NVMe PCIe devices
are supported through the nvme(4) driver; NVMe-oF fabrics, MI,
nvme-discoverd, and
nvme topare not yet available on this platform.
-
Two technology previews reduce what a bug in the code which decodes the data of a device can do. Both are disabled by default. They are work in progress and may change, or be removed again if they turn out not to be useful or too complicated. See
Documentation/PRIVSEP.md.- Privilege separation (
-Dprivsep=enabled, Linux only): when root runs nvme-cli for a user, withsudoor withNVME_PRIVSEP_UIDset, nvme-cli startsnvme-privsep-helper, which keeps root, and drops its own privileges to that user. The helper issues the NVMe commands. Root withoutSUDO_UIDorNVME_PRIVSEP_UIDkeeps its privileges. Commands without a device, like the fabrics, keys and registry commands, and device commands which need root for other reasons still run as root. - Decoder sandbox (
-Dsandbox=enabled, Linux and FreeBSD): the printers which decode device data run in a child process which can do little more than allocate memory and write to stdout and stderr. A crash in a decoder only ends the child.NVME_SANDBOX=0turns it off,NVME_SANDBOX=1turns it on in a build without the option.
- Privilege separation (
-
New daemon, nvme-keysd, a technology preview: it will put NVMe/TCP TLS pre-shared keys into the kernel's .nvme keyring before a connection needs them. Built with the new
nvme-keysdmeson option,disabledby default. It imports the PSKs of the entries withtls-key-source = systemd-credsfrom encrypted systemd credentials in/etc/nvme/credsat boot, and exits. It does not start when no entry has a key source. It needs systemd 257 or later. Seenvme-keysd(8). -
New
tls-key-sourcekey innvme-fabrics.conf. Withtls-key-source = systemd-creds,tls-keyis the name of a systemd credential, not the key.nvme connect-alland nvme-discoverd then connect with TLS and let the kernel find the PSK in the keyring. The default,inline, keeps today's behavior. Seenvme-fabrics.conf(5).
-
nvme top -o jsonsamples the I/O statistics over--delayseconds and prints the rates and the error, retry, failover, reset and reconnect counters of the subsystems, namespaces, paths and controllers as one JSON document, for scripts and monitoring tools.nvme tophas a man page now, which describes the document. -
scripts/mcp/nvme-mcpis an MCP server on top ofnvme top -o json. It lets an agent watch the multipath I/O of a host: it flags paths which are not optimized, are slow compared with their siblings, get an uneven share of the I/O, or whose error counters go up. Started with--allow-iopolicy, it also changes the I/O policy of a subsystem and compares the policies under a running workload. Seescripts/mcp/README.md. -
nvme help <command>finds the command likenvme <command>does, also by a unique prefix, andnvme help <plugin> <command>shows the man page of a plugin's command. -
The shell completions offer a device only to commands which take one. The command metadata (
nvme utils dump-command-metadata) reports the device operand of each command as schema version 2. -
The global options (
--verbose,--output-format,--dry-run, ...) are accepted by every command.config validate,config status,config convert,intel lat-stats-tracking,memblaze lat-stats,memblaze smart-log-add-x,sndk vs-internal-log,wdc vs-internal-logand thesedcommands did not accept them. -
The command metadata reports the type of the value of each option and the range of numbers an option takes. The shell completions use them: they complete paths for every option which names a file or directory, now also the
--keyfileof the keys commands,--nbft-pathand the logs ofocp internal-log, and offer the values of--sel. They no longer offer 0 to 3 for the--selof thelmcommands, which means something else there. -
The help and the shell completions of
--output-formatlist the formats the command supports. Before, the completions offeredtabulareverywhere, and some commands listed formats they rejected. -
--dry-runnow also skipsnvme reset,nvme subsystem-reset,nvme ns-rescan, thenvme sedoperations which change the drive, and the fabrics connects and disconnects. Before, only NVMe commands were skipped: these still reset the controller or subsystem, rescanned the namespaces, connected and disconnected controllers, and withdry-runset in nvme-cli.conf the sed operations still ran.nvme connect --dry-run -vvshows the connect arguments instead.nvme discoverandnvme connect-allstop before connecting the Discovery Controller, as there is nothing to discover without a connection. -
nvme discoverandnvme connect-allnow send the keep-alive timeout to a persistent Discovery Controller. Before, the value was set too late. The DC got no keep-alive timeout, so it was never asked for a persistent connection or for AENs. -
nvme discoverandnvme connect-alladd the scope of a Discovery Controller connected through a scoped link-local IPv6 address, e.g.fe80::1%eth0, to the link-local addresses of its Discovery Log Page entries. Before, these had no scope, and on a host with more than one link the connect could use the wrong one. RDMA has nohost_ifaceto select the link. -
New option
nvme connect --discovery. It tells the kernel that the controller is a Discovery Controller, also when it has a unique NQN. -
nvme connectover TCP without--nr-io-queuesuses one I/O queue per queue of the network interface, at most one per online CPU. The interface is--host-iface, or else the one of the route to the target. Its queues are the combined channels plus the smaller of the RX and TX channels, asethtool -lshows them. With one queue, or if the count can't be read, the kernel default applies as before.nvme connect-alldoes the same for a connection ofnvme-fabrics.confwithoutnr-io-queues. -
nvme sed revertnow prints an extrarevert LSPerror when the kernel cannot revert the Locking SP.nvme sed passwordchecks at run time, not at build time, whether the kernel can set the SID password, and skips that step if it cannot. -
A device, or a fabrics target, which returns log pages whose lengths and counts don't add up no longer makes nvme-cli read past its buffers, loop for minutes or leak memory. This covers id-ctrl and the FDP, host and AVE discovery, pull model DDC request, power measurement, reachability, dispersed namespace, LBA status, changed namespace list and persistent event logs. Found by fuzzing the device data.
-
nvme log host-discovery,ave-discoveryandpull-model-ddc-reqread the records which follow the header now. Before, they printed zeros instead.host-discovery --all-host-entriesreads the header of the right page as well. -
nvme log reachability-groupsandreachability-associationsdecode every descriptor now. Before, only the first one was read from the right place. Their JSON output lists the IDs of a descriptor in an array,nsidandrgid. Before, all but the last ID were lost. -
nvme log persistent-eventfails for a log larger than 4 GiB, which it can't read, instead of printing a part of it as the whole log. -
nvme sanitize-nssends the Sanitize Namespace command to the namespace of the device, or to the one the new--namespace-idoption gives. Before, it sent it with NSID 0, which the controller rejects. -
nvme set-featuresends the timestamp of--valuelittle endian, and no longer in Command Dword 11. It refuses a value which doesn't fit: 32 bits, 48 for the timestamp. Before, it cut off the rest. -
nvme device-self-test --waitaborts the self-test on Ctrl-C again, and no longer waits for a self-test which is done before it reads the progress the first time. Without a self-test code, it fails when it can't read the progress, instead of reporting no running self-test. -
nvme sanitize --waitwaits for the estimated time on big endian hosts too, and no longer fails on a sanitize without an estimated time, like exit-failure, which is done.--repeat=0is refused. -
nvme formaton a controller without--namespace-idtells how to format a namespace or all of them. -
nvme read,writeandcomparerefuse a--data-sizeof more than 65536 logical blocks, which overflowed a buffer, and size the metadata for all blocks of--data-sizewithout--block-count. -
nvme copysends 0 as the expected reference tag of a range without--expected-ref-tags. Before, it was whatever was on the stack. -
nvme get-lba-statussends the namespace of the device without--namespace-id, instead of NSID 0, and refuses a--max-dwwhose data length doesn't fit 32 bits. -
nvme feat num-queues --nsqr=Nwithout--ncqrkeeps the current number of completion queues now. Before, it requested a single completion queue and a wrong number of submission queues. -
nvme feat perf-characteristicsno longer crashes after it sets the feature. It refuses an--attrlabove 4064 bytes, which overflowed a buffer, and sends the attribute length little endian. -
nvme feat arbitrationsets the feature only with the option of a field. Before, any option but--sel, like-o json, set it. -
nvme feat power-measgets the feature with--uuid-indextoo. -
nvme feat timestampclears the attributes of the timestamp it sets. Before, they were whatever was on the stack. -
nvme feat lba-range-typetakes--guidsas optional on every architecture, refuses a--numabove 63, which set 64 zeroed ranges, and shows its own description in its help. -
nvme fw commitreports a commit which needs a reset to activate the image as a success.nvme fw downloadandnvme security recvsend the--ishflag of an NVMe-MI command. -
nvme ns create --nsze-siand--ncap-sitake the namespace granularity of a format with extended metadata, and the LBA format on big endian hosts, right, and align to a granularity above 4 GiB. -
The
nvme znszone management commands andzone-appendwork again: they sent their I/O commands to the admin queue.zone-mgmt-recvrequires a--data-lenwhich is a multiple of 4 for each action, andzone-appendrefuses more than 65536 logical blocks and no longer overflows the metadata buffer. -
nvme resv reportreports a failed Identify Controller with its status, and fails. -
nvme io-mgmt recvrequires a--data-lenwhich is a multiple of 4, exits with success after writing the data to--data, and fails if it can't write all of it. -
nvme dir sendanddir receivedefault to the namespace of a namespace device, anddir sendrefuses an--endirabove 1. -
nvme get-reg --register=NAME[,NAME...]andnvme set-reg --register=NAME --value=VALname the registers, with completion of the names, and--offsetofget-reg,set-reg,get-propertyandset-propertytakes a name too, e.g.--offset=cc. The options of a register each of earlier versions, likeget-reg --ccandset-reg --cc=VAL, still work, but are deprecated. -
nvme show-regsandget-regon a fabrics controller show the properties in the right byte order on big endian hosts, and read the NSSD and CRTO properties too.show-regsleaves out the properties the controller doesn't implement, also in the JSON output. Before, it printed all registers of a PCIe controller, as -1 if they weren't properties. It fails for any other error of an optional property. -
nvme get-regandget-propertyon a fabrics controller fail for a property the controller doesn't implement, andget-regfor a register which is no property. Before, they showed it as all ones, or failed only if the status had the DNR bit set.get-regprints the status of a failed Property Get, and refuses an--offsetwhich is no register, which read past a buffer from 0x1000 on. -
nvme show-regs --verboseprints the CRTO timeouts in milliseconds. Before, it dropped the half seconds.
-
The JSON output of
nvme wdc vs-smart-add-logprints the counters, averages and percentages of the C1 performance statistics as 64 bit values. Before, a value above 2^31 - 1 came out wrapped. -
The wdc plugin no longer creates its dump directories with a broken mode that only root could write to.
-
Fixed root command injection in WDC (
vs-internal-log,drive-essentials, SN730 capture) and SanDisk (telemetry capture): a caller-controlled string reached a shell (system()), so a crafted input could run arbitrary commands as root. -
nvme seagate vs-smart-add-logprints the SMART logs of a drive once. Before, it printed those of legacy drives twice and those of other drives followed by logs which aren't theirs, and its JSON output could crash. -
The dera, ibm, memblaze, ocp, seagate, solidigm and wdc plugins handle unexpected values from the device and free the memory they used.
-
WDC, SanDisk, Micron, Solidigm and Samsung plugins no longer spawn external
tar,zip,cat,lsmod,unameordmesgprocesses; they use libarchive or direct syscalls instead.
-
meson installno longer installsnvme-discoverd.conf, which overwrote the admin's settings. It installs a commentednvme-discoverd.conf.sampleinstead; copy it tonvme-discoverd.confto change a setting. Without the file, every setting keeps its default. -
Discovery Controllers are now connected with
--discoveryand a keep-alive timeout of 30 s, or the configuredkeep-alive-tmo. No keep-alive timeout is used forpersistent = no. -
epcsd-poll-interval-minutes,fc-kickstart-interval-minutesanddc-giveup-timeoutmove from[Global]to a new[Discovery]section innvme-discoverd.conf. In[Global], they are now ignored with an "unknown key" warning. Seenvme-discoverd(8). -
nvme-discoverd can discover Discovery Controllers through mDNS (TP8009), using systemd-resolved. It is off by default. Enable it with
zeroconf = truein the[Discovery]section. The newmdnsbuild option (autoby default) controls whether mDNS support is built. It requires libsystemd v258 or later. -
nvme-discoverd releases a controller it no longer wants, for example one removed from the configuration or from a DC's log page, or one the exclusion list now matches. It clears the registry owner and leaves the connection up. It no longer connects the IOCs of a DC that another orchestrator connected. After a restart, it reconnects the DCs it found through mDNS. A DC configured with a
persistentsetting now connects. -
nvme-discoverd also compares the host ID, not only the host NQN, when it matches a desired connection with an existing one.
-
nvme-discoverd adds the IPv6 scope to link-local addresses. For a Discovery Log Page entry, the scope comes from the Discovery Controller's own address. For an mDNS result, it is the interface. RDMA needs this, because it has no
host_ifaceto select the link. -
A connection unit of nvme-discoverd no longer disconnects another controller that reuses its device name. The unit records the sysfs inode of its device at connect time and disconnects only if the inode still matches. At startup, nvme-discoverd removes the state of controllers that are gone.
-
At shutdown, a connection unit of nvme-discoverd disconnects only after the file systems mounted with
_netdevare unmounted. Before, it could disconnect a controller while its file system was still mounted. A file system on an NVMe-oF namespace needs_netdevin fstab. -
nvme-discoverd resolves the host names in
nvme-fabrics.confin parallel, without blocking. Before, it resolved them one at a time, and a slow DNS server stopped the daemon. A failed lookup is tried again, first after 1 s, then less often, up to every 5 minutes. Before, the connection was skipped until the next reload. While the first lookups run, nvme-discoverd does not release any controller.
-
Built with liburing, libnvme sends a passthru command through io_uring only where the kernel takes it: admin commands on the char device of a controller, I/O commands on that of a namespace, and nothing on a block device. Before, every command on a namespace block device (
/dev/nvme0n1) failed with "Invalid argument", and every admin command on a namespace char device (/dev/ng0n1) with "Inappropriate ioctl for device". -
A failed read of
/dev/nvme-fabricsis no longer cached for the life of the global context, so a later connect retries it. -
New
libnvmf_kernel_option_supported()andlibnvmf_kernel_options_for_each()report the fabrics options the kernel lists in/dev/nvme-fabrics. -
The
libnvme3.pcpkg-config file now reports the nvme-cli release version, e.g. 3.2. Before, it reported the library ABI version, 1.0.0 in every release. A project can now require a release with, for example,libnvme3 >= 3.2. The ABI version and the soname (libnvme3.so.1) do not change. -
A discovered controller gets the KX-HMAC-CHAP secrets (
kxchap-secret,kxchap-ctrl-secret) of the[Subsystem]or[Discovery Controller]section innvme-fabrics.confwith the same NQN, in the file of the Discovery Controller that reported it. This applies tonvme connect-alland nvme-discoverd. A section with nocontroller =line now has a use: it holds the secrets of a subsystem, wherever discovery finds it. Two sections with the same NQN in one file that set different secrets are rejected. Newlibnvmf_config_get_discovered_params()andlibnvmf_context_set_config(), andconfig_discovered_params()in the Python bindings. -
The Copy source range entries carry the Expected Logical Block Tags (ELBT), Application Tag (ELBAT) and Application Tag Mask (ELBATM) little endian again, as in 2.x, except the 80 bit ELBT of formats 1h and 3h, which stays big endian. 3.0 and 3.1 sent them big endian, which
nvme copy --expected-ref-tagsand--expected-app-tagsinherit. The byte order is not spelled out in the specification, see #4278.
-
New optional build dependency:
libarchive(WDC, SanDisk, Micron, Samsung and Solidigm archiving),autoby default. Without it, the affected subcommands fail with a clear error instead of depending on whatevertar/ziphappens to be onPATH. See BUILDING.md. -
The lm, sandisk, sed, wdc and zns plugins are now built on Windows. Without kernel Opal support,
nvme sedonly supportsdiscover.
-
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).
-
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.
-
-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.
-
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.
- 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.
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.
-
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.
-
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).
-
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.