Received: by 10.213.65.68 with SMTP id h4csp216247imn; Fri, 23 Mar 2018 03:06:22 -0700 (PDT) X-Google-Smtp-Source: AG47ELt/do8rDDmqc/8DxdMvpkkAPEY9HvP+R5VzAbm6oglZGSq13ppt02iKeNvJHYBzo5NSqtpk X-Received: by 10.99.60.6 with SMTP id j6mr19956923pga.73.1521799582457; Fri, 23 Mar 2018 03:06:22 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1521799582; cv=none; d=google.com; s=arc-20160816; b=JXbqbRaLDkRuT/PdEkiup0RN+QuzluDZdAl7J/d1Dur72EuKSxf1wQHHmrNkHEIy8x 8CK4VDLSm2IjxisJfKWqkXGr1v8l9NwChSfzS/hBwIWiTV/35WyrhLwFel16/baPYTgB 67eqxR3/JKPwhDiM0/kZCFBh4xVGl5e3YwM9YascT2kms9E5LsRQONPmUmUoakTolaXA PWuXcB2eEBxUqRbgi4eDfr7FG/wnrWqFiJ0lzBx3ItY5rEZO6LVK52xTofwaXMxjci7z iwMR7hLTgYrtcskHZDvFVGB2GokhwoRu4pdgHaPBniRvp0CaB7L+RmsX1c8hKppH4rJM veWw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:mime-version:user-agent:references :in-reply-to:message-id:date:subject:cc:to:from :arc-authentication-results; bh=Gd/UcEXAO9cJh9mFZLh/TOskYuaWwtOzJCjwtlwPt4o=; b=HpSo8cXtiUSsPUETKCKE/gAhtl7D0mQYf4VuKw8DlRp8lM6TX3xULRRXjBpIHzPPLa iYIpUxzvxYfy8UZpbqOwz49pFj8VqrBiKsOLXOK2XSUUmQ/QoONyWU4VAq2kl5zl1Ca4 Frp1Xe/zvu6hfK5gKWmt9oB6jt7LDOlpWpoEw2bbjJE7x2h4P9kse6OoUYim79ht557x 5SSMhnT84d0m5XIgBFhAcMmeuPP1Ui9p2i4AR3VTpLfKSWRNAocOWNWuoI3z7SsIMsyz 5VmuehmRbhrqdMTLCe6ifSwUDoPexNUgKFUCCISwBAtC4CmczOl6FZBzENQAw7OF1W3A IrRQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id 92-v6si8204056plc.713.2018.03.23.03.06.07; Fri, 23 Mar 2018 03:06:22 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754912AbeCWKFM (ORCPT + 99 others); Fri, 23 Mar 2018 06:05:12 -0400 Received: from mail.linuxfoundation.org ([140.211.169.12]:39516 "EHLO mail.linuxfoundation.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754854AbeCWKFJ (ORCPT ); Fri, 23 Mar 2018 06:05:09 -0400 Received: from localhost (LFbn-1-12247-202.w90-92.abo.wanadoo.fr [90.92.61.202]) by mail.linuxfoundation.org (Postfix) with ESMTPSA id 7796E13FE; Fri, 23 Mar 2018 10:05:08 +0000 (UTC) From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Thomas Gleixner , Fenghua Yu , Tony Luck , Herbert Xu , "Rafael J. Wysocki" , Peter Zijlstra , Benjamin Herrenschmidt , Sebastian Siewior , Lai Jiangshan , linux-acpi@vger.kernel.org, Viresh Kumar , Michael Ellerman , Tejun Heo , "David S. Miller" , Len Brown , Sasha Levin Subject: [PATCH 4.9 017/177] ACPI/processor: Replace racy task affinity logic Date: Fri, 23 Mar 2018 10:52:25 +0100 Message-Id: <20180323094205.954384495@linuxfoundation.org> X-Mailer: git-send-email 2.16.2 In-Reply-To: <20180323094205.090519271@linuxfoundation.org> References: <20180323094205.090519271@linuxfoundation.org> User-Agent: quilt/0.65 X-stable: review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 4.9-stable review patch. If anyone has any objections, please let me know. ------------------ From: Thomas Gleixner [ Upstream commit 8153f9ac43897f9f4786b30badc134fcc1a4fb11 ] acpi_processor_get_throttling() requires to invoke the getter function on the target CPU. This is achieved by temporarily setting the affinity of the calling user space thread to the requested CPU and reset it to the original affinity afterwards. That's racy vs. CPU hotplug and concurrent affinity settings for that thread resulting in code executing on the wrong CPU and overwriting the new affinity setting. acpi_processor_get_throttling() is invoked in two ways: 1) The CPU online callback, which is already running on the target CPU and obviously protected against hotplug and not affected by affinity settings. 2) The ACPI driver probe function, which is not protected against hotplug during modprobe. Switch it over to work_on_cpu() and protect the probe function against CPU hotplug. Signed-off-by: Thomas Gleixner Cc: Fenghua Yu Cc: Tony Luck Cc: Herbert Xu Cc: "Rafael J. Wysocki" Cc: Peter Zijlstra Cc: Benjamin Herrenschmidt Cc: Sebastian Siewior Cc: Lai Jiangshan Cc: linux-acpi@vger.kernel.org Cc: Viresh Kumar Cc: Michael Ellerman Cc: Tejun Heo Cc: "David S. Miller" Cc: Len Brown Link: http://lkml.kernel.org/r/20170412201042.785920903@linutronix.de Signed-off-by: Thomas Gleixner Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/processor_driver.c | 7 +++- drivers/acpi/processor_throttling.c | 62 ++++++++++++++++++++---------------- 2 files changed, 42 insertions(+), 27 deletions(-) --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -262,11 +262,16 @@ err_power_exit: static int acpi_processor_start(struct device *dev) { struct acpi_device *device = ACPI_COMPANION(dev); + int ret; if (!device) return -ENODEV; - return __acpi_processor_start(device); + /* Protect against concurrent CPU hotplug operations */ + get_online_cpus(); + ret = __acpi_processor_start(device); + put_online_cpus(); + return ret; } static int acpi_processor_stop(struct device *dev) --- a/drivers/acpi/processor_throttling.c +++ b/drivers/acpi/processor_throttling.c @@ -62,8 +62,8 @@ struct acpi_processor_throttling_arg { #define THROTTLING_POSTCHANGE (2) static int acpi_processor_get_throttling(struct acpi_processor *pr); -int acpi_processor_set_throttling(struct acpi_processor *pr, - int state, bool force); +static int __acpi_processor_set_throttling(struct acpi_processor *pr, + int state, bool force, bool direct); static int acpi_processor_update_tsd_coord(void) { @@ -891,7 +891,8 @@ static int acpi_processor_get_throttling ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Invalid throttling state, reset\n")); state = 0; - ret = acpi_processor_set_throttling(pr, state, true); + ret = __acpi_processor_set_throttling(pr, state, true, + true); if (ret) return ret; } @@ -901,36 +902,31 @@ static int acpi_processor_get_throttling return 0; } -static int acpi_processor_get_throttling(struct acpi_processor *pr) +static long __acpi_processor_get_throttling(void *data) { - cpumask_var_t saved_mask; - int ret; + struct acpi_processor *pr = data; + + return pr->throttling.acpi_processor_get_throttling(pr); +} +static int acpi_processor_get_throttling(struct acpi_processor *pr) +{ if (!pr) return -EINVAL; if (!pr->flags.throttling) return -ENODEV; - if (!alloc_cpumask_var(&saved_mask, GFP_KERNEL)) - return -ENOMEM; - /* - * Migrate task to the cpu pointed by pr. + * This is either called from the CPU hotplug callback of + * processor_driver or via the ACPI probe function. In the latter + * case the CPU is not guaranteed to be online. Both call sites are + * protected against CPU hotplug. */ - cpumask_copy(saved_mask, ¤t->cpus_allowed); - /* FIXME: use work_on_cpu() */ - if (set_cpus_allowed_ptr(current, cpumask_of(pr->id))) { - /* Can't migrate to the target pr->id CPU. Exit */ - free_cpumask_var(saved_mask); + if (!cpu_online(pr->id)) return -ENODEV; - } - ret = pr->throttling.acpi_processor_get_throttling(pr); - /* restore the previous state */ - set_cpus_allowed_ptr(current, saved_mask); - free_cpumask_var(saved_mask); - return ret; + return work_on_cpu(pr->id, __acpi_processor_get_throttling, pr); } static int acpi_processor_get_fadt_info(struct acpi_processor *pr) @@ -1080,8 +1076,15 @@ static long acpi_processor_throttling_fn arg->target_state, arg->force); } -int acpi_processor_set_throttling(struct acpi_processor *pr, - int state, bool force) +static int call_on_cpu(int cpu, long (*fn)(void *), void *arg, bool direct) +{ + if (direct) + return fn(arg); + return work_on_cpu(cpu, fn, arg); +} + +static int __acpi_processor_set_throttling(struct acpi_processor *pr, + int state, bool force, bool direct) { int ret = 0; unsigned int i; @@ -1130,7 +1133,8 @@ int acpi_processor_set_throttling(struct arg.pr = pr; arg.target_state = state; arg.force = force; - ret = work_on_cpu(pr->id, acpi_processor_throttling_fn, &arg); + ret = call_on_cpu(pr->id, acpi_processor_throttling_fn, &arg, + direct); } else { /* * When the T-state coordination is SW_ALL or HW_ALL, @@ -1163,8 +1167,8 @@ int acpi_processor_set_throttling(struct arg.pr = match_pr; arg.target_state = state; arg.force = force; - ret = work_on_cpu(pr->id, acpi_processor_throttling_fn, - &arg); + ret = call_on_cpu(pr->id, acpi_processor_throttling_fn, + &arg, direct); } } /* @@ -1182,6 +1186,12 @@ int acpi_processor_set_throttling(struct return ret; } +int acpi_processor_set_throttling(struct acpi_processor *pr, int state, + bool force) +{ + return __acpi_processor_set_throttling(pr, state, force, false); +} + int acpi_processor_get_throttling_info(struct acpi_processor *pr) { int result = 0;