Re: [PATCH 2/5] hrtimer: pause KCOV during deferred rearm

From: Bradley Morgan

Date: Fri Aug 07 2026 - 21:20:08 EST


On 7 August 2026 21:50:24 BST, Karl Mehltretter <kmehltretter@xxxxxxxxx>
wrote:
>Deferred hrtimer rearm can run after HARDIRQ_OFFSET is dropped. in_task()
>is then true, so KCOV attributes the instrumented timer-reprogramming
>subtree to current.
>
>With CONFIG_KCOV_SELFTEST, the interrupt selftest fails on x86_64
>defconfig under QEMU, detecting spurious coverage in
>__hrtimer_rearm_deferred(). The same happens on s390, RISC-V and
>LoongArch, which also enable HRTIMER_REARM_DEFERRED.
>
>Excluding the involved files instead would cost their coverage on real
>task-context paths, e.g. the hrtimer and timekeeping syscalls.
>
>Pause in the __always_inline wrappers, including hrtick_schedule_exit().
>Call sites where task KCOV can be active are KCOV-disabled or noinstr.
>HAVE_NOINSTR_HACK covers pre-GCC-12 x86. The other affected
>architectures restrict KCOV to GCC 12 or Clang through
>ARCH_WANTS_NO_INSTR. This avoids relying on __no_sanitize_coverage,
>which is empty before GCC 12. Tested with GCC 8.1 and 15 on x86_64.
>
>Fixes: 15dd3a948855 ("hrtimer: Push reprogramming timers into the interrupt return path")
>Assisted-by: Claude:claude-opus-4-8
>Assisted-by: Claude:claude-fable-5
>Signed-off-by: Karl Mehltretter <kmehltretter@xxxxxxxxx>
>---
> include/linux/hrtimer_rearm.h | 18 ++++++++++++++++--
> kernel/sched/core.c | 2 +-
> 2 files changed, 17 insertions(+), 3 deletions(-)
>
>diff --git a/include/linux/hrtimer_rearm.h b/include/linux/hrtimer_rearm.h
>index a6f2e5d5e1c7..b95687529c2e 100644
>--- a/include/linux/hrtimer_rearm.h
>+++ b/include/linux/hrtimer_rearm.h
>@@ -3,10 +3,23 @@
> #define _LINUX_HRTIMER_REARM_H
>
> #ifdef CONFIG_HRTIMER_REARM_DEFERRED
>+#include <linux/kcov.h>
> #include <linux/thread_info.h>
>
> void __hrtimer_rearm_deferred(void);
>
>+/*
>+ * Pause outside __hrtimer_rearm_deferred() to suppress its entry coverage.
>+ * Call sites where task KCOV can be active are uninstrumented.
>+ */

I see. Okay.

Reviewed-by: Bradley Morgan <include@xxxxxxxxx>

LGTM

>+static __always_inline void hrtimer_rearm_deferred_paused(void)
>+{
>+ unsigned int kcov_paused = kcov_pause(current);
>+
>+ __hrtimer_rearm_deferred();
>+ kcov_resume(current, kcov_paused);
>+}
>+
> /*
> * This is purely CPU local, so check the TIF bit first to avoid the overhead of
> * the atomic test_and_clear_bit() operation for the common case where the bit
>@@ -38,7 +51,7 @@ hrtimer_rearm_deferred_user_irq(unsigned long *tif_work, const unsigned long tif
> */
> if (unlikely((*tif_work & TIF_REARM_MASK) == _TIF_HRTIMER_REARM)) {
> clear_thread_flag(TIF_HRTIMER_REARM);
>- __hrtimer_rearm_deferred();
>+ hrtimer_rearm_deferred_paused();
> /* Don't go into the loop if HRTIMER_REARM was the only flag */
> *tif_work &= ~TIF_HRTIMER_REARM;
> return !*tif_work;
>@@ -50,7 +63,7 @@ hrtimer_rearm_deferred_user_irq(unsigned long *tif_work, const unsigned long tif
> static __always_inline void hrtimer_rearm_deferred_tif(unsigned long
> tif_work)
> {
> if (hrtimer_test_and_clear_rearm_deferred_tif(tif_work))
>- __hrtimer_rearm_deferred();
>+ hrtimer_rearm_deferred_paused();
> }
>
> /*
>@@ -73,6 +86,7 @@ static __always_inline bool hrtimer_test_and_clear_rearm_deferred(void)
>
> #else /* CONFIG_HRTIMER_REARM_DEFERRED */
> static __always_inline void __hrtimer_rearm_deferred(void) { }
>+static __always_inline void hrtimer_rearm_deferred_paused(void) { }
> static __always_inline void hrtimer_rearm_deferred(void) { }
> static __always_inline void hrtimer_rearm_deferred_tif(unsigned long
> tif_work) { }
> static __always_inline bool
>diff --git a/kernel/sched/core.c b/kernel/sched/core.c
>index 96226707c2f6..b6a8fbbdd538 100644
>--- a/kernel/sched/core.c
>+++ b/kernel/sched/core.c
>@@ -1010,7 +1010,7 @@ static inline void hrtick_schedule_exit(struct rq *rq)
> }
>
> if (rq->hrtick_sched & HRTICK_SCHED_REARM_HRTIMER)
>- __hrtimer_rearm_deferred();
>+ hrtimer_rearm_deferred_paused();
>
> rq->hrtick_sched = HRTICK_SCHED_NONE;
> }
>

Thanks!