]> git.proxmox.com Git - mirror_ubuntu-kernels.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)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Thu, 12 May 2022 15:11:57 +0000 (17:11 +0200)
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>
drivers/cpufreq/cpufreq.c

index 9664a86766c94a736c5c2576d8409dc569b817ff..1f6667ce43bdd304f9bfb0cc2720c43a7390d1c1 100644 (file)
@@ -1660,18 +1660,25 @@ 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);
 
        remove_cpu_dev_symlink(policy, cpu, 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);
 }
 
 /**