Cpufreq: protect policy & module refcount
Puneet Saxena [Wed, 14 Aug 2013 15:34:00 +0000 (20:34 +0530)]
percpu policy pointer needs to be updated with "cpufreq_cpu_data"
synchronously.

This will avoid different virtue of policy pointer of an
online cpu.

It protects ref counting while releasing policy object

Bug 1327428

Change-Id: I817a78c2ead921546f97e4af8943fb5c4ffcfcc6
Signed-off-by: Puneet Saxena <puneets@nvidia.com>
Reviewed-on: http://git-master/r/261609
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Peter Boonstoppel <pboonstoppel@nvidia.com>
Reviewed-by: Sachin Nikam <snikam@nvidia.com>

drivers/cpufreq/cpufreq.c

index aa4bbb9..774b678 100644 (file)
@@ -668,6 +668,7 @@ static ssize_t store(struct kobject *kobj, struct attribute *attr,
                goto no_policy;
 
        policy = freqobj->cpu_policy;
+
        policy = cpufreq_cpu_get(policy->cpu);
        if (!policy)
                goto no_policy;
@@ -807,6 +808,7 @@ static int cpufreq_add_dev_policy(unsigned int cpu,
                        spin_lock_irqsave(&cpufreq_driver_lock, flags);
                        cpumask_copy(managed_policy->cpus, policy->cpus);
                        per_cpu(cpufreq_cpu_data, cpu) = managed_policy;
+                       cpu_sysnode[cpu].cpu_policy = managed_policy;
                        spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
 
                        pr_debug("CPU already managed, adding link\n");
@@ -877,6 +879,7 @@ static int cpufreq_add_dev_interface(unsigned int cpu,
                if (!cpu_online(j))
                        continue;
                per_cpu(cpufreq_cpu_data, j) = policy;
+               cpu_sysnode[j].cpu_policy = policy;
                per_cpu(cpufreq_policy_cpu, j) = policy->cpu;
        }
        spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
@@ -997,7 +1000,7 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
        blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
                                     CPUFREQ_START, policy);
 
-       policy->kobj = &cpu_sysnode[cpu].cpu_kobj;
+       policy->kobj = &cpu_sysnode[policy->cpu].cpu_kobj;
 
        ret = cpufreq_add_dev_policy(cpu, policy, dev);
        if (ret) {
@@ -1023,8 +1026,10 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
 
 err_out_unregister:
        spin_lock_irqsave(&cpufreq_driver_lock, flags);
-       for_each_cpu(j, policy->cpus)
+       for_each_cpu(j, policy->cpus) {
                per_cpu(cpufreq_cpu_data, j) = NULL;
+               cpu_sysnode[j].cpu_policy = NULL;
+       }
        spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
        kobject_put(policy->kobj);
 err_unlock_policy:
@@ -1081,7 +1086,6 @@ static int __cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif
                cpumask_clear_cpu(cpu, data->cpus);
                spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
                kobj = &dev->kobj;
-               cpufreq_cpu_put(data);
                unlock_policy_rwsem_write(cpu);
                sysfs_remove_link(kobj, "cpufreq");
                return 0;
@@ -1105,6 +1109,7 @@ static int __cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif
                        if (j == cpu)
                                continue;
                        per_cpu(cpufreq_cpu_data, j) = NULL;
+                       cpu_sysnode[j].cpu_policy = NULL;
                }
        }
 
@@ -1124,7 +1129,6 @@ static int __cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif
                        unlock_policy_rwsem_write(cpu);
                        sysfs_remove_link(kobj, "cpufreq");
                        lock_policy_rwsem_write(cpu);
-                       cpufreq_cpu_put(data);
                }
        }
 #else