A modern Copy-on-Write filesystem designed for the Bazzulto OS kernel. Zero external dependencies. Runs on no_std + alloc for the kernel and on std for host-side tooling and tests.
Bazzulto OS needed a filesystem that:
- Never corrupts data on power loss — every write is atomic via Copy-on-Write semantics and journal-backed commit
- Detects silent bit-rot — CRC32C checksums on every data block and every B-tree metadata node
- Scales beyond toy workloads — B-tree structures provide O(log n) lookups, tested with 1000+ files
- Has zero external dependencies — every algorithm (CRC32C, xxHash-64, B-tree) is hand-rolled, keeping the kernel build hermetic with no network access or vendored code
- Is testable in isolation — the
BlockDevicetrait abstraction lets the entire filesystem run against in-memory disks, fault-injecting disks, and real disk images
BAFS draws inspiration from btrfs (CoW B-trees, extent-based allocation, checksums) while keeping the design focused on correctness and simplicity over feature breadth.
- Copy-on-Write — no block is ever overwritten in-place; old data remains valid until the superblock atomically commits the new tree root
- CRC32C checksums on all data blocks and metadata nodes — corruption is detected on every read
- Atomic transactions via journal-backed commit — power loss never produces a partially-written state
- B-tree storage for inodes, directory entries, data extents, checksums, and free extents — all in a single unified format
- Extent-based allocation with free-extent coalescing — contiguous block runs are tracked efficiently
- Full space reclamation on delete — unlink frees data extents, removes inode and extent records, updates free block count
- Superblock backup — primary superblock corruption automatically falls back to the backup copy
- Journal crash recovery — incomplete transactions are detected and replayed on mount
- Host-side developer CLI (
bafs-tools) — format, inspect, read/write files, and benchmark BAFS volumes on macOS and Linux without QEMU
- Snapshots and clones (v2)
- Fine-grained locking for SMP (v2)
- Transparent compression (v3)
- Per-volume and per-file encryption (v3/v4)
src/
lib.rs Crate root, feature gates
superblock.rs Superblock layout, read/write, backup fallback
btree.rs B-tree node format, insert, lookup, delete, split
inode.rs Inode struct (128 bytes), inode tree operations
extent.rs Extent allocator, free-extent tree, block freeing
dir.rs Directory entries, lookup, create, unlink
journal.rs Write-ahead log, commit, crash recovery
checksum.rs CRC32C implementation (hand-rolled, no dependencies)
checksum_tree.rs Per-block checksum storage and verification
block_device.rs BlockDevice trait (the hardware abstraction boundary)
error.rs Error types
volume.rs High-level API: format, mount, unmount, file/dir ops
kernel.rs VFS Inode trait impl (feature = "kernel")
tests/
integration_test.rs 34 comprehensive tests (see Testing below)
bafs-tools/
src/main.rs Host-side CLI for disk images
# Run from OUTSIDE the kernel tree to avoid the kernel's cargo config:
cd /tmp
cargo test --manifest-path /path/to/bafs/Cargo.tomlcargo build --features kernel --target aarch64-unknown-none \
-Zbuild-std=core,alloc,compiler_builtins \
-Zbuild-std-features=compiler-builtins-mem# Create a 1 GiB raw image
dd if=/dev/zero of=/tmp/bafs.img bs=1m count=1024
# Format, inspect, write, list, read, benchmark
cargo run -p bafs-tools --manifest-path /path/to/bafs/Cargo.toml --release -- \
format /tmp/bafs.img
cargo run -p bafs-tools ... -- info /tmp/bafs.img
cargo run -p bafs-tools ... -- write /tmp/bafs.img /hello.txt /etc/hostname
cargo run -p bafs-tools ... -- ls /tmp/bafs.img
cargo run -p bafs-tools ... -- read /tmp/bafs.img /hello.txt
cargo run -p bafs-tools ... -- bench /tmp/bafs.img| Flag | Mode | Use case |
|---|---|---|
kernel |
no_std + alloc |
Kernel module implementing the Bazzulto VFS Inode trait |
userspace |
std |
Host-side tooling (bafs-tools, bafs-mkfs, bafs-fsck) |
| (none) | std |
Library-only: core structures and algorithms, used by tests |
The test suite includes 34 integration tests and 5 unit tests covering:
| Category | Tests | What it validates |
|---|---|---|
| Disk size boundaries | 2 | Minimum viable disk, too-small rejection |
| Large disk (10 GiB) | 2 | 1 MiB write/read, 1000 files with remount |
| Basic correctness | 7 | Empty file, overwrite, partial read, 256 KiB file, nested dirs, max filename |
| Multi-session persistence | 3 | Three mount cycles, flush_and_commit checkpoint, free-space accounting |
| Directory / B-tree stress | 2 | 500 files survive remount, bulk unlink of 250 |
| Crash simulation | 4 | FaultInjectionDisk: crash during format, before commit, mid-journal, mid-delete |
| Corruption detection | 2 | Bit-flip in data block detected by CRC32C, bit-flip in checksum |
| Unlink correctness | 3 | Lookup-after-unlink, unlink-nonexistent, create-unlink-recreate |
| Free-space accounting | 1 | free_block_count tracks writes and deletes accurately |
| Journal recovery | 1 | Committed journal data restored after simulated incomplete flush |
| Superblock backup | 1 | Primary zeroed, mount succeeds via backup |
| CoW recycling | 2 | No OutOfSpace over many sessions, cross-session data isolation |
| Space reclamation | 1 | Unlink 200 files, verify blocks freed, refill same space |
| Hash / checksum sanity | 3 | CRC32C test vectors, xxHash-64 reference value |
All tests use in-memory MemoryDisk and FaultInjectionDisk implementations of the BlockDevice trait.
| Feature | BAFS v1 | ext4 | btrfs | APFS | ZFS |
|---|---|---|---|---|---|
| Copy-on-Write | ✅ | ❌ | ✅ | ✅ | ✅ |
| Data checksums | ✅ CRC32C | ❌ | ✅ CRC32C | ✅ Fletcher-64 | ✅ SHA-256 |
| Metadata checksums | ✅ CRC32C | ✅ CRC32C | ✅ CRC32C | ✅ Fletcher-64 | ✅ Fletcher-4 |
| Atomic transactions | ✅ | ✅ | ✅ | ✅ | ✅ |
| B-tree indexed | ✅ | Partial (H-tree) | ✅ | ✅ | ❌ (DMU+ZAP) |
| Extent-based allocation | ✅ | ✅ | ✅ | ✅ | ✅ |
| Space reclaim on delete | ✅ | ✅ | ✅ | ✅ | ✅ |
| Snapshots | 🕒 v2 | ❌ | ✅ | ✅ | ✅ |
| Compression | 🕒 v3 | ❌ | ✅ zstd | ✅ lzfse | ✅ zstd |
| Encryption | 🕒 v3 | ✅ fscrypt | ❌ | ✅ | ✅ |
| Deduplication | ❌ | ❌ | ✅ | ✅ Clones | ✅ |
| RAID | ❌ | ❌ (mdraid) | ✅ Native | ❌ (Fusion) | ✅ RAID-Z |
| Max file size | 16 EiB | 16 TiB | 16 EiB | 8 EiB | 16 EiB |
| Max volume size | 64 ZiB | 1 EiB | 16 EiB | 8 EiB | 256 ZiB |
| Zero external dependencies | ✅ | ❌ | ❌ | ❌ | ❌ |
no_std compatible |
✅ | ❌ | ❌ | ❌ | ❌ |
| Lines of code | ~3,500 | ~60K | ~170K | Proprietary | ~600K |
✅ = supported ❌ = not supported 🕒 = planned
BAFS is intentionally minimal: it prioritizes correctness and no_std portability over feature breadth. It targets embedded and OS kernels where zero dependencies and auditability matter more than petabyte-scale features.
Block 0 Reserved (boot sector)
Block 1 Primary superblock (512 bytes, CRC32C protected)
Block 2 Backup superblock
Blocks 3..N Journal area (1% of disk, min 256 blocks, max 16384)
Blocks N..end Data area (B-tree nodes, file data, free extents)
Each B-tree node occupies one 4 KiB block:
Offset Size Field
0 4 CRC32C checksum (covers bytes 4..4096)
4 1 Level (0 = leaf, 1+ = internal)
5 1 Flags (reserved)
6 2 Item count
8 8 Self block address
16 8 Generation (transaction ID)
24 ... Items (leaf: key+value pairs; internal: key+child pointers)
BAFS uses a single unified B-tree format for all persistent data:
- Inode tree — file/directory metadata (128-byte inodes), directory entries, data extent mappings
- Free-extent tree — tracks unallocated block runs for recycling
- Checksum tree — per-block CRC32C values for data integrity verification
All tree modifications use Copy-on-Write: modified nodes are written to newly allocated blocks, and the tree root is updated atomically via the superblock. The journal provides crash recovery for the window between writing new blocks and updating the superblock.
// Format a new volume
bafs_format(&device, BafsFormatOptions::default())?;
// Mount and operate
let mut vol = bafs_mount(device)?;
let inode = volume_create_file(&mut vol, root, "hello.txt")?;
volume_write_file_data(&mut vol, inode, 0, b"Hello, BAFS!")?;
// Read back
let mut buf = vec![0u8; 12];
volume_read_file_data(&vol, inode, 0, &mut buf)?;
// Directory operations
let entry = volume_lookup_directory_entry(&vol, root, "hello.txt")?;
volume_unlink_directory_entry(&mut vol, root, "hello.txt")?;
// Commit and unmount
bafs_unmount(vol)?;GNU General Public License v3.0
See CONTRIBUTING.md for guidelines on how to contribute.
This project follows the Contributor Covenant Code of Conduct.