From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S966659AbbBDOkl (ORCPT ); Wed, 4 Feb 2015 09:40:41 -0500 Received: from terminus.zytor.com ([198.137.202.10]:38928 "EHLO terminus.zytor.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S965879AbbBDOkg (ORCPT ); Wed, 4 Feb 2015 09:40:36 -0500 Date: Wed, 4 Feb 2015 06:39:56 -0800 From: tip-bot for Peter Zijlstra Message-ID: Cc: acme@kernel.org, peterz@infradead.org, jolsa@redhat.com, mingo@kernel.org, torvalds@linux-foundation.org, eranian@gmail.com, hpa@zytor.com, tglx@linutronix.de, linux-kernel@vger.kernel.org, vincent.weaver@maine.edu Reply-To: hpa@zytor.com, tglx@linutronix.de, vincent.weaver@maine.edu, linux-kernel@vger.kernel.org, acme@kernel.org, peterz@infradead.org, mingo@kernel.org, jolsa@redhat.com, eranian@gmail.com, torvalds@linux-foundation.org In-Reply-To: <20150129134434.GB26304@twins.programming.kicks-ass.net> References: <20150129134434.GB26304@twins.programming.kicks-ass.net> To: linux-tip-commits@vger.kernel.org Subject: [tip:perf/core] perf: Fix put_event() ctx lock Git-Commit-ID: a83fe28e2e45392464858a96745db26ac73670c8 X-Mailer: tip-git-log-daemon Robot-ID: Robot-Unsubscribe: Contact to get blacklisted from these emails MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Content-Type: text/plain; charset=UTF-8 Content-Disposition: inline Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Commit-ID: a83fe28e2e45392464858a96745db26ac73670c8 Gitweb: http://git.kernel.org/tip/a83fe28e2e45392464858a96745db26ac73670c8 Author: Peter Zijlstra AuthorDate: Thu, 29 Jan 2015 14:44:34 +0100 Committer: Ingo Molnar CommitDate: Wed, 4 Feb 2015 08:07:12 +0100 perf: Fix put_event() ctx lock So what I suspect; but I'm in zombie mode today it seems; is that while I initially thought that it was impossible for ctx to change when refcount dropped to 0, I now suspect its possible. Note that until perf_remove_from_context() the event is still active and visible on the lists. So a concurrent sys_perf_event_open() from another task into this task can race. Reported-by: Vince Weaver Signed-off-by: Peter Zijlstra (Intel) Cc: Stephane Eranian Cc: mark.rutland@arm.com Cc: Jiri Olsa Cc: Arnaldo Carvalho de Melo Cc: Linus Torvalds Link: http://lkml.kernel.org/r/20150129134434.GB26304@twins.programming.kicks-ass.net Signed-off-by: Ingo Molnar --- kernel/events/core.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/kernel/events/core.c b/kernel/events/core.c index 142dbabc..f773fa1 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -947,7 +947,8 @@ static void put_ctx(struct perf_event_context *ctx) * perf_event::mmap_mutex * mmap_sem */ -static struct perf_event_context *perf_event_ctx_lock(struct perf_event *event) +static struct perf_event_context * +perf_event_ctx_lock_nested(struct perf_event *event, int nesting) { struct perf_event_context *ctx; @@ -960,7 +961,7 @@ again: } rcu_read_unlock(); - mutex_lock(&ctx->mutex); + mutex_lock_nested(&ctx->mutex, nesting); if (event->ctx != ctx) { mutex_unlock(&ctx->mutex); put_ctx(ctx); @@ -970,6 +971,12 @@ again: return ctx; } +static inline struct perf_event_context * +perf_event_ctx_lock(struct perf_event *event) +{ + return perf_event_ctx_lock_nested(event, 0); +} + static void perf_event_ctx_unlock(struct perf_event *event, struct perf_event_context *ctx) { @@ -3572,7 +3579,7 @@ static void perf_remove_from_owner(struct perf_event *event) */ static void put_event(struct perf_event *event) { - struct perf_event_context *ctx = event->ctx; + struct perf_event_context *ctx; if (!atomic_long_dec_and_test(&event->refcount)) return; @@ -3580,7 +3587,6 @@ static void put_event(struct perf_event *event) if (!is_kernel_event(event)) perf_remove_from_owner(event); - WARN_ON_ONCE(ctx->parent_ctx); /* * There are two ways this annotation is useful: * @@ -3593,7 +3599,8 @@ static void put_event(struct perf_event *event) * the last filedesc died, so there is no possibility * to trigger the AB-BA case. */ - mutex_lock_nested(&ctx->mutex, SINGLE_DEPTH_NESTING); + ctx = perf_event_ctx_lock_nested(event, SINGLE_DEPTH_NESTING); + WARN_ON_ONCE(ctx->parent_ctx); perf_remove_from_context(event, true); mutex_unlock(&ctx->mutex);