From patchwork Thu Apr 24 12:24:51 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Lezcano X-Patchwork-Id: 28963 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-ig0-f199.google.com (mail-ig0-f199.google.com [209.85.213.199]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id F3B6D203AC for ; Thu, 24 Apr 2014 12:27:28 +0000 (UTC) Received: by mail-ig0-f199.google.com with SMTP id c1sf2755919igq.2 for ; Thu, 24 Apr 2014 05:27:28 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:delivered-to:from:to:cc:subject :date:message-id:in-reply-to:references:sender:precedence:list-id :x-original-sender:x-original-authentication-results:mailing-list :list-post:list-help:list-archive:list-unsubscribe; bh=FK+QjxGj1ZvtA8dUjDMDrBIEPobdkHDNk1K7/QJrHlk=; b=GRrtwW6urQJEAII5LHgdwuw+0DmRGjHhEHAdxz1L92KnVLXnOSu2d/1wp4KcvcDEKo bgeGvvRxp+3xKp9MGyS/wIeUYsQJWaArl0+3BZJKEz4JtoDYbCyEA8hy+wLkS4/X7itc LoFDyuIzxOMiBVMnaKVUYovrv/BjxHjtfKl/nZRGzT9WZ3xqJTRnJkgUfgyi4yzB1x2f dGorUBQEr2aFL0PhANzjH//2zfp2+MPHaRZr2qy0N2IQL1DBKHfFuRBTs1vgC6XAHZ17 IscYJYREo8yLypFjU5IbdvPXdTEn0FrAqaJqgEjIa4+Bpi5WR6amG+8n8l8tOer4RXuV p7gw== X-Gm-Message-State: ALoCoQlwkAaQqyyIAbuuhKrFtQQYIzwvYAhXHWABssemT/sQiF8DTKhaqN0lim+X06MZ5Lf7TeTa X-Received: by 10.182.230.132 with SMTP id sy4mr1033803obc.48.1398342448087; Thu, 24 Apr 2014 05:27:28 -0700 (PDT) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.140.17.3 with SMTP id 3ls1038271qgc.83.gmail; Thu, 24 Apr 2014 05:27:27 -0700 (PDT) X-Received: by 10.221.62.131 with SMTP id xa3mr1040078vcb.13.1398342447840; Thu, 24 Apr 2014 05:27:27 -0700 (PDT) Received: from mail-vc0-f169.google.com (mail-vc0-f169.google.com [209.85.220.169]) by mx.google.com with ESMTPS id sh5si878245vdc.68.2014.04.24.05.27.27 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Thu, 24 Apr 2014 05:27:27 -0700 (PDT) Received-SPF: none (google.com: patch+caf_=patchwork-forward=linaro.org@linaro.org does not designate permitted sender hosts) client-ip=209.85.220.169; Received: by mail-vc0-f169.google.com with SMTP id im17so2891189vcb.0 for ; Thu, 24 Apr 2014 05:27:27 -0700 (PDT) X-Received: by 10.58.187.78 with SMTP id fq14mr1044393vec.9.1398342447757; Thu, 24 Apr 2014 05:27:27 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patch@linaro.org Received: by 10.220.221.72 with SMTP id ib8csp11777vcb; Thu, 24 Apr 2014 05:27:27 -0700 (PDT) X-Received: by 10.68.216.101 with SMTP id op5mr2906334pbc.148.1398342446948; Thu, 24 Apr 2014 05:27:26 -0700 (PDT) Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id pb4si2575075pac.277.2014.04.24.05.27.26; Thu, 24 Apr 2014 05:27:26 -0700 (PDT) Received-SPF: none (google.com: linux-kernel-owner@vger.kernel.org does not designate permitted sender hosts) client-ip=209.132.180.67; Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756864AbaDXM1P (ORCPT + 27 others); Thu, 24 Apr 2014 08:27:15 -0400 Received: from mail-wi0-f172.google.com ([209.85.212.172]:53202 "EHLO mail-wi0-f172.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756017AbaDXMYb (ORCPT ); Thu, 24 Apr 2014 08:24:31 -0400 Received: by mail-wi0-f172.google.com with SMTP id hi2so955290wib.11 for ; Thu, 24 Apr 2014 05:24:29 -0700 (PDT) X-Received: by 10.180.219.75 with SMTP id pm11mr2632530wic.8.1398342269738; Thu, 24 Apr 2014 05:24:29 -0700 (PDT) Received: from localhost.localdomain (AToulouse-654-1-448-67.w83-205.abo.wanadoo.fr. [83.205.199.67]) by mx.google.com with ESMTPSA id wl6sm6008074wjb.3.2014.04.24.05.24.28 for (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Thu, 24 Apr 2014 05:24:29 -0700 (PDT) From: Daniel Lezcano To: peterz@infradead.org, mingo@elte.hu Cc: linux-kernel@vger.kernel.org, rjw@rjwysocki.net, linux-pm@vger.kernel.org, alex.shi@linaro.org, vincent.guittot@linaro.org, morten.rasmussen@arm.com, linaro-kernel@lists.linaro.org Subject: [PATCH 3/3] sched: idle: Store the idle state the cpu is Date: Thu, 24 Apr 2014 14:24:51 +0200 Message-Id: <1398342291-16322-4-git-send-email-daniel.lezcano@linaro.org> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1398342291-16322-1-git-send-email-daniel.lezcano@linaro.org> References: <1398342291-16322-1-git-send-email-daniel.lezcano@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: list List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: daniel.lezcano@linaro.org X-Original-Authentication-Results: mx.google.com; spf=neutral (google.com: patch+caf_=patchwork-forward=linaro.org@linaro.org does not designate permitted sender hosts) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , When the cpu enters idle it stores the cpuidle state pointer in the struct rq which in turn could be used to take a right decision when balancing a task. As soon as the cpu exits the idle state, the structure is filled back with the NULL pointer. There are a couple of situations where the idle state pointer could be changed while looking at it: 1. For x86/acpi with dynamic c-states, when a laptop switches from battery to AC that could result on removing the deeper idle state. The acpi driver triggers: 'acpi_processor_cst_has_changed' 'cpuidle_pause_and_lock' 'cpuidle_uninstall_idle_handler' 'kick_all_cpus_sync'. All cpus will exit their idle state and the pointed object will be set to NULL. 2. The cpuidle driver is unloaded. Logically that could happen but not in practice because the drivers are always compiled in and 95% of the drivers are not coded to unregister the driver. In any case, the unloading code must call 'cpuidle_unregister_device', that calls 'cpuidle_pause_and_lock' leading to 'kick_all_cpus_sync' as mentioned above. The race can happen if we use the pointer and then one of these two situations occurs at the same moment. In order to be safe, the idle state pointer stored in the rq must be used inside a rcu_read_lock section where we are protected with the 'rcu_barrier' in the 'cpuidle_uninstall_idle_handler' function. Signed-off-by: Daniel Lezcano --- drivers/cpuidle/cpuidle.c | 6 ++++++ kernel/sched/idle.c | 8 ++++++++ kernel/sched/sched.h | 5 +++++ 3 files changed, 19 insertions(+) diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 8236746..6a13f40 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -190,6 +190,12 @@ void cpuidle_install_idle_handler(void) */ void cpuidle_uninstall_idle_handler(void) { + /* + * Wait for the scheduler to finish to use the idle state he + * may pointing to when looking for the cpu idle states + */ + rcu_barrier(); + if (enabled_devices) { initialized = 0; kick_all_cpus_sync(); diff --git a/kernel/sched/idle.c b/kernel/sched/idle.c index e877dd4..4c14ec0 100644 --- a/kernel/sched/idle.c +++ b/kernel/sched/idle.c @@ -12,6 +12,8 @@ #include +#include "sched.h" + static int __read_mostly cpu_idle_force_poll; void cpu_idle_poll_ctrl(bool enable) @@ -66,6 +68,8 @@ void __weak arch_cpu_idle(void) #ifdef CONFIG_CPU_IDLE static int __cpuidle_idle_call(void) { + struct rq *rq = this_rq(); + struct cpuidle_state **idle_state = &rq->idle_state; struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices); struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev); int next_state, entered_state, ret; @@ -114,6 +118,8 @@ static int __cpuidle_idle_call(void) if (!ret) { trace_cpu_idle_rcuidle(next_state, dev->cpu); + *idle_state = &drv->states[next_state]; + /* * Enter the idle state previously returned by * the governor decision. This function will @@ -123,6 +129,8 @@ static int __cpuidle_idle_call(void) */ entered_state = cpuidle_enter(drv, dev, next_state); + *idle_state = NULL; + trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, dev->cpu); if (broadcast) diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 456e492..bace64a 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -14,6 +14,7 @@ #include "cpuacct.h" struct rq; +struct cpuidle_state; extern __read_mostly int scheduler_running; @@ -643,6 +644,10 @@ struct rq { #ifdef CONFIG_SMP struct llist_head wake_list; #endif + +#ifdef CONFIG_CPU_IDLE + struct cpuidle_state *idle_state; +#endif }; static inline int cpu_of(struct rq *rq)