Commit dda88878 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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

Pull perf event fix from Ingo Molnar:
 "Fix a perf events time accounting bug"

* tag 'perf-urgent-2025-04-06' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  perf/core: Fix child_total_time_enabled accounting bug at task exit
parents 302deb10 a3c3c666
Loading
Loading
Loading
Loading
+9 −9
Original line number Diff line number Diff line
@@ -2451,6 +2451,7 @@ ctx_time_update_event(struct perf_event_context *ctx, struct perf_event *event)
#define DETACH_GROUP	0x01UL
#define DETACH_CHILD	0x02UL
#define DETACH_DEAD	0x04UL
#define DETACH_EXIT	0x08UL

/*
 * Cross CPU call to remove a performance event
@@ -2465,6 +2466,7 @@ __perf_remove_from_context(struct perf_event *event,
			   void *info)
{
	struct perf_event_pmu_context *pmu_ctx = event->pmu_ctx;
	enum perf_event_state state = PERF_EVENT_STATE_OFF;
	unsigned long flags = (unsigned long)info;

	ctx_time_update(cpuctx, ctx);
@@ -2473,16 +2475,19 @@ __perf_remove_from_context(struct perf_event *event,
	 * Ensure event_sched_out() switches to OFF, at the very least
	 * this avoids raising perf_pending_task() at this time.
	 */
	if (flags & DETACH_DEAD)
	if (flags & DETACH_EXIT)
		state = PERF_EVENT_STATE_EXIT;
	if (flags & DETACH_DEAD) {
		event->pending_disable = 1;
		state = PERF_EVENT_STATE_DEAD;
	}
	event_sched_out(event, ctx);
	perf_event_set_state(event, min(event->state, state));
	if (flags & DETACH_GROUP)
		perf_group_detach(event);
	if (flags & DETACH_CHILD)
		perf_child_detach(event);
	list_del_event(event, ctx);
	if (flags & DETACH_DEAD)
		event->state = PERF_EVENT_STATE_DEAD;

	if (!pmu_ctx->nr_events) {
		pmu_ctx->rotate_necessary = 0;
@@ -13731,12 +13736,7 @@ perf_event_exit_event(struct perf_event *event, struct perf_event_context *ctx)
		mutex_lock(&parent_event->child_mutex);
	}

	perf_remove_from_context(event, detach_flags);

	raw_spin_lock_irq(&ctx->lock);
	if (event->state > PERF_EVENT_STATE_EXIT)
		perf_event_set_state(event, PERF_EVENT_STATE_EXIT);
	raw_spin_unlock_irq(&ctx->lock);
	perf_remove_from_context(event, detach_flags | DETACH_EXIT);

	/*
	 * Child events can be freed.