[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <AANLkTimWMD5fCLfwPNh1_Qc3w08Vy=ErsRKpbprAimeX@mail.gmail.com>
Date: Sun, 28 Nov 2010 10:36:26 +0600
From: Rakib Mullick <rakib.mullick@...il.com>
To: mingo@...hat.com, hpa@...or.com, linux-kernel@...r.kernel.org,
a.p.zijlstra@...llo.nl, stable@...nel.org, tglx@...utronix.de,
mingo@...e.hu
Cc: linux-tip-commits@...r.kernel.org
Subject: Re: [tip:perf/core] perf: Fix inherit vs. context rotation bug
On Fri, Nov 26, 2010 at 9:00 PM, tip-bot for Thomas Gleixner
<tglx@...utronix.de> wrote:
> Commit-ID: dddd3379a619a4cb8247bfd3c94ca9ae3797aa2e
> Gitweb: http://git.kernel.org/tip/dddd3379a619a4cb8247bfd3c94ca9ae3797aa2e
> Author: Thomas Gleixner <tglx@...utronix.de>
> AuthorDate: Wed, 24 Nov 2010 10:05:55 +0100
> Committer: Ingo Molnar <mingo@...e.hu>
> CommitDate: Fri, 26 Nov 2010 15:00:56 +0100
>
> 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@...utronix.de>
> Signed-off-by: Peter Zijlstra <a.p.zijlstra@...llo.nl>
> LKML-Reference: <new-submission>
> Cc: <stable@...nel.org>
> Signed-off-by: Ingo Molnar <mingo@...e.hu>
> ---
> 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;
Isn't it convincing to use atomic_t instead of int as rotate_disable
type. Since, we just have to increment or decrement it inside
raw_spin_lock_irqsave(), we could've easily do it using
atomic_inc/atomic_dec and atomic_read while calling
list_rotate_left(). It will allow us to remove raw_spin_lock_irqsave()
at increment/decrement. Am I missing anyting?
thanks,
rakib
> 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) {
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@...r.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
>
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists