From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1760101AbcBYIIw (ORCPT ); Thu, 25 Feb 2016 03:08:52 -0500 Received: from torg.zytor.com ([198.137.202.12]:59034 "EHLO terminus.zytor.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1759889AbcBYIIu (ORCPT ); Thu, 25 Feb 2016 03:08:50 -0500 Date: Thu, 25 Feb 2016 00:08:15 -0800 From: tip-bot for Peter Zijlstra Message-ID: Cc: acme@redhat.com, mingo@kernel.org, torvalds@linux-foundation.org, alexander.shishkin@linux.intel.com, hpa@zytor.com, peterz@infradead.org, linux-kernel@vger.kernel.org, tglx@linutronix.de, jolsa@redhat.com Reply-To: linux-kernel@vger.kernel.org, tglx@linutronix.de, jolsa@redhat.com, hpa@zytor.com, peterz@infradead.org, mingo@kernel.org, acme@redhat.com, alexander.shishkin@linux.intel.com, torvalds@linux-foundation.org In-Reply-To: <20160224174948.340031200@infradead.org> References: <20160224174948.340031200@infradead.org> To: linux-tip-commits@vger.kernel.org Subject: [tip:perf/urgent] perf: Robustify task_function_call() Git-Commit-ID: 0da4cf3e0a68c97ef811569804616a811f786729 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: 0da4cf3e0a68c97ef811569804616a811f786729 Gitweb: http://git.kernel.org/tip/0da4cf3e0a68c97ef811569804616a811f786729 Author: Peter Zijlstra AuthorDate: Wed, 24 Feb 2016 18:45:51 +0100 Committer: Ingo Molnar CommitDate: Thu, 25 Feb 2016 08:44:29 +0100 perf: Robustify task_function_call() Since there is no serialization between task_function_call() doing task_curr() and the other CPU doing context switches, we could end up not sending an IPI even if we had to. And I'm not sure I still buy my own argument we're OK. Signed-off-by: Peter Zijlstra (Intel) Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: dvyukov@google.com Cc: eranian@google.com Cc: oleg@redhat.com Cc: panand@redhat.com Cc: sasha.levin@oracle.com Cc: vince@deater.net Link: http://lkml.kernel.org/r/20160224174948.340031200@infradead.org Signed-off-by: Ingo Molnar --- kernel/events/core.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/kernel/events/core.c b/kernel/events/core.c index 25edabd..6146148 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -64,8 +64,17 @@ static void remote_function(void *data) struct task_struct *p = tfc->p; if (p) { - tfc->ret = -EAGAIN; - if (task_cpu(p) != smp_processor_id() || !task_curr(p)) + /* -EAGAIN */ + if (task_cpu(p) != smp_processor_id()) + return; + + /* + * Now that we're on right CPU with IRQs disabled, we can test + * if we hit the right task without races. + */ + + tfc->ret = -ESRCH; /* No such (running) process */ + if (p != current) return; } @@ -92,13 +101,17 @@ task_function_call(struct task_struct *p, remote_function_f func, void *info) .p = p, .func = func, .info = info, - .ret = -ESRCH, /* No such (running) process */ + .ret = -EAGAIN, }; + int ret; - if (task_curr(p)) - smp_call_function_single(task_cpu(p), remote_function, &data, 1); + do { + ret = smp_call_function_single(task_cpu(p), remote_function, &data, 1); + if (!ret) + ret = data.ret; + } while (ret == -EAGAIN); - return data.ret; + return ret; } /** @@ -169,19 +182,6 @@ static bool is_kernel_event(struct perf_event *event) * rely on ctx->is_active and therefore cannot use event_function_call(). * See perf_install_in_context(). * - * This is because we need a ctx->lock serialized variable (ctx->is_active) - * to reliably determine if a particular task/context is scheduled in. The - * task_curr() use in task_function_call() is racy in that a remote context - * switch is not a single atomic operation. - * - * As is, the situation is 'safe' because we set rq->curr before we do the - * actual context switch. This means that task_curr() will fail early, but - * we'll continue spinning on ctx->is_active until we've passed - * perf_event_task_sched_out(). - * - * Without this ctx->lock serialized variable we could have race where we find - * the task (and hence the context) would not be active while in fact they are. - * * If ctx->nr_events, then ctx->is_active and cpuctx->task_ctx are set. */ @@ -212,7 +212,7 @@ static int event_function(void *info) */ if (ctx->task) { if (ctx->task != current) { - ret = -EAGAIN; + ret = -ESRCH; goto unlock; }