docs: append REGRESSION + REMEDY record for task-8 ps2d read-to-string regression
Root cause: std::fs::read_to_string loops forever on kernel scheme /scheme/serio/present (serio kread for HandleKind::Present never produces EOF). Fix: bounded single-byte read in ps2d main.rs (commit aeb2df8e on submodule/base branch). 14/14 host tests green. QEMU gate expected: ps2d startup log BEFORE notify-wait ticks, no kill line.
This commit is contained in:
@@ -92,3 +92,61 @@ Single command (no build needed):
|
||||
- No `src/scheme/irq.rs` cpu- path handling touched
|
||||
- No retries/warning noise on absence
|
||||
- No recipe files modified
|
||||
|
||||
---
|
||||
## REGRESSION + REMEDY RECORD (2026-08-05, QEMU verification)
|
||||
|
||||
### Root cause
|
||||
|
||||
`std::fs::read_to_string("/scheme/serio/present")` in
|
||||
`local/sources/base/drivers/input/ps2d/src/main.rs:38` loops forever on
|
||||
the i8042-present path. The kernel's `SerioScheme::kread` for
|
||||
`HandleKind::Present` (kernel `src/scheme/serio.rs:146-148`) always
|
||||
returns the verdict bytes (`b"1\n"` or `b"0\n"`) on every read without
|
||||
ever producing a zero-byte EOF. `read_to_string` in Rust std reads
|
||||
until `read()` returns 0, so it enters an infinite read loop — growing
|
||||
the accumulator string by 3 bytes per iteration — and never returns to
|
||||
caller code. ps2d blocks in `read_to_string` before any log output or
|
||||
`daemon.ready()` can execute, so init's 10s notify-wait timeout kills it
|
||||
with zero diagnostic output ("'ps2d' did not notify readiness within 10s;
|
||||
killing and skipping").
|
||||
|
||||
The absent path (kernel verdict "0\n") is equally affected but was not
|
||||
caught because the QEMU configs used for absent-path testing happened to
|
||||
not exercise `read_to_string` (or the absent-path tests were host-only
|
||||
verdict logic tests, not QEMU boots). The host test suite (14/14 GREEN)
|
||||
tests the verdict DECISION logic in isolation — it does not exercise the
|
||||
actual `read_to_string` syscall path on a running Redox kernel.
|
||||
|
||||
### Remedy
|
||||
|
||||
Commit `aeb2df8e` on `submodule/base`:
|
||||
|
||||
- **`drivers/input/ps2d/src/main.rs`** — Replaced `std::fs::read_to_string`
|
||||
with a bounded single-byte read (`read_serio_present()`): opens
|
||||
`/scheme/serio/present`, reads at most 2 bytes into a stack buffer,
|
||||
returns the first byte. Only the first byte matters (b'1' = present,
|
||||
b'0' = absent); the '\n' is discarded.
|
||||
|
||||
- Added a `log::info!` on the present path BEFORE `InputProducer` opens
|
||||
("ps2d: PS/2 controller present; starting serio device handshake") so
|
||||
future boot logs show ps2d's progress through the startup sequence
|
||||
before any scheme I/O blocking point.
|
||||
|
||||
Host tests: 14/14 GREEN (`cargo test --manifest-path
|
||||
local/sources/kernel/host-tests/i8042-verdict/Cargo.toml`). All verdict
|
||||
decision-table tests pass unchanged — the fix only changes the I/O
|
||||
mechanism, not the decision logic.
|
||||
|
||||
### Expected QEMU gate observable
|
||||
|
||||
On the i8042-present path, the orchestrator's QEMU gate should see:
|
||||
- **BEFORE** the first `notify-wait 'ps2d' tick` (within ~50ms of
|
||||
"Started PS/2 driver"): the line
|
||||
`ps2d: PS/2 controller present; starting serio device handshake`,
|
||||
followed by `ps2d: registered producer handle, listening on serio/0
|
||||
(keyboard) and serio/1 (mouse)`.
|
||||
- **ABSENT**: the kill line `'ps2d' did not notify readiness within 10s;
|
||||
killing and skipping`.
|
||||
- Keyboard input on `/scheme/serio/0` works in QEMU after ps2d's
|
||||
successful notify.
|
||||
|
||||
Reference in New Issue
Block a user