diff options
author | Amerigo Wang <amwang@redhat.com> | 2010-03-04 03:23:46 -0500 |
---|---|---|
committer | Dave Jones <davej@redhat.com> | 2010-03-31 12:00:21 -0400 |
commit | 499bca9b6d3243f9278a1f5a22d00e67acdd844d (patch) | |
tree | 860ef8e80c4b68a10f06eb8a2fa19b43e608fade | |
parent | 2eaa9cfdf33b8d7fb7aff27792192e0019ae8fc6 (diff) |
[CPUFREQ] fix a lockdep warning
There is no need to do sysfs_remove_link() or kobject_put() etc.
when policy_rwsem_write is held, move them after releasing the lock.
This fixes the lockdep warning:
halt/4071 is trying to acquire lock:
(s_active){++++.+}, at: [<c0000000001ef868>] .sysfs_addrm_finish+0x58/0xc0
but task is already holding lock:
(&per_cpu(cpu_policy_rwsem, cpu)){+.+.+.}, at: [<c0000000004cd6ac>] .lock_policy_rwsem_write+0x84/0xf4
Reported-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: WANG Cong <amwang@redhat.com>
Cc: Johannes Berg <johannes@sipsolutions.net>
Cc: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
Signed-off-by: Dave Jones <davej@redhat.com>
-rw-r--r-- | drivers/cpufreq/cpufreq.c | 19 |
1 files changed, 14 insertions, 5 deletions
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 2d5d575e889d..75d293eeb3ee 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1113,6 +1113,8 @@ static int __cpufreq_remove_dev(struct sys_device *sys_dev) unsigned int cpu = sys_dev->id; unsigned long flags; struct cpufreq_policy *data; + struct kobject *kobj; + struct completion *cmp; #ifdef CONFIG_SMP struct sys_device *cpu_sys_dev; unsigned int j; @@ -1141,10 +1143,11 @@ static int __cpufreq_remove_dev(struct sys_device *sys_dev) dprintk("removing link\n"); cpumask_clear_cpu(cpu, data->cpus); spin_unlock_irqrestore(&cpufreq_driver_lock, flags); - sysfs_remove_link(&sys_dev->kobj, "cpufreq"); + kobj = &sys_dev->kobj; cpufreq_cpu_put(data); cpufreq_debug_enable_ratelimit(); unlock_policy_rwsem_write(cpu); + sysfs_remove_link(kobj, "cpufreq"); return 0; } #endif @@ -1181,7 +1184,10 @@ static int __cpufreq_remove_dev(struct sys_device *sys_dev) data->governor->name, CPUFREQ_NAME_LEN); #endif cpu_sys_dev = get_cpu_sysdev(j); - sysfs_remove_link(&cpu_sys_dev->kobj, "cpufreq"); + kobj = &cpu_sys_dev->kobj; + unlock_policy_rwsem_write(cpu); + sysfs_remove_link(kobj, "cpufreq"); + lock_policy_rwsem_write(cpu); cpufreq_cpu_put(data); } } @@ -1192,19 +1198,22 @@ static int __cpufreq_remove_dev(struct sys_device *sys_dev) if (cpufreq_driver->target) __cpufreq_governor(data, CPUFREQ_GOV_STOP); - kobject_put(&data->kobj); + kobj = &data->kobj; + cmp = &data->kobj_unregister; + unlock_policy_rwsem_write(cpu); + kobject_put(kobj); /* we need to make sure that the underlying kobj is actually * not referenced anymore by anybody before we proceed with * unloading. */ dprintk("waiting for dropping of refcount\n"); - wait_for_completion(&data->kobj_unregister); + wait_for_completion(cmp); dprintk("wait complete\n"); + lock_policy_rwsem_write(cpu); if (cpufreq_driver->exit) cpufreq_driver->exit(data); - unlock_policy_rwsem_write(cpu); free_cpumask_var(data->related_cpus); |