Step 47 of 56
ext4: a real filesystem, in Ada
A from-scratch ext2/3/4 implementation with JBD2 journal replay, an on-device formatter, and an error model that is simply Ada's.
Scope
ESP32S3.Ext4 is a reimplementation of lwext4 in pure Ada: read
and write — create, write, truncate, mkdir, rmdir, unlink, rename,
link — with metadata checksums and JBD2 journal replay. It is pure logic
over Block_Dev, so it also compiles host-native
and is developed against a harness that checks every operation against
mke2fs, debugfs and e2fsck.
The pieces are separate children rather than one monolith: superblock, group descriptors, inodes, bitmaps, block map, block cache, directories, paths, files, the writer, the journal, mkfs, and a VFS layer that presents several mounted volumes as one tree.
The error model is Ada's
Operations raise rather than returning status
codes, and the IO-family exceptions are the standard ones from
Ada.IO_Exceptions — chosen so a future
Ada.Streams.Stream_IO bridge maps cleanly — plus a few
filesystem-specific additions. That is a deliberate departure from the
Status-out-parameter style used by the
bus drivers, and it is the right one here: a
filesystem call has many more failure modes than a bus transaction, and threading
them all through return values would drown the call sites.
Journal replay
The JBD2 journal lives in inode 8 as a regular file. On a volume whose
superblock has the RECOVER incompat flag set, pending committed
transactions are replayed into the filesystem before normal use, then the journal
is reset and the flag cleared — which is what makes a power loss survivable
rather than corrupting.
Two things to know. The journal's on-disk structures are
big-endian, unlike the rest of ext — a genuine trap when
reading the code. And only the classic non-checksummed format is handled (ext3,
and ext4 with ^metadata_csum); a checksummed journal (CSUM_V2/V3)
raises Unsupported_Feature rather than guessing.
Formatting on the device
Ext4.Mkfs lays down a fresh minimal ext4 directly on a
Block_Dev: one block group, a root directory and lost+found, no
journal, no metadata_csum. The result mounts read-write with this
filesystem and passes the host's e2fsck — which is the claim
worth making, because it means the format is genuinely correct rather than merely
self-consistent.
It writes only metadata and the two directory blocks, leaving
data blocks untouched (the filesystem initialises each as it is allocated). So
formatting a 32 MB part is fast, but it also means Mkfs is not
an erase — old file contents remain on the medium until overwritten.
Targets the embedded/full runtimes: it needs exceptions, finalization, secondary stack and a heap.