e2fsd is the private ext-family filesystem provider daemon for EriX
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Erik Inkinen f3eec737b7
All checks were successful
CI / markdown (push) Successful in 11s
CI / test (push) Successful in 7m23s
chore: Merge native CLI development into main
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: 6e8cd263d8
Selected feature: 63ff188373

Publish this integration point following the requested cross-repository merge. Preserve the feature branch and immutable dependency objects for reproducibility; do not squash, rebase or rewrite existing commits.
2026-09-12 08:28:42 +03:00
.github build: Pin dependency and CI helper source commits 2026-09-12 07:45:18 +03:00
src build: Pin dependency and CI helper source commits 2026-09-12 07:45:18 +03:00
.editorconfig Initial commit 2026-04-26 08:06:26 +02:00
.gitignore Initial commit 2026-04-26 08:06:26 +02:00
.markdownlint-cli2.yaml Tighten CI markdown policy 2026-05-22 15:10:00 +03:00
ARCHITECTURE.md fix: Separate exact file creation from content authority 2026-09-08 05:44:52 +03:00
Cargo.toml build: Pin dependency and CI helper source commits 2026-09-12 07:45:18 +03:00
CODE_OF_CONDUCT.md docs: Synchronize shared contribution and review policies 2026-09-12 06:38:10 +03:00
CONTRIBUTING.md build: Pin dependency and CI helper source commits 2026-09-12 07:45:18 +03:00
LICENSE Initial commit 2026-04-26 08:06:26 +02:00
linker.ld fix: keep filesystem state below the process stack 2026-07-29 08:39:37 +03:00
README.md fix: Separate exact file creation from content authority 2026-09-08 05:44:52 +03:00
ROADMAP.md fix: Separate exact file creation from content authority 2026-09-08 05:44:52 +03:00
rustfmt.toml Initial commit 2026-04-26 08:06:26 +02:00
SECURITY.md docs: Synchronize shared contribution and review policies 2026-09-12 06:38:10 +03:00

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 blockd endpoint
  • keep provider authority private with no named entry 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 blockd endpoint, explicit journal selectors, and per-policy key material obtained from provider-local keyd.
  • Its private keyd client 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 shared BlockDevice and BlockClient; 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 named service endpoint or peer-provider authority.

Authority Boundaries

  • e2fsd may hold its provider endpoint, provider-local blockd, provider-local keyd, 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.