• P
    perf: Fix race in removing an event · 46ce0fe9
    Peter Zijlstra 提交于
    When removing a (sibling) event we do:
    
    	raw_spin_lock_irq(&ctx->lock);
    	perf_group_detach(event);
    	raw_spin_unlock_irq(&ctx->lock);
    
    	<hole>
    
    	perf_remove_from_context(event);
    		raw_spin_lock_irq(&ctx->lock);
    		...
    		raw_spin_unlock_irq(&ctx->lock);
    
    Now, assuming the event is a sibling, it will be 'unreachable' for
    things like ctx_sched_out() because that iterates the
    groups->siblings, and we just unhooked the sibling.
    
    So, if during <hole> we get ctx_sched_out(), it will miss the event
    and not call event_sched_out() on it, leaving it programmed on the
    PMU.
    
    The subsequent perf_remove_from_context() call will find the ctx is
    inactive and only call list_del_event() to remove the event from all
    other lists.
    
    Hereafter we can proceed to free the event; while still programmed!
    
    Close this hole by moving perf_group_detach() inside the same
    ctx->lock region(s) perf_remove_from_context() has.
    
    The condition on inherited events only in __perf_event_exit_task() is
    likely complete crap because non-inherited events are part of groups
    too and we're tearing down just the same. But leave that for another
    patch.
    
    Most-likely-Fixes: e03a9a55 ("perf: Change close() semantics for group events")
    Reported-by: NVince Weaver <vincent.weaver@maine.edu>
    Tested-by: NVince Weaver <vincent.weaver@maine.edu>
    Much-staring-at-traces-by: NVince Weaver <vincent.weaver@maine.edu>
    Much-staring-at-traces-by: NThomas Gleixner <tglx@linutronix.de>
    Cc: Arnaldo Carvalho de Melo <acme@kernel.org>
    Cc: Linus Torvalds <torvalds@linux-foundation.org>
    Signed-off-by: NPeter Zijlstra <peterz@infradead.org>
    Link: http://lkml.kernel.org/r/20140505093124.GN17778@laptop.programming.kicks-ass.netSigned-off-by: NIngo Molnar <mingo@kernel.org>
    46ce0fe9
core.c 186.7 KB