Filesystem
Motor FS is the default filesystem since June 2026. It is a journaling filesystem served by sys-io, with three-role permissions on every entry, advisory locks, and no notion of users, links, or numeric Unix modes.
Motor FS
- Journaling. Writes are batched into transactions, committed to an on-disk redo log, and then checkpointed into the main block area. The design assumes that a block write is atomic and defends against power loss, not against on-disk corruption.
- On-disk structures. 4 KiB blocks, B+ trees for directories and
file data, and inline data for small files (up to 3,640 bytes live in the entry
itself). The partition type is
0x2e. - Block cache of 4,096 blocks (16 MiB) with readahead and a hit/miss/dedup-wait counter set exposed as metrics.
- Operations. stat, create (optionally with an explicit permission set), delete, read, write, resize and truncate, rename with and without replacing the target, directory iteration, parent lookup, permission changes, copy-file-range, flush, and shared or exclusive advisory file locks with per-connection queueing. Entries carry created, modified, and accessed timestamps.
- Limits. File names up to 255 bytes; paths up to 1,024 bytes. File sizes are 64-bit.
- Not there. Symbolic links, hard links, users, groups, ownership, ACLs, sticky directories, numeric modes, and recursive chmod.
The implementation is src/sys/lib/motor-fs (about 10,000 lines) on top
of async-fs, an abstraction that also runs on a Linux host so that images
can be built and tested there. Rust's std::fs works as expected on top of it,
with the permission model below showing through Permissions.
Image layout
| Directory | Purpose |
|---|---|
/system/bin | System commands: rush, sysbox and its command scripts, ripgrep, curl (developer image). Never writable. |
/system/services | sys-init, sys-tty, strobe, russhd, dns-resolver. |
/system/cfg | Configuration: sys-init.cfg, sys-net.toml, sshd.toml, rush.cfg, libc/ (hosts, resolv.conf), ssl/. |
/system/logs | Service logs written by strobe. Interactive may read them; None cannot enter the directory. |
/system/tmp | Scratch space for every role. |
/user/bin | User programs: red, rmux, kibim, httpd, httpd-axum. Interactive may install programs here. |
/user/cfg | Interactive configuration and credentials (red, rmux, kibim, gears, lorry). Hidden from None. |
/user/tmp | Scratch for every role and the default TMPDIR. |
/devtools | Developer image only: bin, llvm, rust, lorry, tests, www, and the writable src and tmp trees. |
Permissions
A Motor FS mode is three permission triplets in System, Interactive, None
order; rw-r----- gives System read and write, Interactive read, and None
nothing. Each triplet is one of rwx, rw-, r-x,
r--, or ---, and permissions are monotonic across roles:
None ⊆ Interactive ⊆ System
- On a directory,
xcontrols listing, traversal, and lookup, andwcontrols creating, deleting, and renaming children. A non-writable file can therefore still be replaced when its parent directory is writable; directory modes are what make a tree read-only. - On a file,
xis a hint enforced by the program loader, which refuses to run a file the caller's role cannot execute. It is enforced cooperatively: a process withCAP_SPAWNcould build a child by hand from a readable file. The boundaries that hold against a hostile process are read, write, and directory traversal, which sys-io enforces, and the unforgeable role. - W^X for executables: an installed ELF is never writable by any role. Scripts are text interpreted by an executable and may be writable where the policy says so.
sys-io learns the role of each client once, when the client connects, by asking the kernel for the peer's capabilities; it never trusts a role sent by the client.
What an image ships with
Images are built with a declarative policy, src/imager/motor-os-permissions.yaml,
that assigns a mode to every destination by the longest matching tree, with exact entries
for two secrets. Smaller images omit trees; they never relax a mode. The main rules:
| Tree | Directories | Files | Scripts | ELF |
|---|---|---|---|---|
| default | rwxr-xr-x | rw-r--r-- | rwxr-xr-x | r-xr-xr-x |
/system/bin | rwxr-xr-x | rw-r--r-- | r-xr-xr-x | r-xr-xr-x |
/system/logs | rwxr-x--- | rw-r----- | r-xr----- | r-xr----- |
/system/tmp, /user/tmp, /devtools/tmp | rwxrwxrwx | rw-rw-rw- | rwxrwxrwx | r-xr-xr-x |
/user, /user/bin, /devtools/src | rwxrwxr-x | rw-rw-r-- | rwxrwxr-x | r-xr-xr-x |
/user/cfg | rwxrwx--- | rw-rw---- | rwxrwx--- | r-xr-x--- |
/devtools/bin | rwxr-xr-x | rw-r--r-- | rwxrwxr-x | r-xr-xr-x |
/system/cfg/sshd.toml and /system/cfg/ssl/ssl-key.pem are
rw-r-----: readable by the Interactive services that need them, invisible to
None. Consequences worth knowing: Interactive cannot create a new top-level directory or
replace /system; it can edit a launcher script in /devtools/bin
in place but not add or remove entries there; only System can create or rotate files in
/system/logs.
The imager classifies each source file by its host execute bit (a host-executable file
must be a #! script or an ELF executable, anything else is rejected), resolves
every mode before it creates the image, and creates non-writable files through a
staging step so that a shipped ELF is never writable and executable at the same time,
even during image construction. An image description that does not name a policy does
not parse.
Files created at run time
- A new regular file starts
rw-for its creator's role,rwxfor higher roles, andr--for lower roles. A new directory startsrwxfor the creator and higher roles andr-xfor lower roles. - A process can narrow its own role's permissions on an entry, and lower roles are
narrowed with it. The one widening allowed is the one-way
rw-tor-xtransition that turns a freshly written program into an executable. A creation call that specifies the complete mode up front also exists, for files that must be linked with their final mode. - Write permission cannot be restored. A Unix-style
chmod -wfollowed bychmod +wfails on the second step with PermissionDenied, for every role. This is what makes a read-only file genuinely read-only. To replace such a file, read it, create a new writable file, write the bytes, delete the read-only entry (which needs onlywon the parent directory), and rename the new file into place.std::fs::copyis not a substitute, because it preserves the source permissions. chmod MODE PATH...takes the nine-character mode in System, Interactive, None order;cppreserves file permissions.
Locks
Advisory file locks (std::fs::File::lock, lock_shared,
try_lock, unlock) are served by a lock manager in sys-io,
keyed by connection, with at most 64 queued waiters per connection. A lock is released
when the file is closed or when its owner's connection to sys-io goes away. Under memory pressure, releasing
a lock is the one filesystem request that is still served, so that waiters queued before
an episode are not stranded.