perf: Fix inherit vs. context rotation bug

It was found that sometimes children of tasks with inherited events had
one extra event. Eventually it turned out to be due to the list rotation
no being exclusive with the list iteration in the inheritance code.

Cure this by temporarily disabling the rotation while we inherit the events.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
LKML-Reference: <new-submission>
Cc: <stable@kernel.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>

authored by Thomas Gleixner and committed by Ingo Molnar dddd3379 02a9d037

+21 -2
+1
include/linux/perf_event.h
··· 850 850 int nr_active; 851 851 int is_active; 852 852 int nr_stat; 853 + int rotate_disable; 853 854 atomic_t refcount; 854 855 struct task_struct *task; 855 856
+20 -2
kernel/perf_event.c
··· 1622 1622 { 1623 1623 raw_spin_lock(&ctx->lock); 1624 1624 1625 - /* Rotate the first entry last of non-pinned groups */ 1626 - list_rotate_left(&ctx->flexible_groups); 1625 + /* 1626 + * Rotate the first entry last of non-pinned groups. Rotation might be 1627 + * disabled by the inheritance code. 1628 + */ 1629 + if (!ctx->rotate_disable) 1630 + list_rotate_left(&ctx->flexible_groups); 1627 1631 1628 1632 raw_spin_unlock(&ctx->lock); 1629 1633 } ··· 6166 6162 struct perf_event *event; 6167 6163 struct task_struct *parent = current; 6168 6164 int inherited_all = 1; 6165 + unsigned long flags; 6169 6166 int ret = 0; 6170 6167 6171 6168 child->perf_event_ctxp[ctxn] = NULL; ··· 6207 6202 break; 6208 6203 } 6209 6204 6205 + /* 6206 + * We can't hold ctx->lock when iterating the ->flexible_group list due 6207 + * to allocations, but we need to prevent rotation because 6208 + * rotate_ctx() will change the list from interrupt context. 6209 + */ 6210 + raw_spin_lock_irqsave(&parent_ctx->lock, flags); 6211 + parent_ctx->rotate_disable = 1; 6212 + raw_spin_unlock_irqrestore(&parent_ctx->lock, flags); 6213 + 6210 6214 list_for_each_entry(event, &parent_ctx->flexible_groups, group_entry) { 6211 6215 ret = inherit_task_group(event, parent, parent_ctx, 6212 6216 child, ctxn, &inherited_all); 6213 6217 if (ret) 6214 6218 break; 6215 6219 } 6220 + 6221 + raw_spin_lock_irqsave(&parent_ctx->lock, flags); 6222 + parent_ctx->rotate_disable = 0; 6223 + raw_spin_unlock_irqrestore(&parent_ctx->lock, flags); 6216 6224 6217 6225 child_ctx = child->perf_event_ctxp[ctxn]; 6218 6226