Skip to content
lamco-adminPublic

About

Read-only no_std ZFS pool reader for UEFI bootloaders (single disk, mirror, RAID-Z1), from Lamco Development LLC

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

lamzfs

Crates.io Docs.rs CI License: MIT Website

A no_std + alloc, read-only ZFS pool reader for UEFI bootloaders, from Lamco Development LLC.

lamzfs imports a ZFS pool over a plain byte source, walks to one dataset, and reads its files: Enough for a bootloader to find a kernel and initramfs without the OpenZFS kernel module, without std, and without a GPL UEFI driver. The motivating target is Ubuntu and Debian root-on-ZFS, which keep a simple bpool boot pool. Read-only by construction: There is no write path and no BlockWrite.

What it reads

  • Topologies: One top-level vdev: A single disk, a mirror, or a single-parity RAID-Z1 (including degraded reads that rebuild a missing or corrupt column from parity). The active uberblock is chosen from all four labels of every member, so a mirror member that missed the last writes can't win.
  • Pools as installers create them: Proxmox VE's (every feature enabled), Ubuntu's bpool and its rpool with dnodesize=auto, xattr=sa, acltype=posixacl and normalization=formD.
  • Compression: off, zle, lzjb, lz4, gzip and zstd (each a feature).
  • Checksums: Fletcher-2/4, SHA-256, SHA-512 (OpenZFS's SHA-512/256) and BLAKE3 (keyed with the pool's checksum salt, as OpenZFS does).
  • The full read walk: The vdev label, uberblock, MOS, DSL, dataset, ZPL, ZAP directories (micro and fat), names over 255 bytes (longname), large dnodes, large blocks, and the indirect block-pointer tree (sparse-file aware).

What it refuses

Everything else fails with a typed error and a stable token (Error::token), never a wrong read:

  • Active read features it doesn't implement, checked in the label before the MOS is read and in the MOS features_for_read set after: raidz_expansion, device_removal, draid, dynamic_gang_header, redacted_datasets, redaction_list_spill, and any feature it doesn't know (feat_unknown_read_incompat).
  • Several top-level vdevs (topo_multi_toplevel): A stripe such as Proxmox's RAID0, or a pool with log or special vdevs.
  • RAID-Z2/3 and dRAID, gang blocks (gang_block), and encrypted datasets (encryption; an unencrypted /boot beside them still reads).
  • Skein and Edon-R checksums, block by block (csum_skein, csum_edonr). Both are keyed with the pool's salt, and no permissive Rust implementation of either offers a keyed mode (Debian packages neither).

Installation

cargo add lamzfs

or in Cargo.toml:

[dependencies]
lamzfs = "0.1"

Features

Feature Default What it adds
lz4, zstd, gzip, lzjb yes That compression algorithm
mirror yes Mirror topologies
sha512 yes SHA-512/256 checksums (sha2)
blake3 yes BLAKE3 checksums (blake3, portable Rust)
std no impl std::error::Error for Error

For x86_64-unknown-uefi, build in release mode: sha2 0.11's x86 backend hits an LLVM error in unoptimized builds for that target. Release builds, and every other target, are unaffected.

Usage

Implement BlockRead over your device, then import and read:

use lamzfs::{BlockRead, PoolMember, Zfs};

# struct Disk;
# impl BlockRead for Disk {
#     type Error = ();
#     fn read_at(&mut self, _off: u64, _buf: &mut [u8]) -> Result<(), ()> { Ok(()) }
# }
# fn members() -> Vec<PoolMember<Disk>> { Vec::new() }
let mut zfs = Zfs::import(members())?;          // one PoolMember per vdev member
println!("pool {} ({:#x})", zfs.pool_name(), zfs.pool_guid());

// Dataset path = child-directory components under the pool root; the second
// argument is the directory within that dataset (empty = its root).
for entry in zfs.read_dir(&["BOOT", "default"], &[])? {
    println!("{:?} {}", entry.kind, entry.name);
}
let kernel = zfs.read(&["BOOT", "default"], &["vmlinuz"])?;
# Ok::<(), lamzfs::Error>(())

See examples/zfsdump.rs for a runnable host tool.

Testing

The fixtures are real pools that OpenZFS wrote through its kernel module, so the kernel is the oracle: Every file must hash to what the kernel wrote, and every refused layout must fail with its named token. tests/fixtures/regen.sh builds the original compatibility=grub2 pools and tests/fixtures/regen-installer.sh the installer-shaped and refused ones (both need the ZFS kernel module and sudo). Three fuzz targets live in fuzz/.

Basis

The on-disk decoders are vendored from rzfs, electing the MIT half of its GPL-2.0 OR MIT dual license: A clean-room reader, not GPL kernel or userspace source. The orchestration (pool import, vdev routing, feature gate, dataset walk, path resolve, file read) is new lamzfs code. The crate is scalar-only and #![forbid(unsafe_code)]. See NOTICE for attribution.

Contributing

Issues and pull requests are welcome at github.com/lamco-admin/lamzfs. A change to the read path should come with a fixture built by one of the scripts in tests/fixtures/.

License

The crate as published is MIT (LICENSE-MIT). The vendored rzfs decoders are MIT only, by the election recorded in NOTICE. The code written for lamzfs is additionally available under the Apache License, Version 2.0 (LICENSE-APACHE), as each of its files' SPDX headers says.

Copyright 2025-2026 Lamco Development LLC.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you shall be licensed as above, without any additional terms or conditions.

About

Read-only no_std ZFS pool reader for UEFI bootloaders (single disk, mirror, RAID-Z1), from Lamco Development LLC

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages