Read-only LVM2 Logical Volume reader for no_std environments — primarily UEFI bootloaders that need to mount a filesystem from a logical volume without pulling in a userspace LVM stack.
Vendored + modernized fork of main--/rust-lvm2. See PROVENANCE.md for the origin story and the full list of changes from upstream.
- Website: LamBoot, the bootloader lamlvm is maintained for
- Documentation: docs.rs/lamlvm and the LamBoot docs
- Repository: github.com/lamco-admin/lamlvm
- Company: Lamco Development LLC
Given any embedded_io::Read + Seek source that holds an LVM2 Physical Volume (typically a block device or partition):
- Finds the PV label (
LABELONE) in any of the first four sectors, checks its checksum, and parses the PV header. - Reads the Volume Group metadata text (LVM2 format-text) from the first metadata area whose header and committed text pass their checksums. An area marked ignored (
pvchange --metadataignore y) is skipped, since its text may be stale, and a PV with two areas falls back to the second when the first is ignored or damaged. - Enumerates the Logical Volumes in the VG.
- Returns each LV as an
OpenLVthat itself implementsembedded_io::Read + Seek, with offsets mapped from LV space to PV space via the segment table.
Existing filesystem crates (ext4 readers, btrfs readers, etc.) plug onto the OpenLV byte stream unchanged — they don't know or care whether bytes come from a partition directly or from an LV sitting on top of a partition.
Linear LVs are read, and from 0.1.3 RAID1 LVs through the leg on the PV opened (every leg holds the full data). Striped, RAID-4/5/6/10, thin pool, snapshot, and cache LVs fail to open with OpenLvError::Unsupported, and since 0.1.2 they fail on their own: The rest of the volume group still opens and its readable LVs still read. This covers the canonical layout used by Proxmox VE and most default single-disk LVM installs. See PROVENANCE.md for the full coverage matrix and the rationale for the narrow scope.
This is a reader only. It never writes to a PV.
cargo add lamlvmor in Cargo.toml:
[dependencies]
lamlvm = "0.1"use embedded_io::{Read, Seek};
use lamlvm::Lvm2;
// `reader` is anything implementing embedded_io::Read + Seek over the PV's
// bytes — a block device, a partition, or an image file (std callers can
// wrap a File with the embedded-io-adapters crate). Lvm2::open and
// open_lv_by_name each borrow it in turn.
fn read_root_lv<R: Read + Seek>(mut reader: R) -> Result<(), lamlvm::Error> {
let lvm = Lvm2::open(&mut reader)?;
// open_lv_by_name returns None when the VG has no LV by that name.
if let Some(open_lv) = lvm.open_lv_by_name("root", &mut reader) {
// `open_lv` implements embedded_io::Read + Seek. Hand it to any
// filesystem reader (e.g. ext4-view) unchanged — it can't tell the
// bytes come from an LV rather than from a bare partition.
let _ = open_lv;
}
Ok(())
}A worked example walking ext4 on top of a real LV is in examples/walk_ext4_on_lv.rs.
Set default-features = false for full no_std operation. alloc is required (the metadata-text parse path allocates).
- Oracle tests against images the LVM2 tools made on loop devices
(
tests/fixtures.rs; regenerate withtests/fixtures/regenerate.sh): A volume group whose committed metadata wraps its ring buffer, an LV without creation timestamps, a linear root next to a striped LV and a thin pool, labels in sectors 0 and 3, an ignored and stale metadata area, a damaged first metadata area with a good second one, and a RAID1 LV with a leg on each PV. Every readable LV must match the SHA-256 device-mapper gave for it, and the others must fail on their own. - An ext4-on-LV test that runs when a locally built
image.rawis present (sudo tests/build-fixture.sh). cargo fuzztargets over the label, header, metadata text and whole-PV open.
Issues and pull requests are welcome at
github.com/lamco-admin/lamlvm. A change
to the read path should come with a fixture built by
tests/fixtures/regenerate.sh.
MIT. See LICENSE-MIT. Original copyright held by main-- (2022); modifications copyright Lamco Development LLC (2026).