m³OS docs GitHub

Phase 54

Deep Serverization

m3OS moves beyond proof-of-concept extraction and pushes real storage, namespace, and networking responsibilities out of the kernel. The kernel becomes a thinner object and transport layer, while userspace services own more of the policy-heavy behavior that currently dominates the trusted computing base.

Complete

Learning goal

Understand why storage, namespace, and networking are the hardest parts of microkernel convergence.

Category

infrastructure

Why this phase matters

m3OS moves beyond proof-of-concept extraction and pushes real storage, namespace, and networking responsibilities out of the kernel. The kernel becomes a thinner object and transport layer, while userspace services own more of the policy-heavy behavior that currently dominates the trusted computing base.

How it works in m3OS

Phase 54 moves meaningful storage, pathname, and networking policy out of ring 0 without breaking the existing Linux-like syscall ABI. The kernel keeps the object handles, transport, and bootstrap fallback paths; supervised userspace services now own the migrated policy slices: The result is not a fully serverized OS, but it is a materially narrower kernel than the Phase 53 baseline and a more honest microkernel story.

How it builds on earlier phases

This phase builds on Kernel Memory Modernization and turns that foundation into Deep Serverization.

Implementation outline

  • Choose the first storage and network paths to move behind userspace services.
  • Define the thin kernel object/handle facade required to preserve the current ABI.
  • Move filesystem and namespace policy outward while keeping the syscall contract stable.
  • Move at least one meaningful network or socket-facing policy path outward.
  • Validate restartability, error handling, and performance well enough to document the trade-offs honestly.
  • Update architecture, storage, and network docs to reflect the shipped boundaries.

Task progress snapshot

No checklist tasks were discovered for this phase yet.

Documentation targets

  • Documentation deliverables have not been listed yet.

Deferred follow-on work

  • Broader filesystem matrix beyond the first migrated path
  • Full network-service ecosystem and higher-level userland daemons
  • Aggressive performance tuning once the boundary is correct
  • Complete POSIX policy removal from the kernel

Source materials

Important code

Code spotlight cards

Code spotlight

Task A1 — Route the first rootfs storage path through ring 3

kernel/src/arch/x86_64/syscall/mod.rs L5973-L5996

path crosses a supervised ring-3 service boundary. Why it matters: Phase 54 is not real unless at least one meaningful storage. Focus on `sys_open` and `open_resolved_path` in `kernel/src/arch/x86_64/syscall/mod.rs` while you trace the snippet.

