Files
RedBear-OS/local/docs/SCHEME-NAMESPACE-POPULATION-PLAN.md
T
vasilito dc68054305 restore lost packages from 0.2.3 + fix overwritten 0.2.4 files
- Restore 29 recipe symlinks (libdrm, qtbase, dbus, sddm, pipewire, etc.)
- Restore 33 patches (KDE, libdrm, mesa, pipewire, sddm, wireplumber)
- Restore 20+ local/scripts (audit, lint, test, build helpers)
- Restore src/cook/scheduler.rs, status.rs, gnu-config/
- Restore scripts/patch-inclusion-gate.sh, run_mini1.sh, validate-collision-log.sh
- Recover TLC source from HEAD (was overwritten by 0.2.3 checkout)
- Recover 11 local/docs plans from HEAD (were overwritten)
- Recover qt6-wayland-smoke symlink from HEAD
- Fix MOTD: remove garbled ASCII art, use clean text
- Update version: 0.2.0 -> 0.2.4 in os-release, motd, config
- Reduce filesystem_size: 1536 -> 512 MiB
- Add ABSOLUTE RULE to AGENTS.md: never delete/ignore packages
- Reduce pcid scheme log verbosity: info -> debug
2026-06-19 12:39:14 +03:00

20 KiB
Raw Blame History

Red Bear OS /scheme/ Namespace Population Plan

Version: 1.0 (2026-06-12) Status: Draft — pending review Canonical: local/docs/SCHEME-NAMESPACE-POPULATION-PLAN.md Blocks: Writable rootfs on live ISO, redoxfs disk discovery, ls /scheme/ in shell Cross-references: Linux kobject/uevent, Fuchsia Zircon/Component Manager, seL4 CSpace, Plan 9 per-process namespace, Genode capability routing, MINIX 3 driver model

1. Problem Statement

ls /scheme/ hangs or returns empty in Red Bear OS. Three root causes:

  1. initnsmgr getdents depends on daemons registering — but boot ordering means some schemes haven't registered yet when redoxfs calls fs::read_dir("/scheme") to find disk devices.
  2. No aggregator for block devicesredoxfs must enumerate all disk.* schemes individually, but /scheme/disk.live may not exist yet when the rootfs mount runs at priority 50.
  3. driver-block getdents returns EOPNOTSUPP — individual disk schemes use legacy text-based listing, not proper getdents.

The result: redoxfs can't discover disks, rootfs fails to mount read-write, and /scheme/ listing is incomplete.

2. Design Principles (Informed by Cross-Reference)

2.1 Microkernel Principle (seL4, Red Bear OS)

The kernel tracks scheme IDs (integers), not names. All name→ID mapping happens in userspace (initnsmgr). This is correct per the user's explicit correction:

"Kernel does not have to track id-name mapping! Kernel only knows about IDs. It's a microkernel and stuff like this must be done in userspace"

Implication: We never modify the kernel to "export" scheme names. The namespace is purely a userspace construct managed by initnsmgr.

2.2 Aggregator Pattern (Linux devtmpfs + Fuchsia devcoordinator)

Linux populates /dev via two mechanisms:

  • devtmpfs — kernel auto-creates basic /dev/null, /dev/sda1 etc. at boot
  • udev — userspace daemon receives uevents via netlink, applies rules, creates additional nodes

Fuchsia uses devcoordinator (now driver-index + device-finder):

  • Drivers register devices with the driver manager
  • devcoordinator exposes them via devfs (listable, browsable)
  • Component Manager routes specific devices to components via capability declarations

Red Bear OS should follow the aggregator pattern: userspace daemons that discover, enumerate, and expose device categories through listable scheme namespaces.

2.3 Bootstrap Ordering (Plan 9, Fuchsia)

Plan 9 bootstraps namespace incrementally:

  1. Kernel boots with # device drivers (kernel-resident, like Red Bear's GlobalSchemes)
  2. boot(8) script binds drivers into the namespace
  3. init(8) builds the per-process namespace from /lib/namespace

