Re: [PATCH] perf: Fix system hang caused by cpu-clock
From: Peter Zijlstra
Date: Tue Oct 21 2025 - 13:19:01 EST
On Wed, Oct 15, 2025 at 01:18:28PM +0800, Dapeng Mi wrote:
> A system hang issue caused by cpu-clock is reported and bisection
> indicates the commit 18dbcbfabfff ("perf: Fix the POLL_HUP delivery
> breakage") causes this issue.
>
> The root cause of the hang issue is that cpu-clock is a specific SW
> event which relies on the hrtimer. The __perf_event_overflow()
> is invoked from the hrtimer handler for cpu-clock event, and
> __perf_event_overflow() tries to call event stop callback
> (cpu_clock_event_stop()) to stop the event, and cpu_clock_event_stop()
> calls htimer_cancel() to cancel the hrtimer. But unfortunately the
> hrtimer callback is currently executing and then traps into deadlock.
>
> To avoid this deadlock, use hrtimer_try_to_cancel() instead of
> hrtimer_cancel() to cancel the hrtimer, and set PERF_HES_STOPPED flag
> for the stopping events. perf_swevent_hrtimer() would stop the event
> hrtimer once it detects the PERF_HES_STOPPED flag.
>
> Reported-by: Octavia Togami <octavia.togami@xxxxxxxxx>
> Closes: https://lore.kernel.org/all/CAHPNGSQpXEopYreir+uDDEbtXTBvBvi8c6fYXJvceqtgTPao3Q@xxxxxxxxxxxxxx/
> Suggested-by: Peter Zijlstra <peterz@xxxxxxxxxxxxx>
> Fixes: 18dbcbfabfff ("perf: Fix the POLL_HUP delivery breakage")
> Tested-by: Octavia Togami <octavia.togami@xxxxxxxxx>
> Signed-off-by: Dapeng Mi <dapeng1.mi@xxxxxxxxxxxxxxx>
> ---
> kernel/events/core.c | 18 +++++++++++++-----
> 1 file changed, 13 insertions(+), 5 deletions(-)
>
> diff --git a/kernel/events/core.c b/kernel/events/core.c
> index 7541f6f85fcb..f90105d5f26a 100644
> --- a/kernel/events/core.c
> +++ b/kernel/events/core.c
> @@ -11773,7 +11773,8 @@ static enum hrtimer_restart perf_swevent_hrtimer(struct hrtimer *hrtimer)
>
> event = container_of(hrtimer, struct perf_event, hw.hrtimer);
>
> - if (event->state != PERF_EVENT_STATE_ACTIVE)
> + if (event->state != PERF_EVENT_STATE_ACTIVE ||
> + event->hw.state & PERF_HES_STOPPED)
> return HRTIMER_NORESTART;
>
> event->pmu->read(event);
I was wondering if we need a HES_STOPPED check after calling
__perf_event_overflow(), but typically that will return 1 when it does
the stop itself, which then already does NORESTART.
So yeah, I suppose this works. Let me go queue this up.
Thanks!