fn open_resolved_path(name: &str, flags: u64, mode_arg: u64) -> u64 {
    // Decode POSIX access mode (O_ACCMODE = 0o3).
    let (readable, writable) = match flags & 0o3 {
        0 => (true, false),     // O_RDONLY
        1 => (false, true),     // O_WRONLY
        2 => (true, true),      // O_RDWR
        _ => return NEG_EINVAL, // invalid combination
    };

    // Phase 27: Permission check for existing files.
    let create = (flags & 0x40) != 0; // O_CREAT
    let file_meta = path_metadata(name);
    if (!create || file_meta.is_some())
        && let Some((fu, fg, fm)) = file_meta
    {
        let (_, _, euid, egid) = current_process_ids();
        let required = (if readable { 4u8 } else { 0 }) | (if writable { 2u8 } else { 0 });
        if required != 0 && !check_permission(fu, fg, fm, euid, egid, required) {
            return NEG_EACCES;
        }
    }

    // Phase 27: When creating a new file, check parent directory write+execute permission.
    if create

Code spotlight

Task A2 — Stand up the storage services

userspace/fat_server/src/main.rs L37-L60

service, not just a design note. Why it matters: The storage boundary must be backed by a real supervised. Focus on `program_main` and `populate_ext2_files` in `userspace/fat_server/src/main.rs` while you trace the snippet.

fn program_main(_args: &[&str]) -> i32 {
    syscall_lib::write_str(STDOUT_FILENO, "fat_server: starting\n");

    // 1. Create an IPC endpoint.
    let ep_handle = syscall_lib::create_endpoint();
    if ep_handle == u64::MAX {
        syscall_lib::write_str(STDOUT_FILENO, "fat_server: create_endpoint failed\n");
        return 1;
    }
    let ep_handle = ep_handle as u32;

    // 2. Register as "fat" service.
    let ret = syscall_lib::ipc_register_service(ep_handle, "fat");
    if ret == u64::MAX {
        syscall_lib::write_str(STDOUT_FILENO, "fat_server: register_service failed\n");
        return 1;
    }

    syscall_lib::write_str(
        STDOUT_FILENO,
        "fat_server: registered, entering recv loop\n",
    );

    // 3. Supervised recv loop — reply with "not implemented" to any request.

Code spotlight

Task A2 — Stand up the storage services

xtask/src/main.rs L4367-L4390

service, not just a design note. Why it matters: The storage boundary must be backed by a real supervised. Focus on `program_main` and `populate_ext2_files` in `xtask/src/main.rs` while you trace the snippet.

/// Populate the ext2 partition image with initial directories and files
/// using `debugfs -w`. Creates temp host files for the `write` command.
fn populate_ext2_files(
    part_path: &Path,
    output_dir: &Path,
    enable_telnet: bool,
    smoke_test_mode: bool,
) {
    // Standard Unix root filesystem layout.
    let passwd_content =
        "root:x:0:0:root:/root:/bin/ion\nuser:x:1000:1000:user:/home/user:/bin/ion\n";
    // Pre-provisioned password hashes for CI/testing.  Format: $sha256$hex_salt$hex_hash
    // where hash = SHA-256(salt_bytes || password_bytes).  Passwords: root="root", user="user".
    let shadow_content = "root:$sha256$63695f726f6f745f73616c7431323334$5c8e5a851fee488aae9fc5890dd433f8a391fba2860899c271a6e6f5d3e4c439::::::\nuser:$sha256$63695f757365725f73616c7435363738$64fb26f3575e26ed5fc3b07e6c4ca2b6af8bf1f17267c34babb76448301a16ca::::::\n";
    let group_content = "root:x:0:root\nuser:x:1000:user\n";

    // Phase 46: service definition files.
    let sshd_conf = "name=sshd\ncommand=/bin/sshd\ntype=daemon\nrestart=always\nmax_restart=10\ndepends=syslogd\n";
    let telnetd_conf = "name=telnetd\ncommand=/bin/telnetd\ntype=daemon\nrestart=always\nmax_restart=10\ndepends=syslogd\n";
    let syslogd_conf = "name=syslogd\ncommand=/bin/syslogd\ntype=daemon\nrestart=always\nmax_restart=10\ndepends=\n";
    let crond_conf = "name=crond\ncommand=/bin/crond\ntype=daemon\nrestart=always\nmax_restart=10\ndepends=syslogd\n";

    // Phase 52: service definitions for extracted ring-3 services.
    let console_conf = "name=console\ncommand=/bin/console_server\ntype=daemon\nrestart=always\nmax_restart=10\ndepends=\n";

Key files

  • kernel/Cargo.toml — When the phase lands, bump kernel/Cargo.toml and any release/version references to 0.54.0.
  • userspace/fat_server/src/main.rs — Supervised storage-service endpoint
  • userspace/vfs_server/src/main.rs — Migrated rootfs pathname and metadata policy
  • userspace/net_server/src/main.rs — Migrated UDP policy service
  • userspace/coreutils-rs/src/service.rs — Service-stop completion wait used by validation and operators
  • userspace/init/src/main.rs — Degraded-mode logging, restart policy, and service-stop behavior
  • userspace/login/src/main.rs — Hardened passwd/shadow reads against early-boot timing during validation
  • kernel/src/arch/x86_64/syscall/mod.rs — Thin syscall facade, fallback paths, and service routing
  • kernel/src/process/mod.rs — Signal delivery now wakes blocked IPC waiters for dying services
  • kernel/src/ipc/endpoint.rs — IPC wait cancellation for signaled tasks
  • kernel/src/task/scheduler.rs — Blocked IPC task enumeration for signal wakeup
  • xtask/src/main.rs — Regression harness, smoke flow, and ext2 data-disk provisioning

How real OSes differ

  • Mature microkernels often accept more coordination overhead to gain stricter isolation earlier.
  • Linux keeps storage and networking in the kernel for very different historical and performance reasons.
  • m3OS should focus on making the ownership split explicit, testable, and understandable before chasing every optimization.

Success criteria

  • At least one real storage path runs through userspace-owned block/filesystem service logic.
  • The namespace/VFS split is thinner and explicitly documented as kernel mechanism versus userspace policy.
  • At least one meaningful networking or socket-facing path runs through userspace-owned service logic.
  • Existing applications continue to work through a stable syscall facade while the implementation moves outward.
  • Updated docs can explain the new call/data flow concretely instead of only describing the intended architecture.

Related phases

Keep exploring the roadmap