# DF-5176 — hrtimer shim shares one `struct task` across per-CPU taskqueues (cross-CPU re-arm panics / races unlocked task state)

## What

`sys/dev/drm/linux_hrtimer.c` (the LinuxKPI hrtimer shim, compiled into
`drm.ko`) keeps ONE `struct task` (`timer->task`) per hrtimer but enqueues it
on **whichever CPU's `taskqueue_thread[]` the systimer fires on**
(`__hrtimer_function`, linux_hrtimer.c:37), while the systimer itself is
(re-)armed on **whichever CPU calls `hrtimer_start`**
(`hrtimer_start_range_ns` → `systimer_init_oneshot`, linux_hrtimer.c:115,
setting `st.gd = mycpu`).

DragonFly's taskqueue explicitly forbids this —
`sys/kern/subr_taskqueue.c:185-188`:

```
 * NOTE!  If using the per-cpu taskqueues ``taskqueue_thread[mycpuid]'',
 * be sure NOT TO SHARE the ``task'' between CPUs.  TASKS ARE NOT LOCKED.
 * So either use a throwaway task which will only be enqueued once, or
 * use one task per CPU!
```

because `taskqueue_enqueue_locked()` (subr_taskqueue.c:205-209) only handles
the same-queue case and asserts `KKASSERT(queue == task->ta_queue)`.

Re-arming the timer from a different CPU while the previous expiry's task is
still pending therefore either panics (INVARIANTS kernels — the stock
X86_64_GENERIC has INVARIANTS, sys/config/X86_64_GENERIC:56) or performs an
unlocked cross-queue `ta_pending++` on task state owned by another CPU.

## Reproduce (on the audit QEMU guest)

```
scp df5176.c Makefile dfbsd:/root/df5176/
ssh dfbsd 'cd /root/df5176 && make SYSDIR=/usr/src/sys && kldload drm'
ssh dfbsd 'kldload /root/df5176/df5176.ko'   # guest panics immediately
```

## Expected (baseline, unpatched drm.ko)

```
[df5176] attempt 1: arming on cpu0 (1ms)
[df5176] task ta_pending=1 ta_queue == q0
[df5176] re-arming from cpu1 (2ms)
panic: assertion "queue == task->ta_queue" failed in taskqueue_enqueue_locked at /usr/src/sys/kern/subr_taskqueue.c:206
taskqueue_enqueue_locked+0x159
taskqueue_enqueue+0x45
__hrtimer_function+0x21
systimer_intr+0xd6
pcpu_timer_process_oncpu+0x82
```

(fix-validated: with `fix.diff` applied and drm.ko rebuilt, the same module
prints `FAILED to trigger - no panic` and the guest stays up — see
`run.fix.log`.)

## Files

- `df5176.c` / `Makefile` — the PoC KLD
- `build.log` / `run.log` / `run.log.full` / `panic.txt` — baseline evidence
- `run.fix.log` — fixed-kernel rerun (no panic)
- `fix.diff` — one coherent fix for DF-5176 + DF-5177 (pins the home
  taskqueue at `hrtimer_init`; makes `hrtimer_cancel` loop until quiescent
  with the token held across `systimer_del`; drops the `running=false` lie
  from `hrtimer_start`)
- `env.txt` — guest kernel/INVARIANTS/kldstat
- `VERDICT.md`, `manifest.json`, `verdict.json` — full narrative + machine verdict
