VM.running_on claimed by compare-and-swap on switch-in and released once
the context is saved (release_after, sk_vm_switch_finish); a lost claim
returns 1 and the caller re-decides; double claims counted. Per-core
entry_vm and decision_due. g_lock_physics over capsule_vm_physics.c
(rank between switch and registry). KILL refuses a VM running anywhere.
Probe: 15737 claims, 0 lost, 0 double; a core-1 claim of Hera refused.
3-ISA acceptance with a 28-VM churn clean, 0 order violations.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every lock carries a rank (hermes < switch < registry < VM dict_lock <
VM tuning_lock < stadium < slot < doe < log < block < console < heap <
vmm < pmm); each core counts held locks per rank and an acquisition not
above the highest held rank counts an order violation, reported in full
at the idle point. Probe inversion reported exactly once; O-A, a 28-VM
churn and the standard sequence show 0 violations on all three ISAs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Ruling (Captain Bob): per-slot locks, not "own path needs no lock" --
a lock only on the cross-slot side can't exclude an unlocked owner
(Hermes release evicting a sender's cell while the sender admits).
FABRIC-3.10.0 §3.6 amended.
- StadiumVMQuota.lock covers the slot's lists, reservoir, consumed, word
row and its cells. Word dispatch holds only its own slot lock for the
whole dispatch (*_in_slot forms); peek-then-pull is one step.
- g_lock_stadium: grant slot allocation (new slot published with release
in_use) and the shared block table (ruled: the one shared-lock Stadium
path). Taken before a slot lock.
- Bitmap bytes set/cleared atomically (8 cells, possibly 8 slots).
- Cross-slot writers moved under the owner's lock: Hermes decay
(stadium_cell_decay), Hermes release ledger (stadium_evict_credit),
session pin (stadium_cell_set_pin). stadium_conserved() one hold.
- Word and block cell lookups check the cell is still this slot's.
- Probe (removed), identical on all three ISAs: 10,746,599 of 10,746,616
word dispatches took exactly one lock (own slot), the 17 others all row
growths; every live VM conserved; Hermes audit failures 0.
- Findings reported: births/USE run a VM's words while another VM is the
core's current VM (MC-3 claim must cover it); quota slots never
released; owner admission can evict a live message cell (latent, 0).
- Standard sequence on amd64/aarch64/riscv64: dict_hash set and G
byte-identical, MINT/WIREBIND/USE ok, conservation true, 0 idle growth.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- block_subsystem.c (vendored): every public function's body becomes a
static *_locked function; bodies call each other only through the
_locked forms, breaking the internal cycles (relocate, meta relocate,
migration scan, firsttouch, the meta accessors). Thin public wrappers
take g_lock_block under __STARKERNEL__; hosted build has no lock and
still builds clean.
- Lock order: hermes, switch, registry, doe, log, block, console, heap,
vmm, pmm (Stadium, MC-0d, above block).
- Documented, not coverable by this lock: blk_get_buffer() pointers are
used after release -- block-buffer ownership across cores is open for
MC-3.
- Probe (removed): block lock balances on all three ISAs (2,057-2,379
acquisitions), 0 recursions, 0 held at switch; vblk_io timeouts
(0/0/4 probe, 0/0/2 acceptance) within the pre-lock riscv64 baseline
of 0-6.
- Standard sequence on amd64/aarch64/riscv64: hashes and G byte-identical
to MC-0b, MINT/WIREBIND/USE ok, conservation true, 0 idle growth.
- FABRIC-3.10.8 §3.2 wording fix; lock order noted as checked by
inspection only.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- New spinlock primitive (spinlock.h/.c): CAS on an owner word (core+1),
interrupts masked while any lock is held (state kept in the per-core
block, so release order doesn't matter). Recursion, release-not-held,
held-at-switch and destroyed-while-held are counted and logged, never
silent. Locks are no-ops until the boot core's block is installed
(riscv64's monolithic early boot prints before sk_percpu_boot_init()).
- Kernel locks in a documented order: hermes, switch, registry, doe, log,
console, heap, vmm, pmm. sf_mutex (dict_lock/tuning_lock) uses the same
lock word.
- Hermes: public functions over *_locked internals; never held across the
drain's vm_interpret_kind(); switch notifications after dropping the
lock; event payload moved off static storage. Switch table and registry
never call out while held (slot/entry copied under the lock).
- No lock crosses a switch: checked at context switch (leave, resume) and
the idle point.
- Probe (removed): every lock balances on all three ISAs; 0 held at
switch over 7.5M-51M checks; 0 recursions, 0 bad releases.
- Standard sequence on amd64/aarch64/riscv64: hashes and G byte-identical
to MC-0a, MINT/WIREBIND/USE ok, conservation true, 0 idle growth.
- Block subsystem split out as MC-0b2 (Captain Bob's ruling).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>