Fuchsia bootstraps similarly:

  1. Zircon boots, creates root job + resource handles
  2. component_manager starts, receives boot info (device handles from ZBI)
  3. driver_index enumerates drivers, binds them to devices
  4. devfs provides the listable namespace

Red Bear OS boot sequence (current):

bootstrap → initnsmgr (initial schemes: 10 kernel globals + "proc" + "initfs")
  → init starts service targets
  → 10_lived.service (priority 10): registers "disk.live"
  → 40_drivers.target: pcid, graphics, etc.
  → 45_diskd.service (NEW): scans disk.* schemes, registers "diskd"
  → 50_rootfs.service: redoxfs uses diskd to find root device

2.4 Separation of Discovery and Access (Genode, seL4)

Genode separates:

  • Platform session — device discovery (what hardware exists)
  • I/O session — device access (read/write/mmio)

seL4 separates:

  • Device Untyped caps — raw hardware access
  • Platform description — structured description of what devices exist

In Red Bear OS terms: diskd provides discovery (listing), but actual block I/O goes through the original disk.live/disk.sata0 schemes directly. diskd returns OpenResult::OtherScheme so the kernel hands the caller a raw fd to the underlying scheme — zero overhead.

3. Current Architecture

3.1 Kernel Global Schemes (10)

Registered by bootstrap in exec.rsinitnsmgr::run():

Scheme GlobalSchemes Variant Kernel Source
debug Debug scheme/debug.rs
event Event scheme/event.rs
memory Memory scheme/memory.rs
pipe Pipe scheme/pipe.rs
serio Serio scheme/serio.rs
irq Irq scheme/irq.rs
time Time scheme/time.rs
sys Sys scheme/sys/mod.rs
proc Proc scheme/proc/mod.rs
acpi Acpi scheme/acpi.rs
dtb Dtb scheme/dtb.rs

These are registered in the KernelSchemes enum (kernel/src/scheme/mod.rs:438) and exposed to initnsmgr during bootstrap.

3.2 initnsmgr Namespace Manager

Located at local/sources/base/bootstrap/src/initnsmgr.rs.

Key structures:

struct Namespace {
    schemes: HashMap<String, Arc<FdGuard>>,  // name → fd
}
  • open("")Handle::List (directory listing handle)
  • getdents(Handle::List) → iterates schemes HashMap, returns DirEntry for each name
  • Daemons register via NsDup::IssueRegister + sendfd mechanism
  • Bootstrap passes initial set: kernel globals + "proc" + "initfs"

3.3 Userspace Scheme Registration

Daemons register via:

  1. Socket::create() → creates scheme socket
  2. NsDup::IssueRegister → tells initnsmgr the scheme name
  3. sendfd → sends the scheme socket fd to initnsmgr
  4. initnsmgr stores in schemes: HashMap<String, Arc<FdGuard>>

3.4 Current Userspace Schemes (at boot)

Scheme Daemon Priority Source
initfs bootstrap 0 bootstrap exec.rs
proc kernel 0 GlobalSchemes
disk.live lived 10 init.initfs.d/10_lived.service
disk.sata0 ahcid 40 pcid-spawner
disk.virtio0 virtio-blkd 40 pcid-spawner
display vesad 20 init.initfs.d/20_vesad.service
drm redox-drm 30 init.initfs.d/30_graphics.service
net e1000d / virtio-netd 40 pcid-spawner
orbital orbital rootfs (legacy, not used in redbear-full)

3.5 The Root Cause Chain

redoxfs mount (priority 50)
  → fs::read_dir("/scheme") → initnsmgr getdents
  → iterates schemes HashMap → finds "disk.live" (registered at priority 10)
  → is_scheme_category("disk") → true
  → Fd::open("/scheme/disk.live") → reads text listing
  → finds block device → opens /scheme/disk.live/0 → reads UUID
  → UUID matches → mounts as rootfs

The bug: redoxfs retries 20×200ms = 4 seconds. If disk discovery takes longer than 4 seconds (e.g., AHCI probe on real hardware), rootfs mount fails → read-only fallback.

