[CPUFREQ] Fix NULL pointer dereference regression in conservative governor
authorPallipadi, Venkatesh <venkatesh.pallipadi@intel.com>
Wed, 29 Jul 2009 20:36:10 +0000 (13:36 -0700)
committerDave Jones <davej@redhat.com>
Tue, 4 Aug 2009 18:32:10 +0000 (14:32 -0400)
Commit ee88415caf736b89500f16e0a545614541a45005
introduced this regression when it removed enable bit in cpu_dbs_info_s.
That added a possibility of dbs_cpufreq_notifier getting called for a
CPU that is not yet managed by conservative governor. That will happen
as the transition notifier is set as soon as one CPU switches to
conservative governor and other CPUs can get a NULL pointer dereference
without the enable bit check. Add the enable bit back again.

Reported-by: Lermytte Christophe <Christophe.Lermytte@thomson.net>
Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
Signed-off-by: Dave Jones <davej@redhat.com>
drivers/cpufreq/cpufreq_conservative.c

index 5749050..bdea7e2 100644 (file)
@@ -63,6 +63,7 @@ struct cpu_dbs_info_s {
        unsigned int down_skip;
        unsigned int requested_freq;
        int cpu;
+       unsigned int enable:1;
        /*
         * percpu mutex that serializes governor limit change with
         * do_dbs_timer invocation. We do not want do_dbs_timer to run
@@ -141,6 +142,9 @@ dbs_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
 
        struct cpufreq_policy *policy;
 
+       if (!this_dbs_info->enable)
+               return 0;
+
        policy = this_dbs_info->cur_policy;
 
        /*
@@ -497,6 +501,7 @@ static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info)
        int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
        delay -= jiffies % delay;
 
+       dbs_info->enable = 1;
        INIT_DELAYED_WORK_DEFERRABLE(&dbs_info->work, do_dbs_timer);
        queue_delayed_work_on(dbs_info->cpu, kconservative_wq, &dbs_info->work,
                                delay);
@@ -504,6 +509,7 @@ static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info)
 
 static inline void dbs_timer_exit(struct cpu_dbs_info_s *dbs_info)
 {
+       dbs_info->enable = 0;
        cancel_delayed_work_sync(&dbs_info->work);
 }