Skip to content

Commit c26b4bc

Browse files
bebarinoShruthi Krishna
authored andcommitted
cpufreq: Fix sysfs deadlock with concurrent hotplug/frequency switch
Running one program that continuously hotplugs and replugs a cpu concurrently with another program that continuously writes to the scaling_set_speed node eventually deadlocks with: ============================================= [ INFO: possible recursive locking detected ] 3.4.0 torvalds#37 Tainted: G W --------------------------------------------- filemonkey/122 is trying to acquire lock: (s_active#13){++++.+}, at: [<c01a3d28>] sysfs_remove_dir+0x9c/0xb4 but task is already holding lock: (s_active#13){++++.+}, at: [<c01a22f0>] sysfs_write_file+0xe8/0x140 other info that might help us debug this: Possible unsafe locking scenario: CPU0 ---- lock(s_active#13); lock(s_active#13); *** DEADLOCK *** May be due to missing lock nesting notation 2 locks held by filemonkey/122: #0: (&buffer->mutex){+.+.+.}, at: [<c01a2230>] sysfs_write_file+0x28/0x140 #1: (s_active#13){++++.+}, at: [<c01a22f0>] sysfs_write_file+0xe8/0x140 stack backtrace: [<c0014fcc>] (unwind_backtrace+0x0/0x120) from [<c00ca600>] (validate_chain+0x6f8/0x1054) [<c00ca600>] (validate_chain+0x6f8/0x1054) from [<c00cb778>] (__lock_acquire+0x81c/0x8d8) [<c00cb778>] (__lock_acquire+0x81c/0x8d8) from [<c00cb9c0>] (lock_acquire+0x18c/0x1e8) [<c00cb9c0>] (lock_acquire+0x18c/0x1e8) from [<c01a3ba8>] (sysfs_addrm_finish+0xd0/0x180) [<c01a3ba8>] (sysfs_addrm_finish+0xd0/0x180) from [<c01a3d28>] (sysfs_remove_dir+0x9c/0xb4) [<c01a3d28>] (sysfs_remove_dir+0x9c/0xb4) from [<c02d0e5c>] (kobject_del+0x10/0x38) [<c02d0e5c>] (kobject_del+0x10/0x38) from [<c02d0f74>] (kobject_release+0xf0/0x194) [<c02d0f74>] (kobject_release+0xf0/0x194) from [<c0565a98>] (cpufreq_cpu_put+0xc/0x24) [<c0565a98>] (cpufreq_cpu_put+0xc/0x24) from [<c05683f0>] (store+0x6c/0x74) [<c05683f0>] (store+0x6c/0x74) from [<c01a2314>] (sysfs_write_file+0x10c/0x140) [<c01a2314>] (sysfs_write_file+0x10c/0x140) from [<c014af44>] (vfs_write+0xb0/0x128) [<c014af44>] (vfs_write+0xb0/0x128) from [<c014b06c>] (sys_write+0x3c/0x68) [<c014b06c>] (sys_write+0x3c/0x68) from [<c000e0e0>] (ret_fast_syscall+0x0/0x3c) This is because store() in cpufreq.c indirectly grabs a kobject with kobject_get() and is the last one to call kobject_put() indirectly via cpufreq_cpu_put(). Fix this deadlock by introducing two new functions, cpufreq_cpu_get_sysfs() and cpufreq_cpu_put_sysfs() which do the same thing as cpufreq_cpu_{get,put}() but don't grab the kobject. CRs-fixed: 366560 Signed-off-by: Ramakrishna Prasad N <[email protected]> (cherry picked from commit ddda0cf) Change-Id: I6ac89789e89099cff315d7a02de216423376b7f7 Signed-off-by: Shruthi Krishna <[email protected]>
1 parent 4a9bceb commit c26b4bc

File tree

1 file changed

+27
-8
lines changed

1 file changed

+27
-8
lines changed

drivers/cpufreq/cpufreq.c

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ pure_initcall(init_cpufreq_transition_notifier_list);
133133
static LIST_HEAD(cpufreq_governor_list);
134134
static DEFINE_MUTEX(cpufreq_governor_mutex);
135135

136-
struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu)
136+
static struct cpufreq_policy *__cpufreq_cpu_get(unsigned int cpu, int sysfs)
137137
{
138138
struct cpufreq_policy *data;
139139
unsigned long flags;
@@ -157,7 +157,7 @@ struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu)
157157
if (!data)
158158
goto err_out_put_module;
159159

160-
if (!kobject_get(&data->kobj))
160+
if (!sysfs && !kobject_get(&data->kobj))
161161
goto err_out_put_module;
162162

163163
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
@@ -170,16 +170,35 @@ struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu)
170170
err_out:
171171
return NULL;
172172
}
173+
174+
struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu)
175+
{
176+
return __cpufreq_cpu_get(cpu, 0);
177+
}
173178
EXPORT_SYMBOL_GPL(cpufreq_cpu_get);
174179

180+
static struct cpufreq_policy *cpufreq_cpu_get_sysfs(unsigned int cpu)
181+
{
182+
return __cpufreq_cpu_get(cpu, 1);
183+
}
175184

176-
void cpufreq_cpu_put(struct cpufreq_policy *data)
185+
static void __cpufreq_cpu_put(struct cpufreq_policy *data, int sysfs)
177186
{
178-
kobject_put(&data->kobj);
187+
if (!sysfs)
188+
kobject_put(&data->kobj);
179189
module_put(cpufreq_driver->owner);
180190
}
191+
192+
void cpufreq_cpu_put(struct cpufreq_policy *data)
193+
{
194+
__cpufreq_cpu_put(data, 0);
195+
}
181196
EXPORT_SYMBOL_GPL(cpufreq_cpu_put);
182197

198+
static void cpufreq_cpu_put_sysfs(struct cpufreq_policy *data)
199+
{
200+
__cpufreq_cpu_put(data, 1);
201+
}
183202

184203
/*********************************************************************
185204
* EXTERNALLY AFFECTING FREQUENCY CHANGES *
@@ -613,7 +632,7 @@ static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf)
613632
struct cpufreq_policy *policy = to_policy(kobj);
614633
struct freq_attr *fattr = to_attr(attr);
615634
ssize_t ret = -EINVAL;
616-
policy = cpufreq_cpu_get(policy->cpu);
635+
policy = cpufreq_cpu_get_sysfs(policy->cpu);
617636
if (!policy)
618637
goto no_policy;
619638

@@ -627,7 +646,7 @@ static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf)
627646

628647
unlock_policy_rwsem_read(policy->cpu);
629648
fail:
630-
cpufreq_cpu_put(policy);
649+
cpufreq_cpu_put_sysfs(policy);
631650
no_policy:
632651
return ret;
633652
}
@@ -638,7 +657,7 @@ static ssize_t store(struct kobject *kobj, struct attribute *attr,
638657
struct cpufreq_policy *policy = to_policy(kobj);
639658
struct freq_attr *fattr = to_attr(attr);
640659
ssize_t ret = -EINVAL;
641-
policy = cpufreq_cpu_get(policy->cpu);
660+
policy = cpufreq_cpu_get_sysfs(policy->cpu);
642661
if (!policy)
643662
goto no_policy;
644663

@@ -652,7 +671,7 @@ static ssize_t store(struct kobject *kobj, struct attribute *attr,
652671

653672
unlock_policy_rwsem_write(policy->cpu);
654673
fail:
655-
cpufreq_cpu_put(policy);
674+
cpufreq_cpu_put_sysfs(policy);
656675
no_policy:
657676
return ret;
658677
}

0 commit comments

Comments
 (0)