# DF-5565 — IIC_DONTWAIT + busy bridge callback = unkillable tight kernel loop (livelock)

* File under audit: `sys/bus/iicbus/iiconf.c` (pass 2)
* Class: local DoS (CPU livelock, unkillable)
* Severity: Low (root-gated; in-tree reachable via lpbb/ppbus contention)
* Verdict: **REPRODUCED** (non-destructive), fix validated

## The bug

The first loop of `iicbus_request_bus()` (`iiconf.c:92-97`):

```c
do {
        error = IICBUS_CALLBACK(device_get_parent(bus),
                        IIC_REQUEST_BUS, (caddr_t)&how);
        if (error)
                error = iicbus_poll(sc, how);
} while (error == EWOULDBLOCK);
```

With `how == IIC_DONTWAIT` (0), `iicbus_poll()` takes the `default:` case
and returns `EWOULDBLOCK` **immediately without sleeping**
(`iiconf.c:70-72`). If the bridge callback persistently reports busy, the
loop retries forever: no sleep, no yield, no signal checkpoint — a tight
kernel-mode loop that burns one CPU and cannot be interrupted by SIGKILL.

In-tree reachability: `lpbb` is the bridge whose callback can report busy
— `lpbb_callback` (`sys/dev/misc/lpbb/lpbb.c:90-113`) forwards to
`ppb_request_bus`, which returns `EWOULDBLOCK` immediately for
`PPB_DONTWAIT` when another ppbus client (e.g. `lpt` printing, or another
lpbb user) holds the parallel port (`sys/bus/ppbus/ppbconf.c:458-493`).
DONTWAIT callers: `iicwrite`/`iicread` on `/dev/iicN`
(`sys/bus/iicbus/iic.c:212-213, 253-254`). Requires lpbb-class hardware
(parallel-port I2C) or any KLD bridge with the same contract — the rig's
`hw.df5563.busy=1` emulates it faithfully.

Contrast: the second loop (owner contention) handles the DONTWAIT
EWOULDBLOCK correctly (releases and returns, `iiconf.c:110-113`); only
the first loop spins.

## Reproduce (non-destructive)

```
sysctl hw.df5563.busy=1
./park nowait &          # enters the loop; never returns
ps -o pid,stat,time -p $!   # STAT R+ (running, never sleeps), TIME += wall clock
kill -9 $!               # IGNORED
sysctl hw.df5563.busy=0  # next callback succeeds -> loop exits, process dies with pending SIGKILL
```

## Expected output (baseline)

```
--- ps t0 ---                --- ps t1 (+3s) ---
  2007 R1       0:03.01       2007 R1       0:06.01   <-- 100% kernel CPU
SIGKILL_IGNORED=YES
GONE_AFTER_UNBUSY=YES
```

CPU time accrues 1:1 with wall clock (3 s CPU per 3 s wall) while the
thread is in kernel mode the whole time.

## Fix

Covered by DF-5563's `fix.diff`: the restructured loop does exactly one
callback attempt for DONTWAIT — `iicbus_poll()`'s EWOULDBLOCK exits the
loop instead of retrying. Validation (`fix_run.log`): with the patched
`iicbus.ko`, `./park nowait` under busy returns
`errno=35 (EWOULDBLOCK)` immediately, twice, with no spin; the sanity
round trip still passes.
