pub struct Subsystem<'r> { /* private fields */ }Expand description
An NVMe subsystem.
A subsystem groups one or more controllers that share a common identity (NQN, serial, model). For typical single-controller PCIe SSDs the subsystem has exactly one controller; Fabrics and multipath setups can have several.
Implementations§
Source§impl<'r> Subsystem<'r>
impl<'r> Subsystem<'r>
Sourcepub fn subsystem_type(&self) -> Result<&'r str>
pub fn subsystem_type(&self) -> Result<&'r str>
The subsystem type (e.g. nvm, discovery).
Sourcepub fn serial(&self) -> Result<&'r str>
pub fn serial(&self) -> Result<&'r str>
The subsystem-level serial number, when reported.
Only present when built against a libnvme that exposes
nvme_subsystem_get_serial. Older releases (notably the libnvme 1.8
shipped in Ubuntu 24.04) do not have this symbol; on those builds the
method is compiled out.
Sourcepub fn model(&self) -> Result<&'r str>
pub fn model(&self) -> Result<&'r str>
The subsystem-level model string, when reported.
Only present when built against a libnvme that exposes
nvme_subsystem_get_model.
Sourcepub fn firmware(&self) -> Result<&'r str>
pub fn firmware(&self) -> Result<&'r str>
The subsystem-level firmware revision, when reported.
Only present when built against a libnvme that exposes
nvme_subsystem_get_fw_rev.
Sourcepub fn iopolicy(&self) -> Result<&'r str>
pub fn iopolicy(&self) -> Result<&'r str>
ANA / multipath I/O policy for this subsystem, e.g. numa,
round-robin.
Only present when built against a libnvme that exposes
nvme_subsystem_get_iopolicy.
Sourcepub fn application(&self) -> Result<&'r str>
pub fn application(&self) -> Result<&'r str>
Application-set tag for this subsystem (used by tools like nvme-cli
for grouping). Empty when unset.
Only present when built against a libnvme that exposes
nvme_subsystem_get_application.
Sourcepub fn controllers(&self) -> Controllers<'r> ⓘ
pub fn controllers(&self) -> Controllers<'r> ⓘ
Iterate over the controllers in this subsystem.
Examples found in repository?
9fn main() -> Result<(), Box<dyn std::error::Error>> {
10 let root = Root::scan()?;
11 let mut any = false;
12 for host in root.hosts() {
13 for subsys in host.subsystems() {
14 for ctrl in subsys.controllers() {
15 any = true;
16 print_fw(&ctrl)?;
17 }
18 }
19 }
20 if !any {
21 println!("(no NVMe controllers found)");
22 }
23 Ok(())
24}More examples
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6 let root = Root::scan()?;
7 let mut any = false;
8 for host in root.hosts() {
9 for subsys in host.subsystems() {
10 for ctrl in subsys.controllers() {
11 any = true;
12 print_smart(&ctrl)?;
13 }
14 }
15 }
16 if !any {
17 println!("(no NVMe controllers found)");
18 }
19 Ok(())
20}5fn main() -> Result<(), Box<dyn std::error::Error>> {
6 let root = Root::scan()?;
7 let mut any = false;
8 for host in root.hosts() {
9 for subsys in host.subsystems() {
10 for ctrl in subsys.controllers() {
11 any = true;
12 print_controller(&ctrl)?;
13 }
14 }
15 }
16 if !any {
17 println!("(no NVMe controllers found)");
18 }
19 Ok(())
20}5fn main() -> Result<(), Box<dyn std::error::Error>> {
6 let root = Root::scan()?;
7
8 let mut rows: Vec<Row> = Vec::new();
9 for host in root.hosts() {
10 for subsys in host.subsystems() {
11 for ctrl in subsys.controllers() {
12 let mut had_namespace = false;
13 for ns in ctrl.namespaces() {
14 rows.push(Row::from(&ctrl, Some(&ns)));
15 had_namespace = true;
16 }
17 if !had_namespace {
18 rows.push(Row::from(&ctrl, None));
19 }
20 }
21 }
22 }
23
24 if rows.is_empty() {
25 println!("(no NVMe devices found)");
26 return Ok(());
27 }
28
29 print_table(&rows);
30 Ok(())
31}21fn main() -> Result<(), Box<dyn std::error::Error>> {
22 let root = Root::scan()?;
23 let mut formatted = 0;
24 for host in root.hosts() {
25 for subsys in host.subsystems() {
26 for ctrl in subsys.controllers() {
27 let model = ctrl.model().unwrap_or("?").trim();
28 if model != QEMU_MODEL {
29 println!(
30 "skipping {}: model {model:?} != {QEMU_MODEL:?} (refusing to format real hardware)",
31 ctrl.name()?
32 );
33 continue;
34 }
35 for ns in ctrl.namespaces() {
36 let nsid = ns.nsid();
37 let lba_size_before = ns.lba_size();
38 let lba_count_before = ns.lba_count();
39 println!(
40 "about to format {}: NSID={nsid}, {lba_count_before} blocks × {lba_size_before} B",
41 ns.name()?
42 );
43 ns.format()
44 .lba_format(0)
45 .secure_erase(SecureErase::None)
46 .execute()?;
47 println!(" -> format succeeded");
48 formatted += 1;
49 }
50 }
51 }
52 }
53 if formatted == 0 {
54 println!("(no QEMU virtual NVMe controllers found)");
55 } else {
56 println!("formatted {formatted} namespace(s)");
57 }
58 Ok(())
59}19fn main() -> Result<(), Box<dyn std::error::Error>> {
20 let root = Root::scan()?;
21 let mut exercised = 0;
22
23 for host in root.hosts() {
24 for subsys in host.subsystems() {
25 for ctrl in subsys.controllers() {
26 let model = ctrl.model().unwrap_or("?").trim();
27 if model != QEMU_MODEL {
28 println!(
29 "skipping {}: model {model:?} != {QEMU_MODEL:?} (refusing on real hardware)",
30 ctrl.name()?
31 );
32 continue;
33 }
34
35 for ns in ctrl.namespaces() {
36 let lba_size = ns.lba_size();
37 println!(
38 "exercising {} (NSID {}, {} B LBAs)",
39 ns.name()?,
40 ns.nsid(),
41 lba_size
42 );
43
44 // ---- Write one LBA with a recognizable pattern -----
45 let mut pattern = vec![0u8; lba_size as usize];
46 for (i, b) in pattern.iter_mut().enumerate() {
47 *b = (i & 0xFF) as u8;
48 }
49 ns.write(0, 1, &pattern).fua().execute()?;
50 println!(" write ok");
51
52 // ---- Read it back ---------------------------------
53 let got = ns.read_to_vec(0, 1)?;
54 assert_eq!(got, pattern, "read did not return the bytes we wrote");
55 println!(" read ok (round-trip matches)");
56
57 // ---- Compare (should succeed) ---------------------
58 ns.compare(0, 1, &pattern).execute()?;
59 println!(" compare ok");
60
61 // ---- Verify (controller-side integrity check) -----
62 ns.verify(0, 1).execute()?;
63 println!(" verify ok");
64
65 // ---- Write zeroes over the LBA --------------------
66 ns.write_zeroes(0, 1).execute()?;
67 let zeroed = ns.read_to_vec(0, 1)?;
68 assert!(zeroed.iter().all(|&b| b == 0), "expected all-zero LBA");
69 println!(" write_zeroes ok");
70
71 // ---- DSM deallocate (TRIM) ------------------------
72 ns.dsm(DsmAttr::DEALLOCATE)
73 .ranges(&[DsmRange::new(0, 1)])
74 .execute()?;
75 println!(" dsm(deallocate) ok");
76
77 // ---- Flush ----------------------------------------
78 ns.flush()?;
79 println!(" flush ok");
80
81 exercised += 1;
82 }
83 }
84 }
85 }
86
87 if exercised == 0 {
88 println!("(no QEMU virtual NVMe controllers found)");
89 } else {
90 println!("\nall I/O commands exercised on {exercised} namespace(s)");
91 }
92 Ok(())
93}