The console lock, and why the machine goes quiet

Status: the bound is in and the counter is gated. The svc-press failure is now understood well enough to describe, and is not yet fixed.

The one lock that cannot report itself

Every other lock in this kernel panics when its bound fires. This one cannot: a panic prints, and printing goes through the very lock whose state is in question. So it takes the lock anyway, records that it did and who was holding it, and lets the machine carry on talking.

That trades a correct line for a possibly interleaved one, and it is the right trade twice over. Interleaving is detected — interleaved_lines is the boot gate's first check, precisely so a garbled line is caught and named. Silence is not detectable at all, and it is the failure where every piece of evidence is missing rather than wrong.

[CONSOLE] MUSTBEZERO bad_unlocks=… stuck=… stuck_owner=… is the line; the gate fails on a non-zero count and on the line being absent.

What it explained

svc-press allocates 256 KiB at a time and touches every page. At a hundred and twelve blocks — twenty-eight megabytes, not the twenty this was written up as — the machine goes completely quiet.

Four explanations were excluded first: not a deadlock on hw_spin_lock (the bound was lowered to twenty million and still did not fire), not memory exhaustion (104,572 free frames down to 98,735 of 107,485, with reclaim never running), not reverse-map exhaustion (seven thousand nodes against two hundred and fifteen thousand), and no fault of its own.

Lowering this bound to ten million changed the machine from silent to talkative, and what came out was a hw_ctx_check report — cr3_by=, exe=, rip=0x0, cs=0x0, rflags=0x0 — a task whose saved context is zeroed, refused entry by the guard that exists to catch exactly that.

It came out interleaved, because taking a held lock mid-line is what this bound does. That is the cost, and it bought the first piece of evidence this failure has produced in its existence.

So the shape is: a task acquires a zeroed context, hw_ctx_check refuses to enter it and reports under the console lock, and the machine stops there — with the console lock held. Everything else then piles up behind it, which is why the symptom is silence rather than a panic.

The original wedge report said this and was not believed. It put CPU#2 and CPU#3 in hw_ctx_check and CPU#0 and CPU#1 at an address whose nearest preceding symbol was hw_task_slots — a function that returns a constant. hw_ctx_check was right; the other two are almost certainly the pause loop in vibeos_x86_64_serial_lock, which links early and therefore sits at a low address. The lesson CLAUDE.md draws about nearest-preceding-symbol naming cuts both ways: a name that looks absurd is worth discarding, and a name that looks plausible is worth checking rather than dismissing wholesale.

What is not done

Why a task's context is zeroed under heavy anonymous mmap. That is the actual defect and it is untouched.

And hw_ctx_check prints a dozen fields from the task table, including exe_path and vibeos_task_last_why(slot), while holding the console lock with interrupts masked. If any of those reads faults — plausible, since the task it is describing is already corrupt — the machine stops inside the critical section, which is exactly the observed state. Making the report safe to run against a task that is known to be broken is the next step, before the cause is chased.


The reporter that could not report

Written after the bound above found its first real failure, and after the tool built to explain it turned out to have the same defect it was looking for.

hw_lock_deadlock announced a stuck spinlock by calling serial_puts, which takes the console lock. Under svc-press the console lock is one of the jammed ones, so the core that had detected the deadlock sat down in vibeos_x86_64_serial_lock and the message never arrived. The wedge report caught it in the act: CPU#3 rip=0x4000cb5 hw_lock_deadlock.

A lock reporter that can only speak while the locks are healthy reports nothing on exactly the boots it exists for. It writes raw bytes now, taking nothing. The output can interleave, which is the correct trade for the same reason the console bound takes the lock rather than waiting: interleaving is caught by the gate's first check, and silence is not caught by anything.

What svc-press actually does

Not a wedge, or not only one. With the reporting unjammed the boot gate reports guest_still_talking for thirty-nine minutes with quiet_for=0: the machine emits 7.5 MB of hw_ctx_check dumps and never stops. Both verdicts have been seen from the same workload, and which one appears depends on whether the console lock jams before or after the flood starts. That is why this failure was written up for so long as "the serial log fills with binary" - it is not binary, it is one diagnostic repeating for ever, cut into fragments by cores writing over each other.

The repeated fragments are the tail of that dump, and they are not random: rax=0x10a030c050e07000, rbp=0x10a030c010e07200, rax=0x60f08010a030c050. The high nibbles step by 0x20 - 10, 30, 50, 70, 90, a0, c0, e0 - so whatever the failing context is being read from holds structured data, not the leftovers of a freed page. That is a different question from "a context was zeroed", which is what the earlier, garbled capture suggested, and both readings are recorded here because the difference decides where to look next.

Where this stands

The characterisation is much sharper than it was and the instruments now work, which is the whole of what this stretch bought:

  • the console lock cannot silence the machine any more, and says when it was taken by force;
  • the spinlock bound fires and can speak while the locks are jammed;
  • the trap dump reports what it did rather than what the model proposed;
  • an execve that fails names its reason.

The defect itself is not fixed, and it predates all of this. It is outside the memory-manager plan - it is not any of P0 through P7 - and what it blocks is narrow and stated in mm_swap_file.md: freed_anon stays zero because nothing else runs this machine short enough of memory to make reclaim evict a page.