HelixFS

FileSystemOps trait, block device layer, journaling, snapshot API, and CoW semantics.

Profile Reference

HelixFS — Virtual File System

The helix-fs crate provides HelixFS, a feature-rich virtual filesystem with POSIX-compatible operations, B+ tree indexing, write-ahead journaling, copy-on-write snapshots, per-extent compression, and file-level encryption. It's designed to be both a complete filesystem implementation and an extensible VFS layer.

Any module can implement the FileSystemOps trait to plug in a new filesystem — the VFS handles mount points, path resolution, and caching.

VFS I/O Pipeline6N · 6E
open/read/writeresolved pathmetadata opdata writecommit flushnew extentApplicationUserspace I/O reques…1VFS LayerVirtual File System2HelixFSOn-disk filesystem i…3Write-Ahead JournalCrash-safe metadata2CoW SnapshotsCopy-on-Write2Block DeviceRaw disk I/O2
100%
☝ Drag to pan·🤏 Pinch to zoom·Tap a node

FileSystemOps Trait

This is the central VFS interface. Every filesystem implementation — HelixFS, tmpfs, procfs, devfs — implements this trait. The API uses inode numbers (not path strings), similar to FUSE/VFS internals, with Credentials passed to permission-sensitive operations.

fs/src/vfs/ops.rs
rust
pub trait FileSystemOps: Send + Sync {
2
// Filesystem lifecycle
fn mount(&mut self, device: u64, flags: u64) -> HfsResult<()>;
fn unmount(&mut self) -> HfsResult<()>;
fn sync(&mut self) -> HfsResult<()>;
fn statfs(&self) -> HfsResult<FsStats>;
7
8
// Inode operations (all inode-number based, not path-string)
fn lookup(&self, parent: u64, name: &[u8],
10
cred: &Credentials) -> HfsResult<u64>;
fn getattr(&self, ino: u64) -> HfsResult<FileStat>;
fn setattr(&mut self, ino: u64, attr: &SetAttr,
13
cred: &Credentials) -> HfsResult<FileStat>;
14
15
// File I/O
fn create(&mut self, parent: u64, name: &[u8], mode: u32,
17
flags: OpenFlags, cred: &Credentials) -> HfsResult<(u64, FileHandle)>;
fn open(&mut self, ino: u64, flags: OpenFlags,
19
cred: &Credentials) -> HfsResult<FileHandle>;
fn read(&self, ino: u64, handle: &FileHandle,
21
offset: u64, buf: &mut [u8]) -> HfsResult<usize>;
fn write(&mut self, ino: u64, handle: &FileHandle,
23
offset: u64, buf: &[u8]) -> HfsResult<usize>;
fn release(&mut self, ino: u64, handle: FileHandle) -> HfsResult<()>;
25
26
// Directory operations
fn mkdir(&mut self, parent: u64, name: &[u8], mode: u32,
28
cred: &Credentials) -> HfsResult<u64>;
fn rmdir(&mut self, parent: u64, name: &[u8],
30
cred: &Credentials) -> HfsResult<()>;
fn readdir(&self, ino: u64, handle: &DirHandle,
32
offset: u64, buf: &mut [DirEntry]) -> HfsResult<usize>;
33
34
// Link operations
fn link(&mut self, ino: u64, newparent: u64, newname: &[u8],
36
cred: &Credentials) -> HfsResult<()>;
fn unlink(&mut self, parent: u64, name: &[u8],
38
cred: &Credentials) -> HfsResult<()>;
fn symlink(&mut self, parent: u64, name: &[u8], target: &[u8],
40
cred: &Credentials) -> HfsResult<u64>;
fn rename(&mut self, oldparent: u64, oldname: &[u8],
42
newparent: u64, newname: &[u8], flags: u32,
43
cred: &Credentials) -> HfsResult<()>;
44
}
Index

Core Types

These are the fundamental types used across all filesystem operations. They're designed for zero-cost abstractions — newtype IDs prevent misuse, and bitflags provide type-safe option handling.

fs/src/core/types.rs
rust
pub struct InodeNum(pub u64); // NULL=0, ROOT=1
pub struct BlockNum(pub u64); // NULL=0
pub struct TxnId(pub u64); // Transaction ID
pub struct SnapId(pub u64); // Snapshot ID
5
2 refs
pub struct OpenFlags(pub u32);
2 refs
impl OpenFlags {
pub const O_RDONLY: Self = Self(0);
pub const O_WRONLY: Self = Self(1);
pub const O_RDWR: Self = Self(2);
pub const O_CREAT: Self = Self(0x40);
pub const O_EXCL: Self = Self(0x80);
pub const O_TRUNC: Self = Self(0x200);
pub const O_APPEND: Self = Self(0x400);
pub const O_DIRECTORY: Self = Self(0x10000);
16
}
17
18
#[repr(u8)]
2 refs
pub enum FileType {
20
Unknown=0, Regular=1, Directory=2, CharDevice=3,
21
BlockDevice=4, Fifo=5, Socket=6, Symlink=7,
22
}
23
pub struct FileStat {
25
pub st_ino: u64, pub st_mode: u32, pub st_nlink: u32,
26
pub st_uid: u32, pub st_gid: u32, pub st_size: u64,
27
pub st_blocks: u64, pub st_blksize: u32,
28
pub st_atime: u64, pub st_mtime: u64, pub st_ctime: u64,
29
}
30
pub struct DirEntry {
32
pub d_ino: u64, pub d_off: u64, pub d_reclen: u16,
33
pub d_type: FileType, pub d_namelen: u8, pub d_name: [u8; 256],
34
}
35
pub struct Credentials {
37
pub uid: u32, pub gid: u32,
38
pub groups: [u32; 16], // Fixed-size, no alloc
39
pub ngroups: u8,
40
pub privileged: bool,
41
}
Index

