[CPUFREQ] Eliminate cpufreq_userspace scaling_setspeed deadlock
authorVenki Pallipadi <venkatesh.pallipadi@intel.com>
Fri, 26 Oct 2007 17:18:21 +0000 (10:18 -0700)
committerDave Jones <davej@redhat.com>
Thu, 7 Feb 2008 03:57:58 +0000 (22:57 -0500)
commit9e76988e9390a4ff4d171f690586d0c58186b47e
treee033aa977a66b4ea2dc01b0e846eb7f6f8134857
parentb25e75899e449456409cfa1a3b042257c03d4355
[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>
drivers/cpufreq/cpufreq.c
drivers/cpufreq/cpufreq_userspace.c
include/linux/cpufreq.h