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). Commands initially deny write access to every role. |
/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. Runtime permission changes can make an initially read-only directory writable. - 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. - Image W^X: a shipped ELF initially grants no role write access. 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.
Changes also need CAP_FS_WRITE. Without it a process can stat, read, and
list what its role allows, and every other request fails with
PermissionDenied, file locks included. The capability never overrides the
permissions above: a change needs both. See
Capabilities.
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, /devtools/lorry | 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. With the initial modes, 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
during image construction,
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. It may also change
rw-tor-x, orr-xtorwx. These rules apply to files and directories, for every role. Directrw-torwxremains denied; userw-→r-x→rwxfor an editable executable. Exact-permissions creation is also available. - Every change must fit within the immediately higher role's permissions; System
has no higher role. Widening does not automatically restore lower-role permissions.
r-xis not a permanent seal: System can make a shipped ELF writable, and a lower role can make anr-xdirectory writable when its higher-role ceiling isrwx. - A role at
r--or---still cannot widen itself. The std readonly round-trip (rw-→r--→rw-) therefore fails on its second step. Replacing such a file requires reading it, writing a new file, and renaming it into place under a writable parent.std::fs::copypreserves source permissions. chmod MODE PATH...takes the nine-character mode in System, Interactive, None order;cppreserves file permissions.
For offline changes, see imager chmod and imager resize. These host commands edit an image's permissions or copy it into an image with a different data-partition size.
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.
After wait() or try_wait() reports process completion, its locks
no longer block other clients: acquisition checks disconnected owners even if the
connection cleanup task has not run yet. 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.