libnvme 0.9.0

Safe, idiomatic Rust bindings for the Linux libnvme C library
Documentation
# libnvme-rs

[![crates.io](https://img.shields.io/crates/v/libnvme.svg)](https://crates.io/crates/libnvme)
[![docs.rs](https://docs.rs/libnvme/badge.svg)](https://docs.rs/libnvme)
[![CI](https://github.com/Cyberpsych0s1s/libnvme-rs/actions/workflows/ci.yml/badge.svg)](https://github.com/Cyberpsych0s1s/libnvme-rs/actions/workflows/ci.yml)
[![License](https://img.shields.io/crates/l/libnvme.svg)](#license)

Safe, idiomatic Rust bindings for the Linux [`libnvme`](https://github.com/linux-nvme/libnvme) C library — the userspace NVMe management library that backs `nvme-cli`.

> [!WARNING]
> **Alpha — API will change.** `0.x.y` releases break compatibility on
> minor-version bumps. Pin to an exact patch version (`libnvme = "=0.8.0"`)
> if you depend on this and don't want surprises. Linux-only; `libnvme`
> doesn't exist on Windows or macOS.
>
> Destructive admin commands (`Format NVM`, `Sanitize`,
> `delete_namespace`, `fw_commit`, `Lockdown`, and the I/O commands
> `write_uncorrectable` / `write_zeroes`) **permanently mutate or destroy
> data**. Every destructive entry point carries a `# Warning` block in
> its rustdoc; read it before calling. Verify against the QEMU fixture
> in [`tests/qemu/`]tests/qemu/ before pointing at real hardware.

```sh
cargo add libnvme
```

```rust
use libnvme::Root;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let root = Root::scan()?;
    for host in root.hosts() {
        for subsys in host.subsystems() {
            for ctrl in subsys.controllers() {
                println!("{} {}", ctrl.name()?, ctrl.model()?);
                for ns in ctrl.namespaces() {
                    println!("  {} ({} bytes)", ns.name()?, ns.size_bytes());
                }
            }
        }
    }
    Ok(())
}
```

A more complete `nvme list`-style example lives at [`libnvme/examples/list_nvme.rs`](libnvme/examples/list_nvme.rs):

```sh
cargo run --example list_nvme -p libnvme
```

## Verification status

The crate is young. Coverage shape as of `v0.8.0`:

| Surface | Verification |
| --- | --- |
| Enumeration (tree walk, properties) | Examples (`scan`, `list_nvme`), QEMU smoke tests, CI |
| Identify / SMART / Error log / FW slot | Examples (`id_ctrl`, `smart_log`, `fw_info`), QEMU |
| Get / Set Features (69 methods) | Compiles + runs against libnvme 1.8 in CI; no per-feature smoke test yet |
| Format NVM | `examples/format_smoke.rs` against QEMU only (model-name safety latch) |
| NVM I/O (`read`/`write`/`compare`/`verify`/`write_zeroes`/`dsm`/`flush`) | `examples/io_smoke.rs` — full round-trip against QEMU NVMe |
| Sanitize / Lockdown / Self-Test / Security S/R / FW download+commit / NS mgmt | Compiles; not yet exercised by automated tests |
| Fabrics (Connect / Discovery / Disconnect / auth) | Compiles; not yet exercised by automated tests (would need a target) |

Anything in the "compiles" tier should be considered alpha. Bug reports
welcome, particularly from anyone running these against real hardware
or a fabrics target.

## Requirements

- Linux x86_64 or aarch64
- `libnvme` ≥ 1.6 (`apt install libnvme-dev` on Ubuntu 24.04+; equivalent on Fedora/Arch)
- `clang` and `libclang-dev` for `bindgen` at build time
- Rust 1.85+ (`rust-version` in `Cargo.toml`)

## Workspace layout

| Crate | Purpose |
| --- | --- |
| `libnvme-sys` | Raw FFI bindings generated by `bindgen`. Use directly if the safe wrapper doesn't cover what you need. |
| `libnvme` | Safe, idiomatic Rust wrapper. All `unsafe` is audited here. |

## What's covered

### Enumeration and properties

- Enumerate the handle tree: hosts → subsystems → controllers → namespaces → paths
- Controller properties: name, model, serial, firmware, transport, address, state, plus sysfs fields (`numa_node`, `queue_count`, `sq_size`, `phy_slot`, `subsystem_nqn`, `traddr` / `trsvcid` / `host_traddr` / `host_iface`)
- Namespace properties: name, generic name, NSID, LBA size and count, metadata size, utilization, CSI, total size, UUID, NGUID, EUI-64, model/serial/firmware mirrors
- Subsystem properties: name, NQN, type, plus version-gated model/firmware/iopolicy/application/serial
- Host basic properties (HostID, NQN, etc.)
- Multipath / ANA `Path` iteration on both `Controller::paths` and `Namespace::paths`

### Admin commands (read)

- **Identify Controller** (`Controller::identify`) — vendor/subsystem IDs, NVMe spec version, FRU GUID, OACS, FRMW, LPA, NPSS, temperature thresholds, HMB sizes, TNVMCAP/UNVMCAP, NN, and more
- **Identify Namespace** (`Namespace::identify`) — size/capacity/utilization, NSFEAT, NLBAF, FLBAS, data-protection fields, NVMCAP, NGUID/EUI-64, per-format `LbaFormat` lookup
- **SMART / Health log page** (`Controller::smart_log`) — temperature, available spare, percentage used, data units read/written (u128), host commands, power cycles, power-on hours, unsafe shutdowns, media errors, per-sensor temperatures
- **Firmware Slot log page** (`Controller::fw_slot_log`) — active slot, next-activate slot, slot 1..=7 firmware revisions
- **Error Information log page** (`Controller::error_log`) — ring-buffer of recent error entries
- **Generic Get Log Page** (`Controller::get_log_page::<T>`) — fetch any fixed-size log page by LID
- **Get LBA Status** (`Controller::get_lba_status`) — NVMe 1.4+ LBA Status Descriptor query
- **Get Property** (`Controller::get_property`) — Fabrics controller register read

### Admin commands (destructive)

- **Format NVM** (`Namespace::format()` builder) — LBA-format selection, secure erase (None / UserData / Cryptographic), protection-info, metadata settings, timeout
- **Sanitize NVM** (`Controller::sanitize()` builder) — BlockErase / Overwrite / CryptoErase, AUSE, pass count, invert, pattern, NVMe 2.0 EMVS (version-gated)
- **Device Self-Test** (`Controller::self_test`) — Short / Extended / HostInitiated / Vendor-Specific / Abort
- **Firmware Download / Commit** (`Controller::fw_download`, `Controller::fw_commit`) — whole-buffer image transfer + slot/action selection
- **Namespace management** (`Controller::create_namespace`, `delete_namespace`, `attach_namespace`, `detach_namespace`) — full lifecycle on controllers that advertise OACS Namespace Management
- **Lockdown** (`Controller::lockdown`) — NVMe 2.0+ interface restriction
- **Set Property** (`Controller::set_property`) — Fabrics controller register write

### Get/Set Features (NVMe admin features)

- All 32 Set Features and 37 Get Features variants under `Controller::features()`: arbitration, power management, LBA range, temperature thresholds, error recovery, volatile write cache, number of queues, interrupt coalescing/config, async event, auto-PST, timestamp, HMB, KATO, HCTM, NOPSC, RRL, PLM config/window, host behavior, sanitize, endurance event, host ID, reservation mask/persistence, namespace write protection, IOCS profile

### Security

- **Security Send / Receive** (`Controller::security_send`, `security_receive`) — TCG Opal / Pyrite / arbitrary security protocol payloads

### Fabrics (NVMe-oF)

- **Host management**`Root::default_host`, `Root::lookup_host(hostnqn, hostid)`, plus free functions `generate_hostnqn`, `generate_hostid`, `hostnqn_from_file`, `hostid_from_file`
- **Connect** (`Host::connect(Transport, subsysnqn)` builder) — TCP / RDMA / FC / Loop, with chainable setters for traddr, trsvcid, host_traddr, host_iface, queue_size, nr_io_queues, keep_alive_tmo, reconnect_delay, ctrl_loss_tmo, hdr_digest, data_digest, tls, persistent, discovery
- **Disconnect** (`Controller::disconnect`) — tear down a fabrics connection
- **Reset** (`Controller::reset`) — controller reset
- **Discovery**`Controller::is_discovery_controller`, `Controller::discovery_log(max_retries)` returning a `DiscoveryLog` with iterable `DiscoveryLogEntry`
- **Authentication**`Controller::set_dhchap_host_key`, `set_dhchap_key`, `set_tls_key`, `set_tls_key_identity`, `set_keyring` (version-gated)
- **Persistence**`Controller::is_persistent`, `set_persistent`

### NVM I/O commands

- **Read** (`Namespace::read`, `read_to_vec`) — slice fast-path + owned-Vec convenience
- **Write** (`Namespace::write`)
- **Compare** (`Namespace::compare`) — host buffer vs. stored LBAs
- **Verify** (`Namespace::verify`) — controller-side integrity check, no host buffer
- **Write Zeroes** (`Namespace::write_zeroes`) — `.deallocate()` / `.no_deallocate_after_zero()`
- **Write Uncorrectable** (`Namespace::write_uncorrectable`)
- **Flush** (`Namespace::flush`)
- **Dataset Management** (`Namespace::dsm(DsmAttr).ranges(&[..])`) — the TRIM/UNMAP path
- **Copy** (`Namespace::copy(sdlba, &ranges)`) — multi-source copy with PI fields, FUA, directives
- Builders cover the full optional surface of `nvme_io_args`: FUA, Limited Retry, PI action/check-{ref,app,guard}, ref/app/storage tags, dataset-mgmt hints, directives (streams), per-command timeout, separate metadata buffer

### Reservations

- `Namespace::reservation_acquire` / `reservation_register` /
  `reservation_release` / `reservation_report` — multi-host shared-storage
  coordination. Typed enums for `ReservationType` (WE / EA / WERO / EARO /
  WEAR / EAAR), acquire / register / release actions, and `PtplChange`.

### Directives

- `Namespace::directive_send` / `directive_recv` — workload hints. Typed
  `DirectiveType` (Identify / Streams / Raw) and op enums.

### ZNS (Zoned Namespaces)

- `Namespace::zns_mgmt_send` — Open / Close / Finish / Reset / Offline /
  Set Descriptor Extension / ZRWA Flush
- `Namespace::zns_mgmt_recv` — Report Zones / Extended Report Zones with
  `ZoneReportFilter` (Empty / Open / Closed / Full / etc.)
- `Namespace::zns_append` — append-write to a zone, returns the
  assigned LBA

### Generic passthru (escape hatch)

- **`Controller::admin_passthru(args)`** and **`Controller::io_passthru(args)`** — issue any admin- or I/O-class command not yet exposed by a typed helper. Means *no missing function blocks a user* — drop down to passthru, drop down to `libnvme-sys` for raw bindings, or open an issue requesting a typed wrapper.

## Roadmap

| Version | Scope |
| --- | --- |
| 0.9 | API audit + stabilization pass + automated QEMU CI + per-feature smoke tests. No new API surface. |
| 1.0 | Ship the stabilized surface. **Coverage at this point: 122/122 of libnvme's extern functions, either typed or reachable via `admin_passthru` / `io_passthru`.** |
| 1.x | NVMe-MI as a sibling `libnvme-mi` crate; Key-Value command set once libnvme exposes it upstream. |

## Provider-Specific Quirks

Some drives may have issues that arise due to specific changes issued by their provider. If you feel this is the case with your drive, feel free to open an issue detailing the problem.

## Testing

There's a QEMU-based fixture in [`tests/qemu/`](tests/qemu/) that boots an Ubuntu 24.04 guest with a 1 GiB virtual NVMe controller attached as `/dev/nvme0`, so destructive operations (Format NVM, namespace create/delete, firmware commit) can be exercised against a real NVMe protocol stack without touching the host's drives. See [`tests/qemu/README.md`](tests/qemu/README.md) for the workflow.

## Contributing

See [CONTRIBUTING.md](CONTRIBUTING.md) for the build, test, and release
workflow, plus the conventions for adding new symbol probes and SAFETY
comments on `unsafe` blocks.

## Security

See [SECURITY.md](SECURITY.md). Soundness bugs and destructive-command
aliasing bugs should be reported privately via GitHub Security Advisories.

## License

`libnvme-rs` itself is dual MIT / Apache-2.0. The underlying `libnvme` C
library is **LGPL-2.1+**; any binary that links this crate also links
`libnvme`, and the resulting binary must comply with LGPL terms with
respect to `libnvme`. See [libnvme's `COPYING`](https://github.com/linux-nvme/libnvme/blob/master/COPYING)
for details. The MIT/Apache-2.0 dual-license on this crate covers
*only* the Rust wrapper code in this repository — it does not (and
cannot) launder the LGPL out of the linked `libnvme`.

Dual-licensed under either of:

- Apache License, Version 2.0 ([LICENSE-APACHE]LICENSE-APACHE)
- MIT License ([LICENSE-MIT]LICENSE-MIT)

At your option.