The fix: diskd aggregator + longer timeout + event-driven notification.

4. Solution Architecture

4.1 Component Overview

┌─────────────────────────────────────────────────────────┐
│                    /scheme/ namespace                    │
│                   (initnsmgr)                           │
│                                                          │
│  Kernel globals:                                         │
│    debug, event, memory, pipe, serio, irq,              │
│    time, sys, proc, acpi, dtb                            │
│                                                          │
│  Boot schemes (initfs):                                  │
│    initfs, disk.live, display                            │
│                                                          │
│  Aggregators:                                            │
│    diskd  ← /scheme/diskd lists ALL block devices       │
│                                                          │
│  Hardware daemons (post-drivers.target):                 │
│    disk.sata0..7 (ahcid)                                │
│    disk.virtio0..7 (virtio-blkd)                        │
│    disk.nvme0..7 (nvmed)                                │
│    disk.usb0..7 (usbscsid)                              │
│    disk.ide0..3 (ideid)                                 │
│    net (e1000d, virtio-netd, ixgbed, rt8169d)          │
│    drm (redox-drm)                                      │
│                                                          │
│  System daemons (post-rootfs):                           │
│    audio (audiod)                                       │
│    firmware (firmware-loader)                            │
│    input (evdevd)                                       │
│    udev (udev-shim)                                     │
│    ...                                                  │
└─────────────────────────────────────────────────────────┘

4.2 diskd — Disk Aggregator Daemon (IMPLEMENTED)

Location: local/recipes/system/diskd/ Scheme name: diskd Binary: /usr/bin/diskd Status: Code complete, cargo check/clippy/fmt clean

How it works:

  1. At boot (priority 45), diskd starts
  2. Probes /scheme/disk.live, /scheme/disk.sata0..7, /scheme/disk.virtio0..7, etc.
  3. For each found scheme, reads its text listing to discover devices and partitions
  4. Registers scheme diskd with initnsmgr
  5. getdents on diskd: returns real DirEntry with DirentKind::BlockDev
  6. open("0") or open("0p1") opens the underlying scheme and returns OtherScheme (zero-copy — caller talks directly to the block device)

Why this solves the root cause:

  • redoxfs currently must enumerate ALL /scheme/disk.* individually — 50+ Fd::open calls
  • With diskd, redoxfs does ONE read_dir("/scheme/diskd") to get all block devices
  • diskd already did the probing and enumeration
  • Even if AHCI hasn't registered yet, diskd's retry logic handles late registration
  • redoxfs timeout only needs to wait for diskd to be ready, not all individual schemes

4.3 Changes Required to Existing Components

4.3.1 redoxfs — Use diskd for disk discovery

File: local/sources/redoxfs/src/bin/mount.rs (function filesystem_by_uuid)

Current behavior:

// Line 224: fs::read_dir("/scheme") → filter is_scheme_category("disk")
// For each disk.* scheme: open, read listing, find block devices, check UUID
// Retry 20×200ms = 4 seconds total

New behavior (two-path approach):

fn filesystem_by_uuid(uuid: &[u8; 16]) -> Option<File> {
    // Path A: Try diskd aggregator first (fast, single enumeration)
    if let Some(f) = try_diskd_uuid(uuid) {
        return Some(f);
    }
    // Path B: Fall back to legacy per-scheme enumeration
    // (for backwards compat and environments without diskd)
    try_legacy_uuid_search(uuid)
}

fn try_diskd_uuid(uuid: &[u8; 16]) -> Option<File> {
    // Wait for diskd scheme to appear
    for _ in 0..50 {  // 50 × 200ms = 10 seconds
        if let Ok(dir) = fs::read_dir("/scheme/diskd") {
            for entry in dir {
                let entry = entry.ok()?;
                let name = entry.file_name().to_string_lossy().into_owned();
                // Open the block device via diskd (which proxies to underlying scheme)
                let path = format!("/scheme/diskd/{name}");
                if let Ok(mut f) = File::open(&path) {
                    if check_uuid(&mut f, uuid) {
                        return Some(f);
                    }
                }
            }
        }
        thread::sleep(Duration::from_millis(200));
    }
    None
}

