DF-2929 / fix.diff
--- a/sys/dev/drm/linux_hrtimer.c +++ b/sys/dev/drm/linux_hrtimer.c @@ -106,6 +106,30 @@ /* Prevent arbitrarily short timeouts from being scheduled. */ timer->timeout_us = max(500, timer->timeout_us); + /* + * Linux hrtimer semantics: hrtimer_start() on an already-armed + * timer dequeues it and re-arms. We must not re-run + * systimer_init_oneshot() on a queued systimer: it bzero()s the + * struct, leaving stale links in the owning cpu's gd_systimerq + * (ghost links => timer queue corruption, panics in + * systimer_intr()/systimer_del() and wild unlinks on production + * kernels). Delete the pending systimer first, on its owning + * cpu, exactly like hrtimer_cancel() does. + * + * The delete is a no-op if the timer already fired (it is no + * longer queued); SYSTF_ONQUEUE is cleared by then. + */ + if (timer->active) { + if (timer->gd == mycpu) { + systimer_del(&timer->st); + } else { + struct globaldata *oldcpu = mycpu; + lwkt_setcpu_self(timer->gd); + systimer_del(&timer->st); + lwkt_setcpu_self(oldcpu); + } + } + lwkt_gettoken(&timer->timer_token); timer->cancel = false; |