]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
cpufreq: Rearrange locking in cpufreq_remove_dev()
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>
Wed, 11 May 2022 15:51:39 +0000 (17:51 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 16 Jun 2024 11:32:05 +0000 (13:32 +0200)
[ Upstream commit f339f3541701d824a0256ad4bf14c26ceb6d79c3 ]

Currently, cpufreq_remove_dev() invokes the ->exit() driver callback
without holding the policy rwsem which is inconsistent with what
happens if ->exit() is invoked directly from cpufreq_offline().

It also manipulates the real_cpus mask and removes the CPU device
symlink without holding the policy rwsem, but cpufreq_offline() holds
the rwsem around the modifications thereof.

For consistency, modify cpufreq_remove_dev() to hold the policy rwsem
until the ->exit() callback has been called (or it has been determined
that it is not necessary to call it).

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
Stable-dep-of: b8f85833c057 ("cpufreq: exit() callback is optional")
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/cpufreq/cpufreq.c

index dd1acb55fe71786c182a2c32579089d920980b65..cbdea4fa600ab3b0edfe0781e06b87c192ed214f 100644 (file)
@@ -1645,19 +1645,26 @@ static void cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif)
        if (!policy)
                return;
 
+       down_write(&policy->rwsem);
+
        if (cpu_online(cpu))
-               cpufreq_offline(cpu);
+               __cpufreq_offline(cpu, policy);
 
        cpumask_clear_cpu(cpu, policy->real_cpus);
        remove_cpu_dev_symlink(policy, dev);
 
-       if (cpumask_empty(policy->real_cpus)) {
-               /* We did light-weight exit earlier, do full tear down now */
-               if (cpufreq_driver->offline)
-                       cpufreq_driver->exit(policy);
-
-               cpufreq_policy_free(policy);
+       if (!cpumask_empty(policy->real_cpus)) {
+               up_write(&policy->rwsem);
+               return;
        }
+
+       /* We did light-weight exit earlier, do full tear down now */
+       if (cpufreq_driver->offline)
+               cpufreq_driver->exit(policy);
+
+       up_write(&policy->rwsem);
+
+       cpufreq_policy_free(policy);
 }
 
 /**