aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLianwei Wang2013-01-07 00:15:51 -0600
committerArve Hjønnevåg2013-02-19 19:56:15 -0600
commitab946e523af3e630c4433939544465e725769857 (patch)
treeda6eda4dc35d9b92a377a64762026221f2031223 /drivers
parent2f9264b36db37f3668254443be106d4417052d7a (diff)
downloadkernel-common-ab946e523af3e630c4433939544465e725769857.tar.gz
kernel-common-ab946e523af3e630c4433939544465e725769857.tar.xz
kernel-common-ab946e523af3e630c4433939544465e725769857.zip
cpufreq: interactive: fix race on governor start/stop
There is race condition when both two cpu do CPUFREQ_GOV_STOP and one cpu do CPUFREQ_GOV_START soon. The sysfs_remove_group is not done yet on one cpu, but sysfs_create_group is called on another cpu, which cause governor start failed and then kernel panic in timer callback because the policy and cpu mask are all kfree in cpufreq driver. Replace atomic with mutex to lock the whole START/STOP sequence. Change-Id: I3762b3d44315ae021b8275aca84f5ea9147cc540 Signed-off-by: Lianwei Wang <a22439@motorola.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/cpufreq/cpufreq_interactive.c21
1 files changed, 17 insertions, 4 deletions
diff --git a/drivers/cpufreq/cpufreq_interactive.c b/drivers/cpufreq/cpufreq_interactive.c
index c70ebf53415..7d1952c5cb1 100644
--- a/drivers/cpufreq/cpufreq_interactive.c
+++ b/drivers/cpufreq/cpufreq_interactive.c
@@ -34,7 +34,7 @@
34#define CREATE_TRACE_POINTS 34#define CREATE_TRACE_POINTS
35#include <trace/events/cpufreq_interactive.h> 35#include <trace/events/cpufreq_interactive.h>
36 36
37static atomic_t active_count = ATOMIC_INIT(0); 37static int active_count;
38 38
39struct cpufreq_interactive_cpuinfo { 39struct cpufreq_interactive_cpuinfo {
40 struct timer_list cpu_timer; 40 struct timer_list cpu_timer;
@@ -60,6 +60,7 @@ static DEFINE_PER_CPU(struct cpufreq_interactive_cpuinfo, cpuinfo);
60static struct task_struct *speedchange_task; 60static struct task_struct *speedchange_task;
61static cpumask_t speedchange_cpumask; 61static cpumask_t speedchange_cpumask;
62static spinlock_t speedchange_cpumask_lock; 62static spinlock_t speedchange_cpumask_lock;
63static struct mutex gov_lock;
63 64
64/* Hi speed to bump to from lo speed when load burst (default max) */ 65/* Hi speed to bump to from lo speed when load burst (default max) */
65static unsigned int hispeed_freq; 66static unsigned int hispeed_freq;
@@ -913,6 +914,8 @@ static int cpufreq_governor_interactive(struct cpufreq_policy *policy,
913 if (!cpu_online(policy->cpu)) 914 if (!cpu_online(policy->cpu))
914 return -EINVAL; 915 return -EINVAL;
915 916
917 mutex_lock(&gov_lock);
918
916 freq_table = 919 freq_table =
917 cpufreq_frequency_get_table(policy->cpu); 920 cpufreq_frequency_get_table(policy->cpu);
918 if (!hispeed_freq) 921 if (!hispeed_freq)
@@ -947,20 +950,26 @@ static int cpufreq_governor_interactive(struct cpufreq_policy *policy,
947 * Do not register the idle hook and create sysfs 950 * Do not register the idle hook and create sysfs
948 * entries if we have already done so. 951 * entries if we have already done so.
949 */ 952 */
950 if (atomic_inc_return(&active_count) > 1) 953 if (++active_count > 1) {
954 mutex_unlock(&gov_lock);
951 return 0; 955 return 0;
956 }
952 957
953 rc = sysfs_create_group(cpufreq_global_kobject, 958 rc = sysfs_create_group(cpufreq_global_kobject,
954 &interactive_attr_group); 959 &interactive_attr_group);
955 if (rc) 960 if (rc) {
961 mutex_unlock(&gov_lock);
956 return rc; 962 return rc;
963 }
957 964
958 idle_notifier_register(&cpufreq_interactive_idle_nb); 965 idle_notifier_register(&cpufreq_interactive_idle_nb);
959 cpufreq_register_notifier( 966 cpufreq_register_notifier(
960 &cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); 967 &cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER);
968 mutex_unlock(&gov_lock);
961 break; 969 break;
962 970
963 case CPUFREQ_GOV_STOP: 971 case CPUFREQ_GOV_STOP:
972 mutex_lock(&gov_lock);
964 for_each_cpu(j, policy->cpus) { 973 for_each_cpu(j, policy->cpus) {
965 pcpu = &per_cpu(cpuinfo, j); 974 pcpu = &per_cpu(cpuinfo, j);
966 down_write(&pcpu->enable_sem); 975 down_write(&pcpu->enable_sem);
@@ -970,14 +979,17 @@ static int cpufreq_governor_interactive(struct cpufreq_policy *policy,
970 up_write(&pcpu->enable_sem); 979 up_write(&pcpu->enable_sem);
971 } 980 }
972 981
973 if (atomic_dec_return(&active_count) > 0) 982 if (--active_count > 0) {
983 mutex_unlock(&gov_lock);
974 return 0; 984 return 0;
985 }
975 986
976 cpufreq_unregister_notifier( 987 cpufreq_unregister_notifier(
977 &cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); 988 &cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER);
978 idle_notifier_unregister(&cpufreq_interactive_idle_nb); 989 idle_notifier_unregister(&cpufreq_interactive_idle_nb);
979 sysfs_remove_group(cpufreq_global_kobject, 990 sysfs_remove_group(cpufreq_global_kobject,
980 &interactive_attr_group); 991 &interactive_attr_group);
992 mutex_unlock(&gov_lock);
981 993
982 break; 994 break;
983 995
@@ -1017,6 +1029,7 @@ static int __init cpufreq_interactive_init(void)
1017 1029
1018 spin_lock_init(&target_loads_lock); 1030 spin_lock_init(&target_loads_lock);
1019 spin_lock_init(&speedchange_cpumask_lock); 1031 spin_lock_init(&speedchange_cpumask_lock);
1032 mutex_init(&gov_lock);
1020 speedchange_task = 1033 speedchange_task =
1021 kthread_create(cpufreq_interactive_speedchange_task, NULL, 1034 kthread_create(cpufreq_interactive_speedchange_task, NULL,
1022 "cfinteractive"); 1035 "cfinteractive");