Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'perf-urgent-2025-11-08' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull perf event fix from Ingo Molnar:
"Fix a system hang caused by cpu-clock events deadlock"

* tag 'perf-urgent-2025-11-08' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
perf/core: Fix system hang caused by cpu-clock usage

+15 -5
+15 -5
kernel/events/core.c
··· 11773 11773 11774 11774 event = container_of(hrtimer, struct perf_event, hw.hrtimer); 11775 11775 11776 - if (event->state != PERF_EVENT_STATE_ACTIVE) 11776 + if (event->state != PERF_EVENT_STATE_ACTIVE || 11777 + event->hw.state & PERF_HES_STOPPED) 11777 11778 return HRTIMER_NORESTART; 11778 11779 11779 11780 event->pmu->read(event); ··· 11820 11819 struct hw_perf_event *hwc = &event->hw; 11821 11820 11822 11821 /* 11823 - * The throttle can be triggered in the hrtimer handler. 11824 - * The HRTIMER_NORESTART should be used to stop the timer, 11825 - * rather than hrtimer_cancel(). See perf_swevent_hrtimer() 11822 + * Careful: this function can be triggered in the hrtimer handler, 11823 + * for cpu-clock events, so hrtimer_cancel() would cause a 11824 + * deadlock. 11825 + * 11826 + * So use hrtimer_try_to_cancel() to try to stop the hrtimer, 11827 + * and the cpu-clock handler also sets the PERF_HES_STOPPED flag, 11828 + * which guarantees that perf_swevent_hrtimer() will stop the 11829 + * hrtimer once it sees the PERF_HES_STOPPED flag. 11826 11830 */ 11827 11831 if (is_sampling_event(event) && (hwc->interrupts != MAX_INTERRUPTS)) { 11828 11832 ktime_t remaining = hrtimer_get_remaining(&hwc->hrtimer); 11829 11833 local64_set(&hwc->period_left, ktime_to_ns(remaining)); 11830 11834 11831 - hrtimer_cancel(&hwc->hrtimer); 11835 + hrtimer_try_to_cancel(&hwc->hrtimer); 11832 11836 } 11833 11837 } 11834 11838 ··· 11877 11871 11878 11872 static void cpu_clock_event_start(struct perf_event *event, int flags) 11879 11873 { 11874 + event->hw.state = 0; 11880 11875 local64_set(&event->hw.prev_count, local_clock()); 11881 11876 perf_swevent_start_hrtimer(event); 11882 11877 } 11883 11878 11884 11879 static void cpu_clock_event_stop(struct perf_event *event, int flags) 11885 11880 { 11881 + event->hw.state = PERF_HES_STOPPED; 11886 11882 perf_swevent_cancel_hrtimer(event); 11887 11883 if (flags & PERF_EF_UPDATE) 11888 11884 cpu_clock_event_update(event); ··· 11958 11950 11959 11951 static void task_clock_event_start(struct perf_event *event, int flags) 11960 11952 { 11953 + event->hw.state = 0; 11961 11954 local64_set(&event->hw.prev_count, event->ctx->time); 11962 11955 perf_swevent_start_hrtimer(event); 11963 11956 } 11964 11957 11965 11958 static void task_clock_event_stop(struct perf_event *event, int flags) 11966 11959 { 11960 + event->hw.state = PERF_HES_STOPPED; 11967 11961 perf_swevent_cancel_hrtimer(event); 11968 11962 if (flags & PERF_EF_UPDATE) 11969 11963 task_clock_event_update(event, event->ctx->time);