linux/drivers/cpufreq
Stephen Boyd a914443627 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_setspeed node eventually deadlocks with:

=============================================
[ INFO: possible recursive locking detected ]
3.4.0 #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 calls
kobject_get() via cpufreq_cpu_get() and is the last one to call
kobject_put() via cpufreq_cpu_put(). Sysfs code should not call
kobject_get() or kobject_put() directly (see the comment around
sysfs_schedule_callback() for more information).

Fix this deadlock by introducing two new functions:

	struct cpufreq_policy *cpufreq_cpu_get_sysfs(unsigned int cpu)
	void cpufreq_cpu_put_sysfs(struct cpufreq_policy *data)

which do the same thing as cpufreq_cpu_{get,put}() but don't call
kobject functions.

To easily trigger this deadlock you can insert an msleep() with a
reasonably large value right after the fail label at the bottom
of the store() function in cpufreq.c and then write
scaling_setspeed in one task and offline the cpu in another. The
first task will hang and be detected by the hung task detector.

Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
2012-07-20 21:39:25 +02:00
..
acpi-cpufreq.c [CPUFREQ] Handle CPUs with different capabilities in acpi-cpufreq 2011-07-13 18:29:49 -04:00
cpufreq_conservative.c Merge branch 'sched/core' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip into cputime-tip 2011-12-19 19:23:15 +01:00
cpufreq_ondemand.c [CPUFREQ] CPUfreq ondemand: update sampling rate without waiting for next sampling 2012-02-29 22:24:40 -05:00
cpufreq_performance.c [CPUFREQ] use dynamic debug instead of custom infrastructure 2011-05-04 11:50:57 -04:00
cpufreq_powersave.c [CPUFREQ] use dynamic debug instead of custom infrastructure 2011-05-04 11:50:57 -04:00
cpufreq_stats.c Merge branch 'driver-core-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core 2012-01-07 12:03:30 -08:00
cpufreq_userspace.c [CPUFREQ] cpufreq:userspace: fix cpu_cur_freq updation 2012-01-06 10:10:53 -05:00
cpufreq-nforce2.c cpufreq: Add support for x86 cpuinfo auto loading v4 2012-01-26 16:49:06 -08:00
cpufreq.c cpufreq: Fix sysfs deadlock with concurrent hotplug/frequency switch 2012-07-20 21:39:25 +02:00
db8500-cpufreq.c ARM: ux500: core U9540 support 2012-05-02 00:25:13 +02:00
e_powersaver.c cpufreq: Add support for x86 cpuinfo auto loading v4 2012-01-26 16:49:06 -08:00
elanfreq.c cpufreq: Add support for x86 cpuinfo auto loading v4 2012-01-26 16:49:06 -08:00
exynos4x12-cpufreq.c EXYNOS4X12: Add support cpufreq for EXYNOS4X12 2012-03-14 14:39:47 -04:00
exynos4210-cpufreq.c [CPUFREQ] EXYNOS4210: update the name of EXYNOS clock register 2012-02-29 22:24:38 -05:00
exynos5250-cpufreq.c EXYNOS5250: Add support cpufreq for EXYNOS5250 2012-03-14 14:39:50 -04:00
exynos-cpufreq.c EXYNOS: bugfix on retrieving old_index from freqs.old 2012-07-20 11:58:34 +02:00
freq_table.c [CPUFREQ] use dynamic debug instead of custom infrastructure 2011-05-04 11:50:57 -04:00
gx-suspmod.c cpufreq/gx: Fix the compile error 2012-02-02 15:32:12 -08:00
Kconfig Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc 2011-07-25 22:59:39 -07:00
Kconfig.arm cpufreq: OMAP: fix build errors: depends on ARCH_OMAP2PLUS 2012-04-13 17:57:40 -07:00
Kconfig.powerpc powerpc/cpufreq: Add cpufreq driver for Momentum Maple boards 2011-07-19 15:13:04 +10:00
Kconfig.x86 Merge branch 'x86-cpu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip 2011-05-19 17:55:12 -07:00
longhaul.c cpufreq: Add support for x86 cpuinfo auto loading v4 2012-01-26 16:49:06 -08:00
longhaul.h [CPUFREQ] Move x86 drivers to drivers/cpufreq/ 2011-05-19 18:51:07 -04:00
longrun.c cpufreq: Add support for x86 cpuinfo auto loading v4 2012-01-26 16:49:06 -08:00
Makefile Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/davej/cpufreq 2012-03-23 17:56:39 -07:00
maple-cpufreq.c powerpc/cpufreq: Add cpufreq driver for Momentum Maple boards 2011-07-19 15:13:04 +10:00
mperf.c [CPUFREQ] Move x86 drivers to drivers/cpufreq/ 2011-05-19 18:51:07 -04:00
mperf.h [CPUFREQ] Move x86 drivers to drivers/cpufreq/ 2011-05-19 18:51:07 -04:00
omap-cpufreq.c Disintegrate and delete asm/system.h 2012-03-28 15:58:21 -07:00
p4-clockmod.c cpufreq: Add support for x86 cpuinfo auto loading v4 2012-01-26 16:49:06 -08:00
pcc-cpufreq.c drivers/cpufreq/pcc-cpufreq.c: avoid NULL pointer dereference 2011-09-14 18:09:38 -07:00
powernow-k6.c powernow-k6: Really enable auto-loading 2012-02-13 15:26:03 -08:00
powernow-k7.c Remove all #inclusions of asm/system.h 2012-03-28 18:30:03 +01:00
powernow-k7.h [CPUFREQ] Move x86 drivers to drivers/cpufreq/ 2011-05-19 18:51:07 -04:00
powernow-k8.c cpufreq: Add support for x86 cpuinfo auto loading v4 2012-01-26 16:49:06 -08:00
powernow-k8.h [CPUFREQ] Move x86 drivers to drivers/cpufreq/ 2011-05-19 18:51:07 -04:00
s3c64xx-cpufreq.c [CPUFREQ] s3c64xx: Fix mis-cherry pick of VDDINT 2012-02-29 22:24:38 -05:00
s3c2416-cpufreq.c [CPUFREQ] Add S3C2416/S3C2450 cpufreq driver 2012-02-29 22:24:39 -05:00
s5pv210-cpufreq.c [CPUFREQ] s5pv210: make needlessly global symbols static 2011-07-13 18:30:00 -04:00
sc520_freq.c cpufreq: Add support for x86 cpuinfo auto loading v4 2012-01-26 16:49:06 -08:00
speedstep-centrino.c cpufreq: Add support for x86 cpuinfo auto loading v4 2012-01-26 16:49:06 -08:00
speedstep-ich.c cpufreq: Add support for x86 cpuinfo auto loading v4 2012-01-26 16:49:06 -08:00
speedstep-lib.c cpufreq: Add support for x86 cpuinfo auto loading v4 2012-01-26 16:49:06 -08:00
speedstep-lib.h [CPUFREQ] Move x86 drivers to drivers/cpufreq/ 2011-05-19 18:51:07 -04:00
speedstep-smi.c cpufreq: Add support for x86 cpuinfo auto loading v4 2012-01-26 16:49:06 -08:00