aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2017-04-12 16:07:34 -0400
committerThomas Gleixner <tglx@linutronix.de>2017-04-15 06:20:54 -0400
commit8153f9ac43897f9f4786b30badc134fcc1a4fb11 (patch)
tree94f3d52a87a0e9dec031c899dd568fb0977d4e16
parenta5cbdf693a60d5b86d4d21dfedd90f17754eb273 (diff)
ACPI/processor: Replace racy task affinity logic
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 <tglx@linutronix.de> Cc: Fenghua Yu <fenghua.yu@intel.com> Cc: Tony Luck <tony.luck@intel.com> Cc: Herbert Xu <herbert@gondor.apana.org.au> Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Sebastian Siewior <bigeasy@linutronix.de> Cc: Lai Jiangshan <jiangshanlai@gmail.com> Cc: linux-acpi@vger.kernel.org Cc: Viresh Kumar <viresh.kumar@linaro.org> Cc: Michael Ellerman <mpe@ellerman.id.au> Cc: Tejun Heo <tj@kernel.org> Cc: "David S. Miller" <davem@davemloft.net> Cc: Len Brown <lenb@kernel.org> Link: http://lkml.kernel.org/r/20170412201042.785920903@linutronix.de Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--drivers/acpi/processor_driver.c7
-rw-r--r--drivers/acpi/processor_throttling.c62
2 files changed, 42 insertions, 27 deletions
diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c
index eab8cdad7dc3..8697a82bd465 100644
--- a/drivers/acpi/processor_driver.c
+++ b/drivers/acpi/processor_driver.c
@@ -262,11 +262,16 @@ err_power_exit:
262static int acpi_processor_start(struct device *dev) 262static int acpi_processor_start(struct device *dev)
263{ 263{
264 struct acpi_device *device = ACPI_COMPANION(dev); 264 struct acpi_device *device = ACPI_COMPANION(dev);
265 int ret;
265 266
266 if (!device) 267 if (!device)
267 return -ENODEV; 268 return -ENODEV;
268 269
269 return __acpi_processor_start(device); 270 /* Protect against concurrent CPU hotplug operations */
271 get_online_cpus();
272 ret = __acpi_processor_start(device);
273 put_online_cpus();
274 return ret;
270} 275}
271 276
272static int acpi_processor_stop(struct device *dev) 277static int acpi_processor_stop(struct device *dev)
diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c
index a12f96cc93ff..3de34633f7f9 100644
--- a/drivers/acpi/processor_throttling.c
+++ b/drivers/acpi/processor_throttling.c
@@ -62,8 +62,8 @@ struct acpi_processor_throttling_arg {
62#define THROTTLING_POSTCHANGE (2) 62#define THROTTLING_POSTCHANGE (2)
63 63
64static int acpi_processor_get_throttling(struct acpi_processor *pr); 64static int acpi_processor_get_throttling(struct acpi_processor *pr);
65int acpi_processor_set_throttling(struct acpi_processor *pr, 65static int __acpi_processor_set_throttling(struct acpi_processor *pr,
66 int state, bool force); 66 int state, bool force, bool direct);
67 67
68static int acpi_processor_update_tsd_coord(void) 68static int acpi_processor_update_tsd_coord(void)
69{ 69{
@@ -891,7 +891,8 @@ static int acpi_processor_get_throttling_ptc(struct acpi_processor *pr)
891 ACPI_DEBUG_PRINT((ACPI_DB_INFO, 891 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
892 "Invalid throttling state, reset\n")); 892 "Invalid throttling state, reset\n"));
893 state = 0; 893 state = 0;
894 ret = acpi_processor_set_throttling(pr, state, true); 894 ret = __acpi_processor_set_throttling(pr, state, true,
895 true);
895 if (ret) 896 if (ret)
896 return ret; 897 return ret;
897 } 898 }
@@ -901,36 +902,31 @@ static int acpi_processor_get_throttling_ptc(struct acpi_processor *pr)
901 return 0; 902 return 0;
902} 903}
903 904
904static int acpi_processor_get_throttling(struct acpi_processor *pr) 905static long __acpi_processor_get_throttling(void *data)
905{ 906{
906 cpumask_var_t saved_mask; 907 struct acpi_processor *pr = data;
907 int ret; 908
909 return pr->throttling.acpi_processor_get_throttling(pr);
910}
908 911
912static int acpi_processor_get_throttling(struct acpi_processor *pr)
913{
909 if (!pr) 914 if (!pr)
910 return -EINVAL; 915 return -EINVAL;
911 916
912 if (!pr->flags.throttling) 917 if (!pr->flags.throttling)
913 return -ENODEV; 918 return -ENODEV;
914 919
915 if (!alloc_cpumask_var(&saved_mask, GFP_KERNEL))
916 return -ENOMEM;
917
918 /* 920 /*
919 * Migrate task to the cpu pointed by pr. 921 * This is either called from the CPU hotplug callback of
922 * processor_driver or via the ACPI probe function. In the latter
923 * case the CPU is not guaranteed to be online. Both call sites are
924 * protected against CPU hotplug.
920 */ 925 */
921 cpumask_copy(saved_mask, &current->cpus_allowed); 926 if (!cpu_online(pr->id))
922 /* FIXME: use work_on_cpu() */
923 if (set_cpus_allowed_ptr(current, cpumask_of(pr->id))) {
924 /* Can't migrate to the target pr->id CPU. Exit */
925 free_cpumask_var(saved_mask);
926 return -ENODEV; 927 return -ENODEV;
927 }
928 ret = pr->throttling.acpi_processor_get_throttling(pr);
929 /* restore the previous state */
930 set_cpus_allowed_ptr(current, saved_mask);
931 free_cpumask_var(saved_mask);
932 928
933 return ret; 929 return work_on_cpu(pr->id, __acpi_processor_get_throttling, pr);
934} 930}
935 931
936static int acpi_processor_get_fadt_info(struct acpi_processor *pr) 932static int acpi_processor_get_fadt_info(struct acpi_processor *pr)
@@ -1080,8 +1076,15 @@ static long acpi_processor_throttling_fn(void *data)
1080 arg->target_state, arg->force); 1076 arg->target_state, arg->force);
1081} 1077}
1082 1078
1083int acpi_processor_set_throttling(struct acpi_processor *pr, 1079static int call_on_cpu(int cpu, long (*fn)(void *), void *arg, bool direct)
1084 int state, bool force) 1080{
1081 if (direct)
1082 return fn(arg);
1083 return work_on_cpu(cpu, fn, arg);
1084}
1085
1086static int __acpi_processor_set_throttling(struct acpi_processor *pr,
1087 int state, bool force, bool direct)
1085{ 1088{
1086 int ret = 0; 1089 int ret = 0;
1087 unsigned int i; 1090 unsigned int i;
@@ -1130,7 +1133,8 @@ int acpi_processor_set_throttling(struct acpi_processor *pr,
1130 arg.pr = pr; 1133 arg.pr = pr;
1131 arg.target_state = state; 1134 arg.target_state = state;
1132 arg.force = force; 1135 arg.force = force;
1133 ret = work_on_cpu(pr->id, acpi_processor_throttling_fn, &arg); 1136 ret = call_on_cpu(pr->id, acpi_processor_throttling_fn, &arg,
1137 direct);
1134 } else { 1138 } else {
1135 /* 1139 /*
1136 * When the T-state coordination is SW_ALL or HW_ALL, 1140 * When the T-state coordination is SW_ALL or HW_ALL,
@@ -1163,8 +1167,8 @@ int acpi_processor_set_throttling(struct acpi_processor *pr,
1163 arg.pr = match_pr; 1167 arg.pr = match_pr;
1164 arg.target_state = state; 1168 arg.target_state = state;
1165 arg.force = force; 1169 arg.force = force;
1166 ret = work_on_cpu(pr->id, acpi_processor_throttling_fn, 1170 ret = call_on_cpu(pr->id, acpi_processor_throttling_fn,
1167 &arg); 1171 &arg, direct);
1168 } 1172 }
1169 } 1173 }
1170 /* 1174 /*
@@ -1182,6 +1186,12 @@ int acpi_processor_set_throttling(struct acpi_processor *pr,
1182 return ret; 1186 return ret;
1183} 1187}
1184 1188
1189int acpi_processor_set_throttling(struct acpi_processor *pr, int state,
1190 bool force)
1191{
1192 return __acpi_processor_set_throttling(pr, state, force, false);
1193}
1194
1185int acpi_processor_get_throttling_info(struct acpi_processor *pr) 1195int acpi_processor_get_throttling_info(struct acpi_processor *pr)
1186{ 1196{
1187 int result = 0; 1197 int result = 0;