lkml.org 
[lkml]   [2010]   [Mar]   [30]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[051/116] perf_event: Fix oops triggered by cpu offline/online
    2.6.32-stable review patch.  If anyone has any objections, please let us know.

    ------------------

    From: Paul Mackerras <paulus@samba.org>

    commit 220b140b52ab6cc133f674a7ffec8fa792054f25 upstream.

    Anton Blanchard found that he could reliably make the kernel hit a
    BUG_ON in the slab allocator by taking a cpu offline and then online
    while a system-wide perf record session was running.

    The reason is that when the cpu comes up, we completely reinitialize
    the ctx field of the struct perf_cpu_context for the cpu. If there is
    a system-wide perf record session running, then there will be a struct
    perf_event that has a reference to the context, so its refcount will
    be 2. (The perf_event has been removed from the context's group_entry
    and event_entry lists by perf_event_exit_cpu(), but that doesn't
    remove the perf_event's reference to the context and doesn't decrement
    the context's refcount.)

    When the cpu comes up, perf_event_init_cpu() gets called, and it calls
    __perf_event_init_context() on the cpu's context. That resets the
    refcount to 1. Then when the perf record session finishes and the
    perf_event is closed, the refcount gets decremented to 0 and the
    context gets kfreed after an RCU grace period. Since the context
    wasn't kmalloced -- it's part of a per-cpu variable -- bad things
    happen.

    In fact we don't need to completely reinitialize the context when the
    cpu comes up. It's sufficient to initialize the context once at boot,
    but we need to do it for all possible cpus.

    This moves the context initialization to happen at boot time. With
    this, we don't trash the refcount and the context never gets kfreed,
    and we don't hit the BUG_ON.

    Reported-by: Anton Blanchard <anton@samba.org>
    Signed-off-by: Paul Mackerras <paulus@samba.org>
    Tested-by: Anton Blanchard <anton@samba.org>
    Acked-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
    Signed-off-by: Ingo Molnar <mingo@elte.hu>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

    ---
    kernel/perf_event.c | 13 ++++++++++++-
    1 file changed, 12 insertions(+), 1 deletion(-)

    --- a/kernel/perf_event.c
    +++ b/kernel/perf_event.c
    @@ -4981,12 +4981,22 @@ int perf_event_init_task(struct task_str
    return ret;
    }

    +static void __init perf_event_init_all_cpus(void)
    +{
    + int cpu;
    + struct perf_cpu_context *cpuctx;
    +
    + for_each_possible_cpu(cpu) {
    + cpuctx = &per_cpu(perf_cpu_context, cpu);
    + __perf_event_init_context(&cpuctx->ctx, NULL);
    + }
    +}
    +
    static void __cpuinit perf_event_init_cpu(int cpu)
    {
    struct perf_cpu_context *cpuctx;

    cpuctx = &per_cpu(perf_cpu_context, cpu);
    - __perf_event_init_context(&cpuctx->ctx, NULL);

    spin_lock(&perf_resource_lock);
    cpuctx->max_pertask = perf_max_events - perf_reserved_percpu;
    @@ -5057,6 +5067,7 @@ static struct notifier_block __cpuinitda

    void __init perf_event_init(void)
    {
    + perf_event_init_all_cpus();
    perf_cpu_notify(&perf_cpu_nb, (unsigned long)CPU_UP_PREPARE,
    (void *)(long)smp_processor_id());
    perf_cpu_notify(&perf_cpu_nb, (unsigned long)CPU_ONLINE,



    \
     
     \ /
      Last update: 2010-03-31 01:21    [W:2.772 / U:0.004 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site