Operation Builders

For complex I/O patterns, HelixFS provides typed operation builders with fluent APIs. These allow fine-grained control over priority, synchronization, and buffering without overloading function signatures.

fs/src/operations.rs
rust
1
// Scatter/gather read with priority control
2
let bytes_read = ReadOp::new(handle)
3
.offset(4096)
4
.max_bytes(8192)
5
.priority(IoPriority::High)
6
.execute(&fs)?;
7
8
// Buffered write with sync-on-complete
9
WriteOp::new(handle, data)
10
.offset(0)
11
.sync_on_complete(true)
12
.execute(&fs)?;
13
14
// Atomic file creation with permissions
15
let inode = CreateOp::new("/etc/config.toml")
16
.file_type(FileType::Regular)
17
.permissions(0o644)
18
.owner(Credentials::root())
19
.execute(&fs)?;
20
21
// Server-side copy (no userspace buffer)
22
CopyFileRangeOp::new(src_handle, dst_handle)
23
.src_offset(0)
24
.dst_offset(0)
25
.length(1024)
26
.execute(&fs)?;

Block Device Trait

The block device trait is the low-level interface between the filesystem and storage hardware. Any block storage — NVMe, virtio-blk, RAM disk — implements this trait.

fs/src/disk/mod.rs
rust
2 refs
pub trait BlockDevice: Send + Sync {
fn read_block(&self, block: u64, buf: &mut [u8]) -> HfsResult<()>;
fn write_block(&self, block: u64, buf: &[u8]) -> HfsResult<()>;
fn block_size(&self) -> u32;
fn total_blocks(&self) -> u64;
fn flush(&self) -> HfsResult<()>;
fn is_read_only(&self) -> bool;
8
}
9
10
// Async variant for high-performance I/O
pub trait AsyncBlockDevice: BlockDevice {
fn read_block_async(&self, block: u64, buf: &mut [u8]) -> HfsResult<IoToken>;
fn write_block_async(&self, block: u64, buf: &[u8]) -> HfsResult<IoToken>;
fn poll_completion(&self, token: IoToken) -> HfsResult<bool>;
15
}
Index

HelixFS Features

HelixFS is not just a VFS layer — it's a full-featured on-disk filesystem with modern capabilities.

FeatureDescription
B+ Tree IndexingAll directories and extent maps use B+ trees for O(log n) lookups
Write-Ahead JournalCrash-safe metadata with ordered, writeback, and full journal modes
CoW SnapshotsInstant O(1) snapshots with copy-on-write — zero data copying
Per-Extent CompressionLZ4, ZSTD, or LZO compression at the extent level
File EncryptionAES-256-XTS encryption with per-file key management
Extent MappingContiguous block groups for sequential I/O performance
Free-Space TreesB+ tree allocator with group allocation for locality

Journal API

The journal provides crash consistency. Every metadata change goes through the journal, so the filesystem can recover to a consistent state after an unexpected shutdown.

fs/src/journal/mod.rs
rust
3 refs
pub struct Journal { /* ... */ }
2
3 refs
impl Journal {
pub fn begin_transaction(&self) -> HfsResult<TransactionId>;
pub fn log_block_write(&self, txn: TransactionId,
6
block: u64, data: &[u8]) -> HfsResult<()>;
pub fn log_metadata(&self, txn: TransactionId,
8
record: MetadataRecord) -> HfsResult<()>;
2 refs
pub fn commit(&self, txn: TransactionId) -> HfsResult<()>;
pub fn abort(&self, txn: TransactionId) -> HfsResult<()>;
pub fn replay(&self) -> HfsResult<Vec<TransactionId>>; // Crash recovery
pub fn checkpoint(&self) -> HfsResult<()>;
13
}
14
pub enum JournalMode {
16
Ordered, // Metadata journaled, data written before commit
17
WriteBack, // Metadata journaled, data order not guaranteed
18
Journal, // Both metadata and data journaled (safest, slowest)
19
}
Index

Snapshot API

Snapshots use copy-on-write semantics — creating a snapshot is O(1) and costs zero data copying. Blocks are shared between the live filesystem and the snapshot until one side writes, at which point a new copy is allocated.

fs/src/snapshot/mod.rs
rust
2 refs
pub struct SnapshotManager { /* ... */ }
2
2 refs
impl SnapshotManager {
pub fn create_snapshot(&self, name: &str) -> HfsResult<SnapshotId>;
pub fn delete_snapshot(&self, id: SnapshotId) -> HfsResult<()>;
pub fn restore_snapshot(&self, id: SnapshotId) -> HfsResult<()>;
pub fn list_snapshots(&self) -> HfsResult<Vec<SnapshotInfo>>;
pub fn diff_snapshots(&self, a: SnapshotId, b: SnapshotId)
9
-> HfsResult<Vec<Change>>;
10
}
11
2 refs
pub struct SnapshotInfo {
13
pub id: SnapshotId,
14
pub name: String,
15
pub timestamp: Timestamp,
16
pub parent: Option<SnapshotId>, // Snapshot tree
17
pub size_bytes: u64,
18
}
Index

HelixFS snapshots form a tree — you can snapshot a snapshot. The diff_snapshots method lets you see exactly which files changed between any two points in the tree, making it easy to implement incremental backups or rollback.