linux/kernel/power
Rafael J. Wysocki 247bc03742 PM / Sleep: Mitigate race between the freezer and request_firmware()
There is a race condition between the freezer and request_firmware()
such that if request_firmware() is run on one CPU and
freeze_processes() is run on another CPU and usermodehelper_disable()
called by it succeeds to grab umhelper_sem for writing before
usermodehelper_read_trylock() called from request_firmware()
acquires it for reading, the request_firmware() will fail and
trigger a WARN_ON() complaining that it was called at a wrong time.
However, in fact, it wasn't called at a wrong time and
freeze_processes() simply happened to be executed simultaneously.

To avoid this race, at least in some cases, modify
usermodehelper_read_trylock() so that it doesn't fail if the
freezing of tasks has just started and hasn't been completed yet.
Instead, during the freezing of tasks, it will try to freeze the
task that has called it so that it can wait until user space is
thawed without triggering the scary warning.

For this purpose, change usermodehelper_disabled so that it can
take three different values, UMH_ENABLED (0), UMH_FREEZING and
UMH_DISABLED.  The first one means that usermode helpers are
enabled, the last one means "hard disable" (i.e. the system is not
ready for usermode helpers to be used) and the second one
is reserved for the freezer.  Namely, when freeze_processes() is
started, it sets usermodehelper_disabled to UMH_FREEZING which
tells usermodehelper_read_trylock() that it shouldn't fail just
yet and should call try_to_freeze() if woken up and cannot
return immediately.  This way all freezable tasks that happen
to call request_firmware() right before freeze_processes() is
started and lose the race for umhelper_sem with it will be
frozen and will sleep until thaw_processes() unsets
usermodehelper_disabled.  [For the non-freezable callers of
request_firmware() the race for umhelper_sem against
freeze_processes() is unfortunately unavoidable.]

Reported-by: Stephen Boyd <sboyd@codeaurora.org>
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: stable@vger.kernel.org
2012-03-28 23:30:28 +02:00
..
block_io.c block: kill off REQ_UNPLUG 2011-03-10 08:52:27 +01:00
console.c PM / VT: Cleanup #if defined uglyness and fix compile error 2011-10-16 23:28:51 +02:00
hibernate.c PM / Sleep: Move disabling of usermode helpers to the freezer 2012-03-28 23:30:21 +02:00
Kconfig Merge branch 'devel-stable' of http://ftp.arm.linux.org.uk/pub/linux/arm/kernel/git-cur/linux-2.6-arm 2011-10-28 12:02:27 -07:00
main.c PM / Sleep: Make enter_state() in kernel/power/suspend.c static 2012-02-17 23:36:10 +01:00
Makefile PM / QoS: unconditionally build the feature 2012-02-13 16:23:42 +01:00
power.h PM / Sleep: Make enter_state() in kernel/power/suspend.c static 2012-02-17 23:36:10 +01:00
poweroff.c Input: sysrq - drop tty argument from sysrq ops handlers 2010-08-19 22:07:06 -07:00
process.c PM / Sleep: Mitigate race between the freezer and request_firmware() 2012-03-28 23:30:28 +02:00
qos.c PM / QoS: Simplify PM QoS expansion/merge 2012-01-29 20:39:25 +01:00
snapshot.c Power management updates for 3.4 2012-03-21 10:15:51 -07:00
suspend_test.c PM: Make warning in suspend_test_finish() less likely to happen 2009-10-22 08:23:45 +09:00
suspend.c PM / Sleep: Move disabling of usermode helpers to the freezer 2012-03-28 23:30:21 +02:00
swap.c PM / Hibernate: Drop the check of swap space size for compressed image 2012-01-14 00:41:37 +01:00
user.c PM / Sleep: Move disabling of usermode helpers to the freezer 2012-03-28 23:30:21 +02:00