aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/cpufreq/cpufreq.c
diff options
context:
space:
mode:
authorVenki Pallipadi <venkatesh.pallipadi@intel.com>2007-10-26 13:18:21 -0400
committerDave Jones <davej@redhat.com>2008-02-06 22:57:58 -0500
commit9e76988e9390a4ff4d171f690586d0c58186b47e (patch)
treee033aa977a66b4ea2dc01b0e846eb7f6f8134857 /drivers/cpufreq/cpufreq.c
parentb25e75899e449456409cfa1a3b042257c03d4355 (diff)
[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 'drivers/cpufreq/cpufreq.c')
-rw-r--r--drivers/cpufreq/cpufreq.c27
1 files changed, 27 insertions, 0 deletions
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 613314851ecc..64926aa990db 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -601,6 +601,31 @@ static ssize_t show_affected_cpus (struct cpufreq_policy * policy, char *buf)
601 return i; 601 return i;
602} 602}
603 603
604static ssize_t store_scaling_setspeed(struct cpufreq_policy *policy,
605 const char *buf, size_t count)
606{
607 unsigned int freq = 0;
608 unsigned int ret;
609
610 if (!policy->governor->store_setspeed)
611 return -EINVAL;
612
613 ret = sscanf(buf, "%u", &freq);
614 if (ret != 1)
615 return -EINVAL;
616
617 policy->governor->store_setspeed(policy, freq);
618
619 return count;
620}
621
622static ssize_t show_scaling_setspeed(struct cpufreq_policy *policy, char *buf)
623{
624 if (!policy->governor->show_setspeed)
625 return sprintf(buf, "<unsupported>\n");
626
627 return policy->governor->show_setspeed(policy, buf);
628}
604 629
605#define define_one_ro(_name) \ 630#define define_one_ro(_name) \
606static struct freq_attr _name = \ 631static struct freq_attr _name = \
@@ -624,6 +649,7 @@ define_one_ro(affected_cpus);
624define_one_rw(scaling_min_freq); 649define_one_rw(scaling_min_freq);
625define_one_rw(scaling_max_freq); 650define_one_rw(scaling_max_freq);
626define_one_rw(scaling_governor); 651define_one_rw(scaling_governor);
652define_one_rw(scaling_setspeed);
627 653
628static struct attribute * default_attrs[] = { 654static struct attribute * default_attrs[] = {
629 &cpuinfo_min_freq.attr, 655 &cpuinfo_min_freq.attr,
@@ -634,6 +660,7 @@ static struct attribute * default_attrs[] = {
634 &scaling_governor.attr, 660 &scaling_governor.attr,
635 &scaling_driver.attr, 661 &scaling_driver.attr,
636 &scaling_available_governors.attr, 662 &scaling_available_governors.attr,
663 &scaling_setspeed.attr,
637 NULL 664 NULL
638}; 665};
639 666