Received: by 10.213.65.68 with SMTP id h4csp250139imn; Fri, 23 Mar 2018 03:56:55 -0700 (PDT) X-Google-Smtp-Source: AG47ELvB1qfkqirgLLrwjSVKoosgh9dQekl2MNwctenOlWJUfV/YnYmxbcKQfH24LIdgjZQ6KWvm X-Received: by 10.98.51.129 with SMTP id z123mr23758758pfz.132.1521802615204; Fri, 23 Mar 2018 03:56:55 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1521802615; cv=none; d=google.com; s=arc-20160816; b=RUlwevoyIf3It9/yz0l97S6SkpFGZY1blizq+SwNnTD6VC9ylL9CfvgqkKl92Gpg6U kPaF9l55DQR3zkhM4ZUE86sv6l30xrMmJW4y/N/nctIOerzA6jo1M8iYCA19I4EVNeSI VbPkdYfioCVDwVqWv60XsCdn43OVs9oZ1nEEpfrquZ66AYoe4CHiGBPAXNzStHm0cQ9U LbGvYCNa0q5oLZ/6wxEV9Q77lnnwDzSvFNhzGjxnFvmntXm/896LLiy9uoZRh97RJXhP yjw+Xx2WibgcGbwBEmhNS9b0Gr4OfNo0lvz2KuqCarZNwpqP6lOxaLk0Fop56i0vgL3Q xJwQ== 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=4R/Tsp6BhI1LRuepcyO6e5rCSuD+eRQxoBjJ2kk6cBk=; b=a9T41H7ep2uJHooSiPbuxNcP73Wfx0CpIE8so2r5ZR71POtcc0tnrzC26GsQs0WGut kL3nFLkv6R2C/s4XL0nyWnKuCn6UzV6NwQzALDvZx+54cHk1UVjLYRH4xuWdzcFPGsJn EmwoAtEcOVmZ2+MlV75oxevCOJysYX07QlCymnA/Q2GSTX8tD2ZA8JX1fyGIfiukyzCj Vi194nOWp5UgW2D/jdXITALWCmhG5mlH83bARoX9sKXJu88PYGkU4rsHu40pkQJAPzA2 AAGVWyG0251kuJQ5Y/1sUcRyXtexr1mIYVfp7Z8YMX+4O203/XNc7WRFFUFcuGs0A5Kj H/cQ== 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 a84si6739512pfl.154.2018.03.23.03.56.40; Fri, 23 Mar 2018 03:56:55 -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 S1755805AbeCWKNN (ORCPT + 99 others); Fri, 23 Mar 2018 06:13:13 -0400 Received: from mail.linuxfoundation.org ([140.211.169.12]:44666 "EHLO mail.linuxfoundation.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752469AbeCWKNL (ORCPT ); Fri, 23 Mar 2018 06:13:11 -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 2860911E1; Fri, 23 Mar 2018 10:13:10 +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.4 13/97] ACPI/processor: Replace racy task affinity logic Date: Fri, 23 Mar 2018 10:54:00 +0100 Message-Id: <20180323094158.240658328@linuxfoundation.org> X-Mailer: git-send-email 2.16.2 In-Reply-To: <20180323094157.535925724@linuxfoundation.org> References: <20180323094157.535925724@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.4-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 @@ -270,11 +270,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;