- Rust 99.9%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
Merge the selected feature/native-cli history with an explicit two-parent commit so main retains the development lineage and the validated source snapshot. The resulting tree is identical to the selected feature commit; no dependency pins or runtime behavior are changed by this merge. Previous main: |
||
| .github | ||
| src | ||
| .editorconfig | ||
| .gitignore | ||
| .markdownlint-cli2.yaml | ||
| ARCHITECTURE.md | ||
| Cargo.toml | ||
| CODE_OF_CONDUCT.md | ||
| CONTRIBUTING.md | ||
| LICENSE | ||
| linker.ld | ||
| README.md | ||
| ROADMAP.md | ||
| rustfmt.toml | ||
| SECURITY.md | ||
e2fsd
e2fsd is the private ext-family filesystem provider daemon behind vfsd. It
is started by rootd after keyd and before fatd, and it is reachable only
through the provider endpoint delegated to vfsd.
EriX is a clean-room, capability-based microkernel operating system written entirely in Rust.
Technical requirements are tracked in the EriX requirements, conventions, and project documentation.
See:
- docs for design documents, specifications, and development plans.
- Related architecture repositories for kernel, services, libraries, drivers, and integration tooling.
Purpose of This Repository
Exact-entry grants support transactionally creating empty regular files without returning content authority. Explicit private truncation operates on the retained file inode, not a re-resolved pathname, and preserves filesystem safety and timestamp checks. Unknown OPEN mount identities are not object-absence evidence. During OPEN only, missing backing storage is an internal failure and missing key material is denied; genuine pathname absence remains distinguishable. Borrowed adapters preserve the original I/O calls without caching or retries. Host filesystem fixtures honor TMPDIR, including unique inspection-image paths.
This repository implements the EriX ext-family filesystem provider. Its purpose
in EriX is to serve validated ext2/ext3/ext4 media behind vfsd without
exposing a public service.
Functionally, it parses ext media, validates features and journals, and implements provider file/directory operations. The repository keeps the implementation, interface contracts, tests, and documentation for that behavior in one reviewable ownership boundary.
The maintained responsibilities are:
- serve ext-family filesystems only through the private filesystem-provider ABI
- validate ext media, journals, checksums, names, and authority before exposing mounts
- implement persistent file and directory operations through the assigned
blockdendpoint - keep provider authority private with no
namedentry or public client endpoint
Clean-Room Policy
EriX follows a strict clean-room philosophy:
- No external source code may be copied.
- No external Rust crates are allowed.
- No code generation tools that embed third-party code.
- All code must be authored within the project.
Violations will result in rejection of the contribution.
License
All EriX repositories are licensed under the ISC License.
Development Model
EriX development is modular, deterministic, reproducible, authority-explicit, security-first, and self-hosting oriented.
This repository follows the project roadmap and the validation rules documented in its own roadmap.
Current Status
Private cwd traversal pins each immediate directory or symbolic link beneath a
retained directory handle; . creates an independent duplicate. Raw readlink
uses the held symlink inode and preserves relative .. text for the bounded
VFS walker, while the older pathname readlink API stays canonical-absolute.
The opaque mount/inode/generation identity is descriptive only and valid for
comparison while the associated handles remain live. Existing close retires
both kinds of handle, and mutation guards protect held objects from removal or
replacement.
The private directory-entry metadata operation accepts one retained directory
handle and one validated immediate basename. It returns current no-follow
metadata without reopening a parent pathname, following a symbolic link, or
granting file-content access. Closed handles, non-directory objects, and path
selectors fail closed; public authorization remains owned by vfsd.
The provider service, startup validation, generic ABI dispatch, CI, and
block-backed media path are present. Mount reads device metadata and the ext
superblock through the private blockd endpoint, validates core superblock and
group/inode geometry, runs every Linux/e2fsprogs ext4 superblock feature bit
through an explicit feature registry, verifies supported metadata_csum /
gdt_csum metadata using the shared lib-crc CRC-32C primitive, validates
internal journals or explicit same-disk external journal partition selectors,
including external JBD2 UUID, superblock, block-size, feature-bit, and
sequence-state checks. The mapping table is validated and retained as exact
count-derived encoded bytes, so e2fsd imposes no provider-count ceiling below
startup transport capacity. Each selector is combined with the mounted data
partition's live parent identity and resolved by streaming the blockd
namespace; no opaque runtime device ID or local scan ceiling is embedded in
policy. The provider rejects obsolete, planned, or unknown
ext feature
flags, standalone journal_dev volumes offered as filesystem providers, unknown
journal feature layouts, read-write mounts of read-only media or read-only-only
ext4 feature media (readonly, shared_blocks), and mutation handles after a
read-only mount. The supported ext geometry envelope covers every power-of-two
filesystem block from 1 KiB through the format-defined 64 KiB maximum.
lib-block fragments complete filesystem-block transfers at its transport
boundary, so wire capacity does not constrain media geometry. Inode records are
accepted at every power of two from 128 bytes through the smaller of the
filesystem block and the largest value representable by ext's 16-bit inode-size
field (32 KiB); irregular records fail closed. Media reads, metadata checksum updates,
inline-data handling, xattr handling, quota/orphan cleanup, and mutation
writeback preserve unknown bytes in the accepted inode tail.
The media path stores only mount records and open handles in memory. Packaging
derives the mount-record count from exact provider = "ext" deployment rows
and takes the handle-record count from explicit runtime policy. It authenticates
both counts and their target layouts in the signed service image, then expands
one writable NOBITS arena to the exact page-rounded size. e2fsd carves only
typed mount and handle slices from that arena and retains neither a general
allocator nor access to alignment/page padding. Create reserves a handle record
before media mutation, so provider-capacity exhaustion cannot leave an
unreported file. Provider-private exact handles admit file reads, writes, or
directory enumeration only when the retained authority operation matches;
other operations cannot reuse them as ordinary open handles. Directory lookup
scans media directories, inode metadata is
read from group descriptor
inode tables, file data follows extents or legacy direct/single/double/triple
indirect block maps, and writes allocate/free blocks and inodes through ext
bitmaps. New and grown files use inline extent records for small extent sets and
spill into indexed extent tree leaf blocks when fragmentation exceeds the inode
record capacity; clean ext2 and non-extent ext3 media use legacy direct and
indirect block pointers instead. The positive Filesystem provider work VM
scenario reads host-created ext media, creates a new marker through vfsd,
reopens/stat/readdir-checks it, leaves it on disk, and verifies the partition
with host e2fsck -fn after shutdown.
Journaled ext media now routes metadata mutations through a JBD2 transaction on the internal journal inode or an explicitly authorized external journal device. External-journal log blocks retain JBD2's device-absolute identity mapping; only the journal superblock is located through the enclosing journal-volume metadata. This keeps replay, transaction staging, and commit writeback within the authorized partition geometry. The provider writes file data first, sets the ext recovery-required incompatibility bit, emits descriptor/data/commit records, checkpoints the staged metadata blocks to their home locations, refreshes checksums, and clears recovery-required only after the checkpoint succeeds. If the journal or checkpoint step fails after the recovery bit is set, the bit is left set so the next mount fails closed instead of exposing potentially partial metadata. Provider-originated large mutations stream the distinct changed-block sequence from sectors staged in the clean journal ring and split full-commit transactions only when the JBD2 descriptor or journal ring requires it. Staging grows backward from the ring tail while descriptor/data/commit records grow forward, and writeback fails before the two regions overlap. There is no fixed in-memory staged-sector array, separate changed-block array ceiling, or two-block transaction cap. A scratch-owned sector-address index prevents ordinary reads from rereading every staged record; transactions that outgrow the index continue through the authoritative journal-backed records rather than encountering a local ceiling. Large file writes publish data blocks before the final size metadata commit.
Current mutation support targets the deterministic clean ext fixtures used by
the filesystem-provider VM matrix, including the ext4 metadata_csum + metadata_csum_seed + dir_index + extents + internal journal positive fixture
and a fragmented ext4 extent-tree fixture that forces provider-created files out
of inline inode extent records. The ext4 bigalloc fixture is mounted read-write
with cluster geometry validation, cluster bitmap accounting, full cluster
i_blocks accounting, cluster freeing on unlink, malformed bitmap rejection,
and host e2fsck -fn verification. The ext4 meta_bg fixture uses
e2fsprogs-created meta block groups with 1 KiB blocks and non-default
blocks-per-group; descriptor lookup, inode-table reads, checksum refresh, and
metadata reservation all use the same descriptor-placement helper, while an
impossible s_first_meta_bg variant fails closed at mount. The provider
dispatch also parses the expanded generic filesystem-provider ABI for rename,
truncate, symlink/readlink, hard-link, and metadata-update requests. Ext media
binds each exact-entry operation to one provider-private handle that retains the
parent inode, target inode and generation or proven absence, and admitted
operation. Selector-free exact stat and touch join the existing namespace
mutations. Follow-up operations revalidate that identity from the retained
parent; ordinary handle operations cannot use the exact handle. Touch accepts
only the vfsd-derived basename and explicit atime/mtime selection. NO_CREATE
on retained absence changes nothing, while creation and its selected timestamp
updates share one journal transaction. V1 preserves ctime; v2 sets ctime from
independent trusted change-time evidence without transferring clock authority.
Ext media
now implements regular-file truncate shrink, no-op, zero-length shrink, and
sparse growth for accepted legacy indirect, extent, inline-data, quota,
journaled, and bigalloc media, with block/cluster freeing, inode-size and
i_blocks updates, checksum refresh, quota sync, and full JBD2 commits where
journaling is active. Existing handles retain only inode identity and therefore
observe the committed size and block map on their next operation without any
new authority or stale metadata cache. Write-past-EOF regular-file operations
allocate only the
written logical block range, read unmapped holes as zeroes, preserve legacy and
extent holes, and convert only touched unwritten extents before writeback.
Verity, immutable/append-only, unsupported encrypted, malformed xattr,
read-only, and shared-block states remain denied before writeback begins. Ext
media also implements rename for same-directory and cross-directory moves of
files, directories, symlinks, and metadata-only special nodes, including
compatible overwrite, .. repair for directory moves, HTree entry updates,
metadata checksum refresh, journal writeback, quota sync where quota media is
mounted, and fail-closed rejection for cycles or non-empty directory overwrite.
Ext media also surfaces symlink inode types through stat/readlink, supports
fast and block-backed symlink targets, creates symlinks, creates and removes
hard links for regular files and symlinks with checked link-count updates, and
preserves FIFO/socket/device inode metadata during traversal and directory
mutation. Device nodes remain metadata only: open and hard-link mutation for
special-file entries return DENIED and do not grant device authority. Ext
stat responses expose decoded atime, mtime, ctime, and crtime values with ext
extra-epoch and nanosecond fields when the inode size carries them. Metadata
updates support controlled mode, uid/gid, atime, mtime, and user-settable
filesystem flag changes on accepted writable media. The path preserves high
uid/gid bits, generation, project ID, structural inode flags, and unknown
inode-tail bytes, refreshes inode and filesystem checksums, routes updates
through JBD2 when journaling is active, and denies mutation of current
immutable, append-only, imagic, read-only, malformed-xattr, and root-inode
states. Integration's advanced ext corpus maintenance rows keep these metadata
mutation checks tied to explicit implemented, rejected, obsolete-rejected,
planned, and permanent non-goal feature classes so accepted feature bits cannot
silently bypass mount, mutation, unit, VM, or documentation evidence. Ext4
The additive private provider v2 operations carry only checked descriptive
wall-clock values from vfsd; they do not transfer timed, RTC, or any other
endpoint authority. On journaled writable ext media, successful create,
namespace, data, metadata, and read-family operations update ext atime, mtime,
ctime (inode-change time), and crtime according to the operation while keeping
data and timestamp changes in one JBD2 transaction. Epoch zero is valid. Old
inode records use second precision and their signed legacy range, while
extra-time fields preserve representable nanoseconds and extended epochs.
Untrusted or unavailable time continues through the unchanged v1 operation
without an automatic timestamp. V1 metadata updates preserve existing ctime
instead of deriving it from explicit atime or mtime values.
A timestamped file read commits atime on the first successful nonempty read of
each open file description when persisted atime is not newer than mtime or
ctime, or when atime is at least 24 hours old. Further transport fragments on
that handle and recent unchanged reopenings avoid redundant JBD2 transactions.
Close clears the descriptive handle flag, and the next open re-evaluates only
persisted inode timestamps. Empty reads and failed commits do not consume the
update. This relatime policy retains no cross-handle cache and carries no
clock or endpoint authority.
Regular extent reads cap each provider response at the largest whole-sector payload accepted by the private block transport. Physically consecutive mapped blocks are issued as one bounded block request, avoiding duplicate per-block IPC without retaining file data or bypassing extent and hole validation.
Timestamped v2 operations are denied before mutation on non-journal ext2 and
read-only ext media because those mounts cannot provide atomic timestamp
writeback; v1 reads and legacy mutations remain available. Precommit failures
discard all staged data and timestamp changes. Once a JBD2 commit may be
durable, checkpoint or cleanup uncertainty is not returned as a retryable
provider failure: e2fsd fails stop and leaves recovery evidence for the next
mount.
Ext4 stable-resize media carries stable_inodes together with resize_inode:
stable-inode identity and UUID-bound encryption-state mutations are rejected,
and allocation/freeing treats inode 7 reservation trees and reserved GDT blocks
as metadata even if a bitmap is unsafe. The ext2 positive corpus includes a
host-generated large-file fixture that crosses the direct-block boundary and
exercises legacy indirect allocation, readback, free, and host e2fsck -fn
validation. The broader ext2 corpus adds every format-defined power-of-two block
size from 1 KiB through 64 KiB, inode tables through 16 KiB, sparse
superblocks, non-default blocks-per-group, grown directories, and a 70 MiB
sparse file whose tail crosses into triple-indirect mapping while holes still
read back as zeroes. The ext2 malformed corpus corrupts block maps, directory
records, inode geometry, bitmap
metadata, and reserved inode state so mount and mutation paths fail closed. The
ext2 compat corpus also mounts media carrying dir_prealloc, imagic_inodes,
ext_attr, and resize_inode: allocation skips reserved GDT metadata even if
media bitmaps are unsafe, imagic inodes deny provider-originated mutation, and
existing external xattr blocks are parsed and preserved for regular writes.
Deleting an xattr-bearing inode validates the xattr header, rejects duplicate
entry names, decrements shared xattr refcounts, and frees unshared xattr blocks
before the inode is cleared. The ext2 xattr corpus carries both a user xattr and
a POSIX ACL and is checked with host e2fsck -fn, getfattr, and getfacl.
Ext4 xattr handling also accepts inode-body xattrs, metadata-checksummed
external xattr blocks, ACL and unknown namespace payload preservation,
ea_inode value references, checksum refresh after refcount updates, and
deletion cleanup for unshared external xattr blocks. Value-inode validation and
cleanup stream every encoded entry, so an internal scratch-array size cannot
reject otherwise valid metadata. Public list/get/set/remove xattr and POSIX ACL
mutation requests are a permanent non-goal for this provider ABI; user, system,
trusted, security, and unknown namespaces are never exposed as caller authority
and are only parsed for preservation, validation, or deletion cleanup. Ext4
quota/project-quota media is accepted after mount-time
comparison of user, group, and project quota files against live inode usage;
provider mutations resync quota usage after create, write growth, unlink, and
rmdir, and new files/directories inherit project IDs from PROJINHERIT parents.
Usage is streamed against the format-defined quota radix tree without a fixed
identity count.
The integration Linux/e2fsprogs interoperability matrix links ext2/ext3/ext4
host-generated images to the feature bits they prove, malformed companions, host
tools, and provider-mutation VM scenarios. The targeted 512-byte-inode VM media
covers ext2, ext3, and ext4. The ext4
geometry fixture combines descriptor and bitmap checksum handling, inode-table
reads, internal journaling, extents, HTree directories, inode-body xattrs, and
inline-data payloads under the larger inode record. The large-inode VM media
proves that a format-valid 1,024-byte inode mounts and preserves unknown tail
bytes during metadata mutation. Separate malformed fixtures prove that
non-power-of-two, smaller-than-minimum, containing-block-exceeding, and
unrepresentable inode geometry fails closed before a VFS mount is exposed. Ext4
inline_data media is accepted for regular files and directories: provider
reads and writes inline inode bodies, preserves system.data and other xattrs,
creates small files/directories inline when the feature is present, converts
them to block-backed storage on growth, and rejects malformed inline payload
sizes fail-closed. Ext4 orphan recovery runs before writable mounts are exposed:
legacy orphan inode chains and orphan_file records are validated, zero-link
orphaned inodes are freed through the normal bitmap/xattr/checksum cleanup path,
linked truncate orphans have their orphan pointers cleared, orphan_present is
cleared after successful cleanup, and malformed orphan chains or orphan-file
checksums fail closed. Ext4 encrypt media is accepted for fscrypt v2
AES-256-XTS file contents and AES-256-CTS filename transforms. Encrypted inodes
must carry a valid ext encryption xattr, the referenced key identifier must
resolve through the provider-local keyd endpoint, and mismatched or missing
key material fails closed before data or names are exposed. fscrypt v1 contexts
are parsed for compatibility detection but are an explicit non-goal for data
access under the current keyd material-id ABI; v1 media fails closed before
key lookup or decryption. Other Linux fscrypt mode or policy variants, including
AES-128-CBC/CTS, Adiantum, AES-256-HCTR2, direct-key, IV_INO_LBLK, and
non-default data-unit-size policies, are likewise explicit fail-closed states.
Ext4 verity media is accepted for read-only fsverity files using the Linux
ext4 post-EOF metadata layout. Verity inodes carry a 256-byte Linux v1
descriptor after the Merkle tree, store the descriptor-size footer in the last
allocated filesystem block, resolve their SHA-256 root through the
provider-local keyd trust-root operation, verify salt-aware Merkle tree blocks
before reads are served, derive arbitrary-depth tree geometry with checked
scalar arithmetic instead of a fixed level table, and deny every write to
verity files. Missing roots,
mismatched roots, malformed descriptors, unsupported hash algorithms, malformed
built-in signature framing, PKCS#7 SignedData-framed signatures without an
explicit signature trust policy, tampered Merkle blocks, and tampered file data
fail closed without ambient trust authority. Ext4 readonly and
shared_blocks ro-compat media is accepted only when the caller requests a
read-only mount. On read-only mounts e2fsd exposes traversal operations
(open without write intent, read, stat, and readdir) and denies
create, mkdir, write, unlink, rmdir, and write-intent open handles
before any media mutation can start. The shared-block fixture exercises
host-marker and depth-2 HTree traversal without adding mutation authority. Ext4
casefold media is accepted for UTF-8 encoding ID 1 (utf8-12.1) with encoding
flags zero. Casefolded lookup, duplicate detection, HTree hash routing, readdir
validation, create, unlink, and rmdir use the Unicode default casefold tables
from lib-fs-name; the documented table version is UNICODE_CASEFOLD_VERSION
(17.0.0). Unsupported encodings, unsupported casefold/hash combinations, and
malformed UTF-8 directory-entry names fail closed before names are exposed or
mutated. fscrypt v2 encrypted+casefold directories support read-only lookup and
readdir by decrypting names through the private keyd authority and hashing
folded plaintext where HTree routing is present; directory mutation under
encrypted parents remains denied. Ext4 MMP media is accepted with a conservative
current policy: read-only mounts validate the MMP block and never write it,
while writable mounts require a clean sequence, write a deterministic
erix-e2fsd claim, verify the checksum and reread state, and reject active,
fsck, stale-inconsistent, malformed, or checksum-bad blocks. Stale owner
takeover is not attempted because e2fsd has no delegated timer authority.
Mount-time replay is implemented for the supported JBD2
dialects: clean descriptor/data/revoke/commit streams can be replayed from
internal journals or from an external journal device mapped in BootConfig.
Standalone journal_dev volumes are not exposed as filesystem providers. The
scanner validates journal UUID binding, journal geometry, legacy transaction
checksum records, checksum-v1-compatible records, CRC32C checksum-v2/v3
descriptor tails, data-block tags, commit records, and journal superblocks,
honors every format-bounded revoke record, handles sequence rollover and
partially checkpointed transactions, and streams every descriptor tag without
fixed replay or revoke arrays. It walks transactions until the journal ring
reaches a clean end instead of imposing a fixed transaction-count cap,
checkpoints committed metadata, marks the journal clean, and clears ext
recovery only after the checkpoint succeeds. Provider-originated writeback also
splits large metadata sets across multiple descriptor/data/commit transactions
and leaves recovery-required set on journal-capacity failure.
JBD2_FEATURE_INCOMPAT_FAST_COMMIT media reserves the fast-commit tail from the
full-commit journal ring, replays any pending full commits first, then accepts
zeroed tail blocks and HEAD/PAD/TAIL records with feature bits zero, the
expected checkpoint transaction ID, and valid CRC-32C tails. Supported
host-originated mutating TLVs (ADD_RANGE, DEL_RANGE, CREAT, LINK,
UNLINK, and INODE) can span multiple tail-delimited segments and replay
through staged writeback. Dentry replay uses the normal checked directory
mutation path for HTree parents, handles large linear directories one block at a
time, preserves checksum tails, and denies encrypted parent directories without
obtaining fscrypt key authority. Unsupported features, unknown tags, bad
tails/checksums, malformed ranges, and inconsistent inode or dentry state fail
closed without checkpointing partial replay. Provider-originated writes
intentionally keep using full JBD2 commits and home checkpoints instead of
emitting new fast-commit deltas.
Metadata checksum writeback is implemented for the superblock, group
descriptors, block/inode bitmaps, inodes, directory checksum tails, and HTree
root/interior/leaf blocks that the current media path mutates. HTree indexed
directories support bounded recursive lookup, readdir, insertion, removal, leaf
splitting, parent split propagation, cycle rejection, depth-1 operation on
ordinary indexed-directory media, and large_dir-gated depth-2 operation;
casefolded HTree directories hash and route folded lookup names. The
deterministic ext4 large-dir fixture carries a depth-2 HTree, while
non-large_dir depth-2 metadata fails closed. The feature registry documents
which current Linux/e2fsprogs ext4 feature bits are accepted, read-only-only,
planned, obsolete-rejected, or unknown-rejected. Obsolete bits such as
compression, dirdata, btree_dir, has_snapshot, replica, lazy_bg,
exclude_inode, and exclude_bitmap are rejected with unit and VM negative
coverage; undefined gap and high future bits are rejected as unknown, and
planned advanced features continue to fail closed until their media semantics
are implemented. Malformed/cyclic HTree layouts, unknown JBD2 feature bits,
unsupported fast-commit records, malformed checksum dialects, unknown ext
feature bits, and unsafe media continue to fail closed by policy.
Validation
cargo fmt --all -- --check- strict
cargo clippy --all-targets --all-features -- -D warnings cargo test --all-targets --all-features- integration image builds through the Filesystem provider work fixture path
Dynamic Boot Artifact Evidence
The runtime image contract documents e2fsd as a dynamic boot artifact.
The image build
packages the ext-family filesystem provider as an ELF64 x86_64 ET_DYN
executable with .erix_dynlink metadata in the signed dynlink-store and
mirrors it under /lib/erix/dynlink with its required shared objects.
Startup remains rootd through procd staged dynamic creation before dynlinkd;
authority remains explicit block, key, and VFS peers. Dynamic packaging and
filesystem mirror records are evidence and launch inputs only; they do not
grant filesystem, loader, object-store, service-discovery, provider-bypass,
block-device, or dynlinkd authority. e2fsd receives only the documented
startup endpoints, peers, and capabilities for its role.
The runtime path retains journal geometry, a staged-record count, and a scratch-owned address index for one single-threaded metadata mutation; sector records themselves occupy the already-authorized clean journal ring. Index overflow is resolved from those records, so the optimization does not define transaction capacity. Startup and orphan-recovery boundaries remain out of line so optimized dynamic executables stay within the linked stack reserve. This private transaction state adds no authority, concurrency, or discovery state.
The authenticated startup rendezvous and private provider request loop wait for work without service-local tick deadlines. Incoming calls must be authority-free: any complete, unwanted capability receipt is retired before an invalid-argument reply through the shared backpressure-safe local-slot helper, and uncertain cleanup requests process teardown. Accepted reply storage remains unchanged through transient kernel backpressure, while terminal transport failures also request process teardown so no accepted-call or provider authority can remain in a quarantined task.
Governance Principles
e2fsd governance is scoped to private ext-family filesystem service behind
vfsd.
The scoped governance rules are:
- It serves ext media only through the generic private provider ABI.
- It must fail closed on malformed metadata, unsupported feature combinations, missing keys, or journal/trust failures.
- It performs media mutation only through the provider-local
blockdendpoint, explicit journal selectors, and per-policy key material obtained from provider-localkeyd. - Its private
keydclient retries transient backpressure without a local ceiling, retains accepted call-message storage until the authoritative reply, and wraps long-lived nonzero request identifiers to one. - Its required startup and provider receives have no local polling deadline; replies remain retained until delivery, unwanted incoming capability receipts are retired, and uncertain cleanup fails stop through process teardown.
- It uses
lib-block's sharedBlockDeviceandBlockClient; e2fsd supplies the endpoint, separate call-message and transfer storage, and syscall/yield callbacks explicitly. Transient backpressure has no service-local ceiling, and accepted calls retain their delegated storage until the authoritative reply arrives. Full transport envelopes therefore do not become hidden stack frames, and the library performs no authority discovery. - It supplies format-defined ext filesystem scratch explicitly through
ProviderState; bitmap, inode-read, zeroing, and all three legacy indirect levels stay out of recursive task frames. Resize reservations are traversed without a fixed-entry cache limit, ordinary legacy pointer growth is iterative, directory checksum work streams every mapped block, and inode checksum CRCs stream without a record-sized copy. Canonical VFS paths are split by their encoded path boundary rather than a component-count array; rename ancestry uses cycle detection instead of a fixed depth allowance. - It transfers inode byte ranges directly in aligned device-block spans, using only one device-sector buffer for unaligned edges. A filesystem-maximum block therefore never becomes an implicit stack frame merely to read or update a subrange. Each file read reuses its just-checksummed raw inode for inline xattr validation, eliminating the immediate duplicate inode read. External attributes and value inodes remain freshly validated; no snapshot survives that request, and encryption, verity, and timestamp policy are unchanged.
- It walks extent records in bounded record chunks and legacy indirect maps in device-sector chunks. Read-only map traversal retains only scalar tree state across recursion rather than a filesystem block at each level.
- It normalizes HTree root and index records into one provider-owned scratch block per format-defined level and reads or mutates leaves through the same explicit workspace. Indexed lookup and split propagation therefore have no task-stack entry arrays or implementation entry-count ceiling. Hash-collision candidates are visited directly instead of being capped by a target array.
- It clears unwritten extent ranges through the provider-owned zeroing buffer and rebuilds edited extent trees online through one provider-owned block per format-defined level. Traversal retains one encoded record, while bottom-up serialization carries only the current node at each level; neither extent count nor intermediate tree-reference count has an implementation ceiling or a task-stack array.
- It validates inode-body and external xattrs, resolves fscrypt contexts, and performs encrypted file I/O through provider-owned scratch. Encrypted gap clearing streams the complete requested range and has no one-block limit.
- It preserves ext xattrs and POSIX ACLs as media metadata only; no public xattr or ACL mutation endpoint is part of the provider contract. Inline-data xattr rebuilds sort directly in the caller's inode buffer, so valid inode geometry rather than a descriptor-table limit determines how many entries fit.
- It never exposes a public
namedservice endpoint or peer-provider authority.
Authority Boundaries
e2fsdmay hold its provider endpoint, provider-localblockd, provider-localkeyd, and authorized same-disk external-journal partition selectors only.- Key and trust material must come from
keyd; no filesystem key material is ambient, residual, or self-asserted in the request body, and each lookup operation selects its material namespace.
Contact
Development occurs in EriX organization and discussions happen in issues and design documents.
No decisions are considered valid without documented rationale.
Maintainers can be reached via email: admin@erikinkinen.fi.