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 int nr_active; 851 int is_active; 852 int nr_stat; 853 atomic_t refcount; 854 struct task_struct *task; 855
··· 850 int nr_active; 851 int is_active; 852 int nr_stat; 853 + int rotate_disable; 854 atomic_t refcount; 855 struct task_struct *task; 856
+20 -2
kernel/perf_event.c
··· 1622 { 1623 raw_spin_lock(&ctx->lock); 1624 1625 - /* Rotate the first entry last of non-pinned groups */ 1626 - list_rotate_left(&ctx->flexible_groups); 1627 1628 raw_spin_unlock(&ctx->lock); 1629 } ··· 6166 struct perf_event *event; 6167 struct task_struct *parent = current; 6168 int inherited_all = 1; 6169 int ret = 0; 6170 6171 child->perf_event_ctxp[ctxn] = NULL; ··· 6207 break; 6208 } 6209 6210 list_for_each_entry(event, &parent_ctx->flexible_groups, group_entry) { 6211 ret = inherit_task_group(event, parent, parent_ctx, 6212 child, ctxn, &inherited_all); 6213 if (ret) 6214 break; 6215 } 6216 6217 child_ctx = child->perf_event_ctxp[ctxn]; 6218
··· 1622 { 1623 raw_spin_lock(&ctx->lock); 1624 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); 1631 1632 raw_spin_unlock(&ctx->lock); 1633 } ··· 6162 struct perf_event *event; 6163 struct task_struct *parent = current; 6164 int inherited_all = 1; 6165 + unsigned long flags; 6166 int ret = 0; 6167 6168 child->perf_event_ctxp[ctxn] = NULL; ··· 6202 break; 6203 } 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 + 6214 list_for_each_entry(event, &parent_ctx->flexible_groups, group_entry) { 6215 ret = inherit_task_group(event, parent, parent_ctx, 6216 child, ctxn, &inherited_all); 6217 if (ret) 6218 break; 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); 6224 6225 child_ctx = child->perf_event_ctxp[ctxn]; 6226