cpufreq: Fix broken usage of governor->owner's refcount
authorViresh Kumar <viresh.kumar@linaro.org>
Tue, 6 Aug 2013 17:23:10 +0000 (22:53 +0530)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Sat, 10 Aug 2013 01:24:47 +0000 (03:24 +0200)
The cpufreq governor owner refcount usage is broken.  We should only
increment that refcount when a CPUFREQ_GOV_POLICY_INIT event has come
and it should only be decremented if CPUFREQ_GOV_POLICY_EXIT has come.

Currently, there can be situations where the governor is in use, but
we have allowed it to be unloaded which may result in undefined
behavior.  Let's fix it.

Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
drivers/cpufreq/cpufreq.c

index 37af929746afe72e7f3fad2245f2fa64c11a4bb4..f149e14f77c7a0405ec333f9a684cd5cb2809810 100644 (file)
@@ -1709,8 +1709,9 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
                }
        }
 
-       if (!try_module_get(policy->governor->owner))
-               return -EINVAL;
+       if (event == CPUFREQ_GOV_POLICY_INIT)
+               if (!try_module_get(policy->governor->owner))
+                       return -EINVAL;
 
        pr_debug("__cpufreq_governor for CPU %u, event %u\n",
                                                policy->cpu, event);
@@ -1719,6 +1720,8 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
        if ((!policy->governor_enabled && (event == CPUFREQ_GOV_STOP)) ||
            (policy->governor_enabled && (event == CPUFREQ_GOV_START))) {
                mutex_unlock(&cpufreq_governor_lock);
+               if (event == CPUFREQ_GOV_POLICY_INIT)
+                       module_put(policy->governor->owner);
                return -EBUSY;
        }
 
@@ -1746,11 +1749,8 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
                mutex_unlock(&cpufreq_governor_lock);
        }
 
-       /* we keep one module reference alive for
-                       each CPU governed by this CPU */
-       if ((event != CPUFREQ_GOV_START) || ret)
-               module_put(policy->governor->owner);
-       if ((event == CPUFREQ_GOV_STOP) && !ret)
+       if (((event == CPUFREQ_GOV_POLICY_INIT) && ret) ||
+                       ((event == CPUFREQ_GOV_POLICY_EXIT) && !ret))
                module_put(policy->governor->owner);
 
        return ret;