4.3.2 init.initfs.d — Add diskd service

New file: local/sources/base/init.initfs.d/45_diskd.service

[[service]]
name = "diskd"
command = "/usr/bin/diskd"
priority = 45
requires = ["lived"]

This ensures diskd starts after lived (which provides disk.live at priority 10) and before rootfs mount (priority 50).

4.3.3 config/redbear-mini.toml — Add diskd package

Add diskd to the [packages] section so it's included in the image.

4.4 /scheme/ Namespace Completeness Matrix

After all changes, /scheme/ will expose:

Category Scheme Name Provider getdents Notes
Kernel globals
Debug debug kernel GlobalSchemes real DirEntry kernel/src/scheme/debug.rs
Event event kernel GlobalSchemes real DirEntry kernel/src/scheme/event.rs
Memory memory kernel GlobalSchemes EOPNOTSUPP No sub-entries expected
Pipe pipe kernel GlobalSchemes EOPNOTSUPP Anonymous, no listing
Serio serio kernel GlobalSchemes real DirEntry kernel/src/scheme/serio.rs
IRQ irq kernel GlobalSchemes real DirEntry cpu-XX entries
Time time kernel GlobalSchemes real DirEntry CLOCK_* entries
Sys sys kernel GlobalSchemes real DirEntry scheme:/scp/ sub-entries
Proc proc kernel GlobalSchemes real DirEntry pid entries
ACPI acpi kernel GlobalSchemes real DirEntry rxsdt, kstop
DTB dtb kernel GlobalSchemes EOPNOTSUPP Single blob
Bootstrap
InitFS initfs bootstrap real DirEntry initramfs contents
Storage
Live disk disk.live lived text listing virtio/ahci backend
SATA disk disk.sata0..7 ahcid text listing per-disk scheme
VirtIO disk disk.virtio0..7 virtio-blkd text listing per-disk scheme
NVMe disk disk.nvme0..7 nvmed text listing per-disk scheme
USB disk disk.usb0..7 usbscsid text listing per-disk scheme
IDE disk disk.ide0..3 ideid text listing per-disk scheme
Aggregators
Disk aggregator diskd diskd real DirEntry BlockDev THIS PLAN
Display
Framebuffer display vesad EOPNOTSUPP Legacy text listing
DRM/KMS drm redox-drm real DirEntry card0, card0-*, connectors
Network
Ethernet net e1000d/virtio-netd real DirEntry interface entries
Input
Input events input evdevd real DirEntry event0, event1, ...
Audio
Audio audio audiod text listing Audio streams
System
Firmware firmware firmware-loader real DirEntry GPU/device blobs
Udev udev udev-shim real DirEntry Linux-compatible device nodes

4.5 initnsmgr getdents — Already Correct

The initnsmgr getdents implementation at line 402-439 of initnsmgr.rs iterates schemes: HashMap<String, Arc<FdGuard>> and emits a DirEntry for each registered scheme. This is already correct — it will list any scheme that has been registered, including diskd.

The /scheme/ listing issue was NOT a getdents bug — it was a timing issue:

  • Daemons hadn't registered yet when fs::read_dir("/scheme") was called
  • The fix is proper boot ordering (diskd at priority 45) and the diskd aggregator

5. Future Enhancements (Beyond Current Scope)

5.1 Event-Driven Discovery (uevent Equivalent)

Currently diskd probes statically at startup. For hotplug (USB drives, PCIe hot-add):

  • pcid sends a uevent-like notification when a new PCI device appears
  • diskd listens for these notifications and re-scans
  • Alternative: inotify-like watch on /scheme/ (would need kernel support)

This mirrors Linux's uevent netlink broadcast → udev listener pattern.

5.2 devfs-Style Aggregation

A future devfsd could provide Linux-compatible /dev paths:

