From 52f48ed2a98f2181cd5b581f298926f1a1d2e26d Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 8 Nov 2026 14:21:57 +0000 Subject: [PATCH] wip(blocks): a BAM flush reads and writes only the pages that hold the volume's bits (#155) [skip ci] Not yet accepted. bam_flush_to_disk() and bam_sync_from_disk() read and wrote every page of the BAM; with the stick's BAM sized for 256 GiB (6144 devblocks, 24 MiB) every flush of a dirty block moved 24 MiB each way. They now touch only the pages that hold the slot's bits -- its reserved bits and one per user block (bam_pages_used()) -- the pages past them are never set, so the bytes on disk are the same. Test (qemu_session.py bam_flush, --target qemu-stick --stick-gib 16): three SAVE-BUFFERS of an Artemis block, each timed, then the BAM hashed. Before: 5.1 / 5.6 / 6.1 s (the 2 s limit fails; it was set after seeing this baseline). After: 1.1 / 1.1 / 1.1 s. The BAM's bytes the same either way: sha256 79197a40...b9e44b50, 5 non-zero bytes. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2 --- .../runs/doe-amd64-20261108-141717.csv | 0 .../runs/doe-amd64-20261108-141943.csv | 0 .../amd64/qemu-amd64-20261108-141717.log | 177 ++++++++++++++++++ .../amd64/qemu-amd64-20261108-141943.log | 177 ++++++++++++++++++ scripts/qemu_session.py | 40 +++- v3/src/block_subsystem.c | 25 ++- 6 files changed, 412 insertions(+), 7 deletions(-) create mode 100644 experiments/bare_metal/runs/doe-amd64-20261108-141717.csv create mode 100644 experiments/bare_metal/runs/doe-amd64-20261108-141943.csv create mode 100644 logs/20261108-141717/amd64/qemu-amd64-20261108-141717.log create mode 100644 logs/20261108-141943/amd64/qemu-amd64-20261108-141943.log diff --git a/experiments/bare_metal/runs/doe-amd64-20261108-141717.csv b/experiments/bare_metal/runs/doe-amd64-20261108-141717.csv new file mode 100644 index 00000000..e69de29b diff --git a/experiments/bare_metal/runs/doe-amd64-20261108-141943.csv b/experiments/bare_metal/runs/doe-amd64-20261108-141943.csv new file mode 100644 index 00000000..e69de29b diff --git a/logs/20261108-141717/amd64/qemu-amd64-20261108-141717.log b/logs/20261108-141717/amd64/qemu-amd64-20261108-141717.log new file mode 100644 index 00000000..648e925b --- /dev/null +++ b/logs/20261108-141717/amd64/qemu-amd64-20261108-141717.log @@ -0,0 +1,177 @@ +[=3h[=3h[=3hBdsDxe: loading Boot0001 "UEFI QEMU QEMU USB HARDDRIVE 1-0000:00:03.0-1" from PciRoot(0x0)/Pci(0x3,0x0)/USB(0x0,0x0) +BdsDxe: starting Boot0001 "UEFI QEMU QEMU USB HARDDRIVE 1-0000:00:03.0-1" from PciRoot(0x0)/Pci(0x3,0x0)/USB(0x0,0x0) +[=3hStarKernel UEFI Loader +Loading kernel from ESP... +[CKPT 001] Entered efi_main - ConOut live +RAW SERIAL UP +[CKPT 002] Serial (COM1) initialized +Monolithic build - kernel linked directly +Collecting boot information... +CmdLine: from starforth.cfg +CmdLine: parsed OK +[CKPT 004] Command line parsed +[CKPT 005] Kernel stack allocation decided +[CKPT 006] Boot info collected (ACPI table located) +GOP: linear framebuffer found +[CKPT 007] GOP: linear framebuffer found +[CKPT 008] About to enter ExitBootServices retry loop +EBS... +EBS OK +Calling kernel_main (monolithic)... + + + _____ _ _ __ _ + / ____| | | |/ / | | + | (___ | |_ __ _ _ __| ' / ___ _ __ _ __ ___| | + \___ \| __/ _` | '__| < / _ \ '__| '_ \ / _ \ | + ____) | || (_| | | | . \ __/ | | | | | __/ | + |_____/ \__\__,_|_| |_|\_\___|_| |_| |_|\___|_| + +LithosAnanke v4.0.0-alpha.3 amd64 +Architecture: amd64 +Build: Nov 8 2026 14:17:11 + +UEFI BootServices: EXITED +Console: serial line is a 16550 at port 0x00000000000003f8 (COM1, probed) + +=== StarKernel Boot Information === +Memory map entries: 128 +Total memory: 1023 MB +Usable memory: 965 MB +=================================== + +PMM initialized. +PMM statistics: + Total pages: 248623 + Free pages : 247096 + Used pages : 1527 + Total MB : 971 + Free MB : 965 + Used MB : 5 + +VMM initialized (mapped RAM, CR3 switched) +VMM initialized (mapped RAM, CR3 switched) +VMM self-test: mapped OK at 0xffff800000000000 +VMM self-test complete. + +IDT installed. + +APIC: init... +APIC: IA32_APIC_BASE MSR=0x00000000fee00900 +APIC: stale-ISR drain: 0 EOI(s) issued +APIC: initialized (xAPIC MMIO, TPR=0, SIVR=0x1FF, EOI-clear) +APIC: init done + +I/O APIC: init... +I/O APIC: base=0xfec00000, gsi_base=0, overrides=5 + override: source=00 gsi=2 flags=0x0000 + override: source=05 gsi=5 flags=0x000d + override: source=09 gsi=9 flags=0x000d + override: source=0a gsi=10 flags=0x000d + override: source=0b gsi=11 flags=0x000d +i8042: keyboard ACKed enable-scanning +i8042: IRQ1 enabled in controller config byte +I/O APIC: keyboard IRQ1 routed (masked) + +Timer: init... +Timer: init start +Timer: PM_TMR_BLK discovered from FADT at port 1544 +Timer: VM mode detected (hypervisor present). +Timer: HPET calibration disabled (VM-exit MMIO would poison timing). +Timer: WARNING: invariant TSC not present under hypervisor. +Timer: continuing in RELATIVE mode (no determinism guarantees). +Timer: RDTSCP not present; using RDTSC (less serialized). +Timer: CPUID frequency unavailable; trying PM Timer... +Timer: trust=1 (0=NONE,1=REL,2=ABS), TSC=2089810820 Hz +Timer: init done + +Kernel heap initialized. +Heap statistics: + Total bytes: 536870872 + Free bytes: 536870872 + Used bytes: 0 + Peak bytes: 0 + Heap base addr: 24641536 + Heap end addr: 561512448 + +Heartbeat: init... +APIC Timer: calibrating... +APIC Timer: apic_hz=1000098709, tick_hz=100, initial_count=10000987 +APIC Timer: configured (masked, ready to start) +Heartbeat: init done +Kernel initialization complete. +Boot successful! + +Boot disk: a StarshipOS stick +System: StarForth v4 (system=v4) +StarForth v4: one host node, the F18-derived engine +V4: capsule v4:sys:map-64.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:map-64.f18 capsule_hash=0x949eb6a1e9260e49 +V4: capsule v4:sys:core.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:core.f18 capsule_hash=0xb8f167892ec18c28 +V4: capsule v4:sys:input.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:input.f18 capsule_hash=0x85d3ec486d929a79 +V4: capsule v4:sys:dict.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:dict.f18 capsule_hash=0x1379bd3b5de811dc +V4: capsule v4:sys:codegen.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:codegen.f18 capsule_hash=0x36d2ae84d2911b90 +V4: capsule v4:sys:compile.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:compile.f18 capsule_hash=0x11145c4c2ab819d8 +V4: capsule v4:sys:quit.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:quit.f18 capsule_hash=0x43cadf3b21ddbf3e +V4: capsule v4:sys:forth.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:forth.f18 capsule_hash=0x16cab4a1268b85da +V4: capsule v4:sys:numout.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:numout.f18 capsule_hash=0x85a240ad3fb2b299 +V4: capsule v4:sys:words.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:words.f18 capsule_hash=0xb1d381f927d9f14e +V4: capsule v4:sys:system.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:system.f18 capsule_hash=0xd92203664c2915bd +V4: capsule v4:sys:qmath.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:qmath.f18 capsule_hash=0xdb4140713dd857f3 +V4: capsule v4:sys:blocks.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:blocks.f18 capsule_hash=0x76307ef48678dc2a +V4: capsule v4:sys:log.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:log.f18 capsule_hash=0xfc6540e6b824a52b +V4: capsule v4:sys:acl.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:acl.f18 capsule_hash=0x6845aa048db7eb22 +V4: capsule v4:sys:end.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:end.f18 capsule_hash=0x5ef01312c07b79cc +PARITY:V4_ROM words=2372 rom_hash=0x87b23d3ae2643c8d instructions=59145258 +V4: capsule v4:forth79.4th signature: missing (unsigned) +PARITY:V4_CAPSULE name=v4:forth79.4th capsule_id=0x4055641ee17d176b capsule_hash=0x4055641ee17d176b dict_hash=0x033e1c05c09a1df8 +PARITY:V4_POST tests=538 pass=538 fail=0 +PARITY:V4_SYSTEM word_count=317 dict_hash=0xfec8c47cfc6f437f +PARITY:OK +POST: PASSED +[HADES][INFO ] [KRELTSC: 0] blk: raw device LBN 2048..3071 (1024 blocks) +PCI: init... +PCI: ECAM mapped (amd64) +virtio-rng: no device on PCI bus 0 +rng: backend = rdrand +entropy: ready +virtio-input: no device on PCI bus 0 +Starting heartbeat... +APIC Timer: started (LVT=0x00020020 ICR=10000987) +I/O APIC: keyboard IRQ1 unmasked +Heartbeat running. +blkio_usb: MSC device ready +Artemis: grown to fill the stick +[HADES][INFO ] [KRELTSC: 16653709542] blk: disk 'StarForth Volume' v2 LBN 3072..12132441 (12129370 us +Artemis: the stick's partition attached +[HADES][INFO ] [KRELTSC: 16675740886] blk: disk 'StarForth Volume' v2 LBN 12132442..12515983 (383542 +[HADES][INFO ] [KRELTSC: 16705753972] MINT verify: identity reads back correctly +[Hera] Zuse: genesis minted onto attached thumbdrive +[zuse@Hera] ok> 3172 BLOCK DROP UPDATE +[zuse@Hera] ok +[zuse@Hera] ok> SAVE-BUFFERS +[zuse@Hera] ok +[zuse@Hera] ok> 3173 BLOCK DROP UPDATE +[zuse@Hera] ok +[zuse@Hera] ok> SAVE-BUFFERS +[zuse@Hera] ok +[zuse@Hera] ok> 3174 BLOCK DROP UPDATE +[zuse@Hera] ok +[zuse@Hera] ok> SAVE-BUFFERS +[zuse@Hera] ok +[zuse@Hera] ok>  \ No newline at end of file diff --git a/logs/20261108-141943/amd64/qemu-amd64-20261108-141943.log b/logs/20261108-141943/amd64/qemu-amd64-20261108-141943.log new file mode 100644 index 00000000..2d286ae7 --- /dev/null +++ b/logs/20261108-141943/amd64/qemu-amd64-20261108-141943.log @@ -0,0 +1,177 @@ +[=3h[=3h[=3hBdsDxe: loading Boot0001 "UEFI QEMU QEMU USB HARDDRIVE 1-0000:00:03.0-1" from PciRoot(0x0)/Pci(0x3,0x0)/USB(0x0,0x0) +BdsDxe: starting Boot0001 "UEFI QEMU QEMU USB HARDDRIVE 1-0000:00:03.0-1" from PciRoot(0x0)/Pci(0x3,0x0)/USB(0x0,0x0) +[=3hStarKernel UEFI Loader +Loading kernel from ESP... +[CKPT 001] Entered efi_main - ConOut live +RAW SERIAL UP +[CKPT 002] Serial (COM1) initialized +Monolithic build - kernel linked directly +Collecting boot information... +CmdLine: from starforth.cfg +CmdLine: parsed OK +[CKPT 004] Command line parsed +[CKPT 005] Kernel stack allocation decided +[CKPT 006] Boot info collected (ACPI table located) +GOP: linear framebuffer found +[CKPT 007] GOP: linear framebuffer found +[CKPT 008] About to enter ExitBootServices retry loop +EBS... +EBS OK +Calling kernel_main (monolithic)... + + + _____ _ _ __ _ + / ____| | | |/ / | | + | (___ | |_ __ _ _ __| ' / ___ _ __ _ __ ___| | + \___ \| __/ _` | '__| < / _ \ '__| '_ \ / _ \ | + ____) | || (_| | | | . \ __/ | | | | | __/ | + |_____/ \__\__,_|_| |_|\_\___|_| |_| |_|\___|_| + +LithosAnanke v4.0.0-alpha.3 amd64 +Architecture: amd64 +Build: Nov 8 2026 14:19:38 + +UEFI BootServices: EXITED +Console: serial line is a 16550 at port 0x00000000000003f8 (COM1, probed) + +=== StarKernel Boot Information === +Memory map entries: 128 +Total memory: 1023 MB +Usable memory: 965 MB +=================================== + +PMM initialized. +PMM statistics: + Total pages: 248623 + Free pages : 247096 + Used pages : 1527 + Total MB : 971 + Free MB : 965 + Used MB : 5 + +VMM initialized (mapped RAM, CR3 switched) +VMM initialized (mapped RAM, CR3 switched) +VMM self-test: mapped OK at 0xffff800000000000 +VMM self-test complete. + +IDT installed. + +APIC: init... +APIC: IA32_APIC_BASE MSR=0x00000000fee00900 +APIC: stale-ISR drain: 0 EOI(s) issued +APIC: initialized (xAPIC MMIO, TPR=0, SIVR=0x1FF, EOI-clear) +APIC: init done + +I/O APIC: init... +I/O APIC: base=0xfec00000, gsi_base=0, overrides=5 + override: source=00 gsi=2 flags=0x0000 + override: source=05 gsi=5 flags=0x000d + override: source=09 gsi=9 flags=0x000d + override: source=0a gsi=10 flags=0x000d + override: source=0b gsi=11 flags=0x000d +i8042: keyboard ACKed enable-scanning +i8042: IRQ1 enabled in controller config byte +I/O APIC: keyboard IRQ1 routed (masked) + +Timer: init... +Timer: init start +Timer: PM_TMR_BLK discovered from FADT at port 1544 +Timer: VM mode detected (hypervisor present). +Timer: HPET calibration disabled (VM-exit MMIO would poison timing). +Timer: WARNING: invariant TSC not present under hypervisor. +Timer: continuing in RELATIVE mode (no determinism guarantees). +Timer: RDTSCP not present; using RDTSC (less serialized). +Timer: CPUID frequency unavailable; trying PM Timer... +Timer: trust=1 (0=NONE,1=REL,2=ABS), TSC=2086331501 Hz +Timer: init done + +Kernel heap initialized. +Heap statistics: + Total bytes: 536870872 + Free bytes: 536870872 + Used bytes: 0 + Peak bytes: 0 + Heap base addr: 24641536 + Heap end addr: 561512448 + +Heartbeat: init... +APIC Timer: calibrating... +APIC Timer: apic_hz=1003269800, tick_hz=100, initial_count=10032698 +APIC Timer: configured (masked, ready to start) +Heartbeat: init done +Kernel initialization complete. +Boot successful! + +Boot disk: a StarshipOS stick +System: StarForth v4 (system=v4) +StarForth v4: one host node, the F18-derived engine +V4: capsule v4:sys:map-64.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:map-64.f18 capsule_hash=0x949eb6a1e9260e49 +V4: capsule v4:sys:core.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:core.f18 capsule_hash=0xb8f167892ec18c28 +V4: capsule v4:sys:input.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:input.f18 capsule_hash=0x85d3ec486d929a79 +V4: capsule v4:sys:dict.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:dict.f18 capsule_hash=0x1379bd3b5de811dc +V4: capsule v4:sys:codegen.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:codegen.f18 capsule_hash=0x36d2ae84d2911b90 +V4: capsule v4:sys:compile.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:compile.f18 capsule_hash=0x11145c4c2ab819d8 +V4: capsule v4:sys:quit.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:quit.f18 capsule_hash=0x43cadf3b21ddbf3e +V4: capsule v4:sys:forth.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:forth.f18 capsule_hash=0x16cab4a1268b85da +V4: capsule v4:sys:numout.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:numout.f18 capsule_hash=0x85a240ad3fb2b299 +V4: capsule v4:sys:words.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:words.f18 capsule_hash=0xb1d381f927d9f14e +V4: capsule v4:sys:system.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:system.f18 capsule_hash=0xd92203664c2915bd +V4: capsule v4:sys:qmath.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:qmath.f18 capsule_hash=0xdb4140713dd857f3 +V4: capsule v4:sys:blocks.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:blocks.f18 capsule_hash=0x76307ef48678dc2a +V4: capsule v4:sys:log.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:log.f18 capsule_hash=0xfc6540e6b824a52b +V4: capsule v4:sys:acl.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:acl.f18 capsule_hash=0x6845aa048db7eb22 +V4: capsule v4:sys:end.f18 signature: missing (unsigned) +PARITY:V4_F18 name=v4:sys:end.f18 capsule_hash=0x5ef01312c07b79cc +PARITY:V4_ROM words=2372 rom_hash=0x87b23d3ae2643c8d instructions=59145258 +V4: capsule v4:forth79.4th signature: missing (unsigned) +PARITY:V4_CAPSULE name=v4:forth79.4th capsule_id=0x4055641ee17d176b capsule_hash=0x4055641ee17d176b dict_hash=0x033e1c05c09a1df8 +PARITY:V4_POST tests=538 pass=538 fail=0 +PARITY:V4_SYSTEM word_count=317 dict_hash=0xfec8c47cfc6f437f +PARITY:OK +POST: PASSED +[HADES][INFO ] [KRELTSC: 0] blk: raw device LBN 2048..3071 (1024 blocks) +PCI: init... +PCI: ECAM mapped (amd64) +virtio-rng: no device on PCI bus 0 +rng: backend = rdrand +entropy: ready +virtio-input: no device on PCI bus 0 +Starting heartbeat... +APIC Timer: started (LVT=0x00020020 ICR=10032698) +I/O APIC: keyboard IRQ1 unmasked +Heartbeat running. +blkio_usb: MSC device ready +Artemis: grown to fill the stick +[HADES][INFO ] [KRELTSC: 12025219166] blk: disk 'StarForth Volume' v2 LBN 3072..12132441 (12129370 us +Artemis: the stick's partition attached +[HADES][INFO ] [KRELTSC: 12045668588] blk: disk 'StarForth Volume' v2 LBN 12132442..12515983 (383542 +[HADES][INFO ] [KRELTSC: 12076101916] MINT verify: identity reads back correctly +[Hera] Zuse: genesis minted onto attached thumbdrive +[zuse@Hera] ok> 3172 BLOCK DROP UPDATE +[zuse@Hera] ok +[zuse@Hera] ok> SAVE-BUFFERS +[zuse@Hera] ok +[zuse@Hera] ok> 3173 BLOCK DROP UPDATE +[zuse@Hera] ok +[zuse@Hera] ok> SAVE-BUFFERS +[zuse@Hera] ok +[zuse@Hera] ok> 3174 BLOCK DROP UPDATE +[zuse@Hera] ok +[zuse@Hera] ok> SAVE-BUFFERS +[zuse@Hera] ok +[zuse@Hera] ok>  \ No newline at end of file diff --git a/scripts/qemu_session.py b/scripts/qemu_session.py index 2ed7a68c..bf7b96ee 100755 --- a/scripts/qemu_session.py +++ b/scripts/qemu_session.py @@ -63,6 +63,9 @@ the stick's, plan 2026-10-26-stick-1-screen-and-keyboard.md): on the copy is clean (plan 2026-10-29-stick-5, Task 2) stick_small --target qemu-stick --stick-gib 4: under 8 GB -- not grown, said so; Artemis at the image's size; the prompt + bam_flush --target qemu-stick --stick-gib 16: an Artemis block changed and SAVE-BUFFERS'd three + times, each timed (TIME:); each answers ok within 2 s (#155: it took 5-6 s); then the BAM's bytes on the + stick hashed (BAM:), to be the same before and after #155's change stick_artemis ARTDISK= (no virtio disk): Artemis and Zuse from the Zuse stick alone -- the stick's Artemis partition attached first (785938 user blocks), then its identity (48724); [zuse@Hera] ok> (plan 2026-10-27-stick-4-one-disk.md, Task 4) @@ -106,7 +109,7 @@ NO_ZUSE_MODES = {"gpt_zuse", "gpt_hotplug", "gpt_foreign", "gpt_bad_crc", "gpt_b "alttab_after_logout", "alttab_before_pull", "emergency_pull", "screen_dark_until_login", "screen_console_after_login", "screen_dark_after_logout", "kbd_typeahead", "stick_boot", "stick_v3", "stick_zuse", "screen_boot", "genesis", - "stick_genesis", "stick_grow", "stick_small"} + "stick_genesis", "stick_grow", "stick_small", "bam_flush"} label = a.label or f"{a.mode}-{a.arch}" work = os.path.join(ROOT, "build", "qemu-session", label) shutil.rmtree(work, ignore_errors=True) @@ -156,7 +159,7 @@ if a.mode == "stick_zuse": make_args.append(f"STICK_PAIR={work}") # the PC stick with this session's copy of the pair if a.stick_gib: make_args.append(f"STICK_GIB={a.stick_gib}") -if a.mode in ("stick_grow", "stick_small"): +if a.mode in ("stick_grow", "stick_small", "bam_flush"): make_args.append("KERNEL_ARGS=--log-level=info") # the blk: disk lines the sizes are read from if a.mode == "genesis": # a fresh data stick, made once into this session's directory and booted twice: the second @@ -531,6 +534,39 @@ elif m in ("stick_grow", "stick_small"): v.returncode == 0 and "No errors detected" in v.stdout + v.stderr) boot_done = True +elif m == "bam_flush": + check("[zuse@Hera] ok>", wait_for(PROMPT, 600)) + lbns = re.findall(r"blk: disk .*? LBN (\d+)\.\.(\d+)", text()) + check(f"Artemis's LBN range ({lbns[:1]})", bool(lbns)) + first = int(lbns[0][0]) if lbns else 0 + times = [] + for i in range(3): + blk = first + 100 + i + n = count(PROMPT) + type_line(f"{blk} BLOCK DROP UPDATE") + check(f"block {blk} changed", wait_for(PROMPT, 60, n)) + n = count(PROMPT) + t = time.time() + type_line("SAVE-BUFFERS") + done = wait_for(PROMPT, 300, n) + times.append(time.time() - t) + print(f"TIME: SAVE-BUFFERS of block {blk}: {times[-1]:.1f} s", flush=True) + check(f"SAVE-BUFFERS answers ok within 2 s ({times[-1]:.1f} s)", done and times[-1] < 2) + check("no fault", count(r"EXCEPTION|PANIC|panic") == 0) + shutdown() + boot_done = True + sf = shutil.which("sfdisk") or "/usr/sbin/sfdisk" + run = os.path.join(ROOT, "build", a.arch, "kernel", "stick-run.img") + parts = json.loads(subprocess.run([sf, "--json", run], capture_output=True, text=True).stdout) + art = [q for q in parts["partitiontable"]["partitions"] + if q["type"].upper() == "BCD7B586-1C8E-4EEF-86A3-273A8D8EE624"][0] + import hashlib + with open(run, "rb") as f: + f.seek(art["start"] * 512 + 4096) # the BAM: devblocks 1 .. 6144 of Artemis + bam = f.read(6144 * 4096) + print(f"BAM: sha256 {hashlib.sha256(bam).hexdigest()}, {sum(1 for x in bam if x)} non-zero bytes", + flush=True) + elif m == "stick_v3": t = text() check("Boot disk: a StarshipOS stick", re.search(r"Boot disk: a StarshipOS stick", t) is not None) diff --git a/v3/src/block_subsystem.c b/v3/src/block_subsystem.c index 6c3afca6..3da95eb5 100644 --- a/v3/src/block_subsystem.c +++ b/v3/src/block_subsystem.c @@ -402,6 +402,19 @@ void blk_subsys_set_format_bam_for(uint64_t total_devblocks) { /* ===== physical BAM I/O (sync to/from slot->bam[]) ===== */ +/* The BAM pages that hold a slot's bits: its reserved bits and one per user + * block (bit i is in page i / 32768). A BAM sized for a larger volume than + * the slot is -- the stick's, sized for 256 GiB -- has pages past these that + * no allocation ever sets, so they are neither read nor written: the bytes on + * disk are the same, and a flush of a 2 GiB volume no longer moves a 24 MiB + * BAM (#155). */ +static uint32_t bam_pages_used(const blk_dev_slot_t *slot) { + uint64_t bits = (uint64_t) BLK_DISK_SYS_RESERVED + slot->user_blocks; + uint64_t pages = (bits + 32767ULL) / 32768ULL; + uint32_t b = slot->vol_meta.bam_devblocks; + return (pages < (uint64_t) b) ? (uint32_t) pages : b; +} + /* * Read physical BAM from disk; populate slot->bam[i].allocated for user blocks. * Physical bit [BLK_DISK_SYS_RESERVED + i] → slot->bam[i].allocated. @@ -410,11 +423,12 @@ static int bam_sync_from_disk(blk_dev_slot_t *slot) { blk_volume_meta_t *m = &slot->vol_meta; if (!slot->dev || m->bam_devblocks == 0) return BLK_EINVAL; - size_t psize = (size_t)4096u * m->bam_devblocks; + uint32_t npages = bam_pages_used(slot); + size_t psize = (size_t)4096u * npages; uint8_t *pbam = (uint8_t *) calloc(1, psize); if (!pbam) return BLK_ENOMEM; - for (uint32_t i = 0; i < m->bam_devblocks; i++) { + for (uint32_t i = 0; i < npages; i++) { uint32_t base1k = (m->bam_start + i) * 4u; for (uint32_t k = 0; k < 4; k++) { if (blkio_read(slot->dev, base1k + k, pbam + i*4096u + k*1024u) != BLKIO_OK) @@ -439,12 +453,13 @@ static int bam_flush_to_disk(blk_dev_slot_t *slot) { blk_volume_meta_t *m = &slot->vol_meta; if (m->bam_devblocks == 0) return BLK_OK; - size_t psize = (size_t)4096u * m->bam_devblocks; + uint32_t npages = bam_pages_used(slot); + size_t psize = (size_t)4096u * npages; uint8_t *pbam = (uint8_t *) calloc(1, psize); if (!pbam) return BLK_ENOMEM; /* read current on-disk BAM */ - for (uint32_t i = 0; i < m->bam_devblocks; i++) { + for (uint32_t i = 0; i < npages; i++) { uint32_t base1k = (m->bam_start + i) * 4u; for (uint32_t k = 0; k < 4; k++) { if (blkio_read(slot->dev, base1k + k, pbam + i*4096u + k*1024u) != BLKIO_OK) @@ -462,7 +477,7 @@ static int bam_flush_to_disk(blk_dev_slot_t *slot) { } /* write back */ - for (uint32_t i = 0; i < m->bam_devblocks; i++) { + for (uint32_t i = 0; i < npages; i++) { uint32_t base1k = (m->bam_start + i) * 4u; for (uint32_t k = 0; k < 4; k++) { if (blkio_write(slot->dev, base1k + k, pbam + i*4096u + k*1024u) != BLKIO_OK) {