diff options
author | Venki Pallipadi | 2007-10-26 19:18:21 +0200 |
---|---|---|
committer | Dave Jones | 2008-02-07 04:57:58 +0100 |
commit | 9e76988e9390a4ff4d171f690586d0c58186b47e (patch) | |
tree | e033aa977a66b4ea2dc01b0e846eb7f6f8134857 /include/linux/cpufreq.h | |
parent | [CPUFREQ] gx-suspmod.c: use boot_cpu_data instead of current_cpu_data (diff) | |
download | kernel-qcow2-linux-9e76988e9390a4ff4d171f690586d0c58186b47e.tar.gz kernel-qcow2-linux-9e76988e9390a4ff4d171f690586d0c58186b47e.tar.xz kernel-qcow2-linux-9e76988e9390a4ff4d171f690586d0c58186b47e.zip |
[CPUFREQ] Eliminate cpufreq_userspace scaling_setspeed deadlock
Eliminate cpufreq_userspace scaling_setspeed deadlock.
Luming Yu recently uncovered yet another cpufreq related deadlock.
One thread that continuously switches the governors and the other thread that
repeatedly cats the contents of cpufreq directory causes both these threads to
go into a deadlock.
Detailed examination of the deadlock showed the exact flow before the deadlock
as:
Thread 1 Thread 2
________ ________
cats files under /sys/devices/.../cpufreq/
Set governor to userspace
Adds a new sysfs entry for
scaling_setspeed
cats files under /sys/devices/.../cpufreq/
Set governor to performance
Holds cpufreq_rw_sem in write
mode
Sends a STOP notify to
userspace governor
cat /sys/devices/.../cpufreq/scaling_setspeed
Gets a handle on the above sysfs entry with
sysfs_get_active
Blocks while trying to get cpufreq_rw_sem
in read mode
Remove a sysfs entry for
scaling_setspeed
Blocks on sysfs_deactivate
while waiting for earlier
get_active (on other thread)
to drain
At this point both threads go into deadlock and any other thread that tries to
do anything with sysfs cpufreq will also block.
There seems to be no easy way to avoid this deadlock as long as
cpufreq_userspace adds/removes the sysfs entry under same kobject as cpufreq.
Below patch moves scaling_setspeed to cpufreq.c, keeping it always and calling
back the governor on read/write. This is the cleanest fix I could think of,
even though adding two callbacks in governor structure just for this seems
unnecessary.
Note that the change makes scaling_setspeed under /sys/.../cpufreq permanent
and returns <unsupported> when governor is not userspace.
Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
Signed-off-by: Dave Jones <davej@redhat.com>
Diffstat (limited to 'include/linux/cpufreq.h')
-rw-r--r-- | include/linux/cpufreq.h | 4 |
1 files changed, 4 insertions, 0 deletions
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 23932d7741a9..ddd8652fc3f3 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -167,6 +167,10 @@ struct cpufreq_governor { char name[CPUFREQ_NAME_LEN]; int (*governor) (struct cpufreq_policy *policy, unsigned int event); + ssize_t (*show_setspeed) (struct cpufreq_policy *policy, + char *buf); + int (*store_setspeed) (struct cpufreq_policy *policy, + unsigned int freq); unsigned int max_transition_latency; /* HW must be able to switch to next freq faster than this value in nano secs or we will fallback to performance governor */ |