/scheme/devfs/sda     → /scheme/diskd/0
/scheme/devfs/sda1    → /scheme/diskd/0p1
/scheme/devfs/null    → /scheme/debug (write sink)
/scheme/devfs/zero    → /scheme/memory (zero-filled read)
/scheme/devfs/random  → /scheme/entropy
/scheme/devfs/tty0    → /scheme/display.0
/scheme/devfs/input/event0 → /scheme/input/event0

This would be the Fuchsia devcoordinator equivalent — a unified, Linux-compatible device namespace. The udev-shim already provides parts of this.

5.3 Per-Process Namespace (Plan 9 Style)

Plan 9's bind and mount allow per-process namespace customization. Red Bear OS's setrens syscall provides a basic version (switch namespace fd). Future enhancement:

  • Per-container namespaces (for contain and future container runtime)
  • Namespace inheritance rules (like Fuchsia's .cml capability routing)
  • chroot-like namespace restriction for sandboxed applications

5.4 Capability-Based Access (seL4 Style)

seL4 uses CSpace (capability spaces) for device access. Each process has a CSpace that contains only the capabilities it should have access to. Red Bear OS could evolve toward this model:

  • initnsmgr tracks which schemes each process can access
  • open("/scheme/net") checks the caller's capability set
  • setrens evolves from "switch namespace" to "restrict to capability subset"

This would require kernel changes (per-process scheme allowlists), which is beyond current scope but worth keeping in mind for security hardening.

6. Implementation Plan

Phase 1 — Immediate Fix (This Session)

Step Action Files Status
1 diskd daemon implementation local/recipes/system/diskd/ Done
2 Add diskd init service local/sources/base/init.initfs.d/45_diskd.service Pending
3 Add diskd to config config/redbear-mini.toml Pending
4 Modify redoxfs to use diskd local/sources/redoxfs/src/bin/mount.rs Pending
5 Commit uncommitted changes driver-manager, config Pending
6 Remove pcid debug logging local/sources/base/drivers/pcid/src/cfg_access/fallback.rs Pending
7 Make C++ header fix durable mk/prefix.mk Pending
8 Build and test ISO ./local/scripts/build-redbear.sh redbear-mini Pending
9 Boot test in QEMU scripts/run_mini1.sh Pending

Phase 2 — Hotplug Support (Future)

Step Action Dependencies
1 pcid uevent notification pcid-spawner enhancement
2 diskd dynamic re-scan uevent listener
3 devfsd Linux-compatible /dev udev-shim + diskd integration

Phase 3 — Namespace Security (Future)

Step Action Dependencies
1 Per-process scheme allowlist kernel scheme access control
2 Container namespace isolation contain enhancement
3 Capability routing initnsmgr capability model

7. Cross-Reference Summary

System Mechanism Red Bear Equivalent Status
Linux kobject/uevent → udev → /dev pcid → diskd → /scheme/diskd Phase 1
Fuchsia devcoordinator → devfs initnsmgr → diskd Phase 1
seL4 CSpace capabilities setrens (basic) Phase 3
Plan 9 bind/mount per-process setrens (basic) Phase 3
Genode Platform session redox-driver-sys Existing
MINIX 3 driver announce → devfs daemon register → initnsmgr Existing

8. Risk Assessment

Risk Mitigation
diskd probe takes too long on real hardware Increase retry count (50×200ms = 10s), add event-driven re-scan
diskd crashes and disk namespace disappears init service auto-restart (restart = true in service file)
redoxfs legacy path broken by diskd changes Two-path approach: try diskd first, fall back to legacy
Boot ordering regression (diskd starts before lived) Explicit requires = ["lived"] in service file
diskd returns stale device list after hotplug Phase 2: event-driven re-scan; Phase 1: manual re-trigger via signal

9. Acceptance Criteria

  1. ls /scheme/ in shell shows all registered schemes (no hang, no empty)
  2. ls /scheme/diskd/ shows all block devices discovered by diskd
  3. redoxfs mounts rootfs read-write via diskd path
  4. /tmp is writable by non-root users
  5. Boot completes to login prompt with zero warnings
  6. QEMU boot test passes: scripts/run_mini1.sh reaches login prompt
  7. ./local/scripts/build-redbear.sh redbear-mini produces working ISO