This patch doesn't apply to the .36 stable tree
If someone wants it applied there, please email the backport
to [email protected]

thanks,

greg k-h

> commit: dddd3379a619a4cb8247bfd3c94ca9ae3797aa2e
> From: Thomas Gleixner <[email protected]>
> Date: Wed, 24 Nov 2010 10:05:55 +0100
> Subject: [PATCH] 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 <[email protected]>
> Signed-off-by: Peter Zijlstra <[email protected]>
> LKML-Reference: <new-submission>
> Cc: <[email protected]>
> Signed-off-by: Ingo Molnar <[email protected]>
> ---
>  include/linux/perf_event.h |    1 +
>  kernel/perf_event.c        |   22 ++++++++++++++++++++--
>  2 files changed, 21 insertions(+), 2 deletions(-)
> 
> diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
> index 40150f3..142e3d6 100644
> --- a/include/linux/perf_event.h
> +++ b/include/linux/perf_event.h
> @@ -850,6 +850,7 @@ struct perf_event_context {
>       int                             nr_active;
>       int                             is_active;
>       int                             nr_stat;
> +     int                             rotate_disable;
>       atomic_t                        refcount;
>       struct task_struct              *task;
>  
> diff --git a/kernel/perf_event.c b/kernel/perf_event.c
> index 671f6c8..f365dd8 100644
> --- a/kernel/perf_event.c
> +++ b/kernel/perf_event.c
> @@ -1622,8 +1622,12 @@ static void rotate_ctx(struct perf_event_context *ctx)
>  {
>       raw_spin_lock(&ctx->lock);
>  
> -     /* Rotate the first entry last of non-pinned groups */
> -     list_rotate_left(&ctx->flexible_groups);
> +     /*
> +      * Rotate the first entry last of non-pinned groups. Rotation might be
> +      * disabled by the inheritance code.
> +      */
> +     if (!ctx->rotate_disable)
> +             list_rotate_left(&ctx->flexible_groups);
>  
>       raw_spin_unlock(&ctx->lock);
>  }
> @@ -6162,6 +6166,7 @@ int perf_event_init_context(struct task_struct *child, 
> int ctxn)
>       struct perf_event *event;
>       struct task_struct *parent = current;
>       int inherited_all = 1;
> +     unsigned long flags;
>       int ret = 0;
>  
>       child->perf_event_ctxp[ctxn] = NULL;
> @@ -6202,6 +6207,15 @@ int perf_event_init_context(struct task_struct *child, 
> int ctxn)
>                       break;
>       }
>  
> +     /*
> +      * We can't hold ctx->lock when iterating the ->flexible_group list due
> +      * to allocations, but we need to prevent rotation because
> +      * rotate_ctx() will change the list from interrupt context.
> +      */
> +     raw_spin_lock_irqsave(&parent_ctx->lock, flags);
> +     parent_ctx->rotate_disable = 1;
> +     raw_spin_unlock_irqrestore(&parent_ctx->lock, flags);
> +
>       list_for_each_entry(event, &parent_ctx->flexible_groups, group_entry) {
>               ret = inherit_task_group(event, parent, parent_ctx,
>                                        child, ctxn, &inherited_all);
> @@ -6209,6 +6223,10 @@ int perf_event_init_context(struct task_struct *child, 
> int ctxn)
>                       break;
>       }
>  
> +     raw_spin_lock_irqsave(&parent_ctx->lock, flags);
> +     parent_ctx->rotate_disable = 0;
> +     raw_spin_unlock_irqrestore(&parent_ctx->lock, flags);
> +
>       child_ctx = child->perf_event_ctxp[ctxn];
>  
>       if (child_ctx && inherited_all) {
> 
> _______________________________________________
> stable mailing list
> [email protected]
> http://linux.kernel.org/mailman/listinfo/stable

_______________________________________________
stable mailing list
[email protected]
http://linux.kernel.org/mailman/listinfo/stable

Reply via email to