diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-04-04 17:26:40 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-04-04 17:26:40 -0400 |
| commit | 64ebe987311853ea857a244439de5b947a4b1b07 (patch) | |
| tree | b33ab6efd7f118e0f6ab5a6bcbd59ba31a313da5 /kernel | |
| parent | a5149bf3fed59b94207809704b5d06fec337a771 (diff) | |
| parent | c4772d192c70b61d52262b0db76f7abd8aeb51c6 (diff) | |
Merge tag 'pm-for-3.4-part-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
Pull more power management updates from Rafael Wysocki:
- Patch series that hopefully fixes races between the freezer and
request_firmware() and request_firmware_nowait() for good, with two
cleanups from Stephen Boyd on top.
- Runtime PM fix from Alan Stern preventing tasks from getting stuck
indefinitely in the runtime PM wait queue.
- Device PM QoS update from MyungJoo Ham introducing a new variant of
pm_qos_update_request() allowing the callers to specify a timeout.
* tag 'pm-for-3.4-part-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
PM / QoS: add pm_qos_update_request_timeout() API
firmware_class: Move request_firmware_nowait() to workqueues
firmware_class: Reorganize fw_create_instance()
PM / Sleep: Mitigate race between the freezer and request_firmware()
PM / Sleep: Move disabling of usermode helpers to the freezer
PM / Hibernate: Disable usermode helpers right before freezing tasks
firmware_class: Do not warn that system is not ready from async loads
firmware_class: Split _request_firmware() into three functions, v2
firmware_class: Rework usermodehelper check
PM / Runtime: don't forget to wake up waitqueue on failure
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/kmod.c | 117 | ||||
| -rw-r--r-- | kernel/power/hibernate.c | 18 | ||||
| -rw-r--r-- | kernel/power/process.c | 8 | ||||
| -rw-r--r-- | kernel/power/qos.c | 50 | ||||
| -rw-r--r-- | kernel/power/suspend.c | 7 | ||||
| -rw-r--r-- | kernel/power/user.c | 10 |
6 files changed, 148 insertions, 62 deletions
diff --git a/kernel/kmod.c b/kernel/kmod.c index 957a7aab8ebc..05698a7415fe 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c | |||
| @@ -322,7 +322,7 @@ static void __call_usermodehelper(struct work_struct *work) | |||
| 322 | * land has been frozen during a system-wide hibernation or suspend operation). | 322 | * land has been frozen during a system-wide hibernation or suspend operation). |
| 323 | * Should always be manipulated under umhelper_sem acquired for write. | 323 | * Should always be manipulated under umhelper_sem acquired for write. |
| 324 | */ | 324 | */ |
| 325 | static int usermodehelper_disabled = 1; | 325 | static enum umh_disable_depth usermodehelper_disabled = UMH_DISABLED; |
| 326 | 326 | ||
| 327 | /* Number of helpers running */ | 327 | /* Number of helpers running */ |
| 328 | static atomic_t running_helpers = ATOMIC_INIT(0); | 328 | static atomic_t running_helpers = ATOMIC_INIT(0); |
| @@ -334,32 +334,110 @@ static atomic_t running_helpers = ATOMIC_INIT(0); | |||
| 334 | static DECLARE_WAIT_QUEUE_HEAD(running_helpers_waitq); | 334 | static DECLARE_WAIT_QUEUE_HEAD(running_helpers_waitq); |
| 335 | 335 | ||
| 336 | /* | 336 | /* |
| 337 | * Used by usermodehelper_read_lock_wait() to wait for usermodehelper_disabled | ||
| 338 | * to become 'false'. | ||
| 339 | */ | ||
| 340 | static DECLARE_WAIT_QUEUE_HEAD(usermodehelper_disabled_waitq); | ||
| 341 | |||
| 342 | /* | ||
| 337 | * Time to wait for running_helpers to become zero before the setting of | 343 | * Time to wait for running_helpers to become zero before the setting of |
| 338 | * usermodehelper_disabled in usermodehelper_disable() fails | 344 | * usermodehelper_disabled in usermodehelper_disable() fails |
| 339 | */ | 345 | */ |
| 340 | #define RUNNING_HELPERS_TIMEOUT (5 * HZ) | 346 | #define RUNNING_HELPERS_TIMEOUT (5 * HZ) |
| 341 | 347 | ||
| 342 | void read_lock_usermodehelper(void) | 348 | int usermodehelper_read_trylock(void) |
| 343 | { | 349 | { |
| 350 | DEFINE_WAIT(wait); | ||
| 351 | int ret = 0; | ||
| 352 | |||
| 344 | down_read(&umhelper_sem); | 353 | down_read(&umhelper_sem); |
| 354 | for (;;) { | ||
| 355 | prepare_to_wait(&usermodehelper_disabled_waitq, &wait, | ||
| 356 | TASK_INTERRUPTIBLE); | ||
| 357 | if (!usermodehelper_disabled) | ||
| 358 | break; | ||
| 359 | |||
| 360 | if (usermodehelper_disabled == UMH_DISABLED) | ||
| 361 | ret = -EAGAIN; | ||
| 362 | |||
| 363 | up_read(&umhelper_sem); | ||
| 364 | |||
| 365 | if (ret) | ||
| 366 | break; | ||
| 367 | |||
| 368 | schedule(); | ||
| 369 | try_to_freeze(); | ||
| 370 | |||
| 371 | down_read(&umhelper_sem); | ||
| 372 | } | ||
| 373 | finish_wait(&usermodehelper_disabled_waitq, &wait); | ||
| 374 | return ret; | ||
| 375 | } | ||
| 376 | EXPORT_SYMBOL_GPL(usermodehelper_read_trylock); | ||
| 377 | |||
| 378 | long usermodehelper_read_lock_wait(long timeout) | ||
| 379 | { | ||
| 380 | DEFINE_WAIT(wait); | ||
| 381 | |||
| 382 | if (timeout < 0) | ||
| 383 | return -EINVAL; | ||
| 384 | |||
| 385 | down_read(&umhelper_sem); | ||
| 386 | for (;;) { | ||
| 387 | prepare_to_wait(&usermodehelper_disabled_waitq, &wait, | ||
| 388 | TASK_UNINTERRUPTIBLE); | ||
| 389 | if (!usermodehelper_disabled) | ||
| 390 | break; | ||
| 391 | |||
| 392 | up_read(&umhelper_sem); | ||
| 393 | |||
| 394 | timeout = schedule_timeout(timeout); | ||
| 395 | if (!timeout) | ||
| 396 | break; | ||
| 397 | |||
| 398 | down_read(&umhelper_sem); | ||
| 399 | } | ||
| 400 | finish_wait(&usermodehelper_disabled_waitq, &wait); | ||
| 401 | return timeout; | ||
| 345 | } | 402 | } |
| 346 | EXPORT_SYMBOL_GPL(read_lock_usermodehelper); | 403 | EXPORT_SYMBOL_GPL(usermodehelper_read_lock_wait); |
| 347 | 404 | ||
| 348 | void read_unlock_usermodehelper(void) | 405 | void usermodehelper_read_unlock(void) |
| 349 | { | 406 | { |
| 350 | up_read(&umhelper_sem); | 407 | up_read(&umhelper_sem); |
| 351 | } | 408 | } |
| 352 | EXPORT_SYMBOL_GPL(read_unlock_usermodehelper); | 409 | EXPORT_SYMBOL_GPL(usermodehelper_read_unlock); |
| 353 | 410 | ||
| 354 | /** | 411 | /** |
| 355 | * usermodehelper_disable - prevent new helpers from being started | 412 | * __usermodehelper_set_disable_depth - Modify usermodehelper_disabled. |
| 413 | * depth: New value to assign to usermodehelper_disabled. | ||
| 414 | * | ||
| 415 | * Change the value of usermodehelper_disabled (under umhelper_sem locked for | ||
| 416 | * writing) and wakeup tasks waiting for it to change. | ||
| 356 | */ | 417 | */ |
| 357 | int usermodehelper_disable(void) | 418 | void __usermodehelper_set_disable_depth(enum umh_disable_depth depth) |
| 419 | { | ||
| 420 | down_write(&umhelper_sem); | ||
| 421 | usermodehelper_disabled = depth; | ||
| 422 | wake_up(&usermodehelper_disabled_waitq); | ||
| 423 | up_write(&umhelper_sem); | ||
| 424 | } | ||
| 425 | |||
| 426 | /** | ||
| 427 | * __usermodehelper_disable - Prevent new helpers from being started. | ||
| 428 | * @depth: New value to assign to usermodehelper_disabled. | ||
| 429 | * | ||
| 430 | * Set usermodehelper_disabled to @depth and wait for running helpers to exit. | ||
| 431 | */ | ||
| 432 | int __usermodehelper_disable(enum umh_disable_depth depth) | ||
| 358 | { | 433 | { |
| 359 | long retval; | 434 | long retval; |
| 360 | 435 | ||
| 436 | if (!depth) | ||
| 437 | return -EINVAL; | ||
| 438 | |||
| 361 | down_write(&umhelper_sem); | 439 | down_write(&umhelper_sem); |
| 362 | usermodehelper_disabled = 1; | 440 | usermodehelper_disabled = depth; |
| 363 | up_write(&umhelper_sem); | 441 | up_write(&umhelper_sem); |
| 364 | 442 | ||
| 365 | /* | 443 | /* |
| @@ -374,31 +452,10 @@ int usermodehelper_disable(void) | |||
| 374 | if (retval) | 452 | if (retval) |
| 375 | return 0; | 453 | return 0; |
| 376 | 454 | ||
| 377 | down_write(&umhelper_sem); | 455 | __usermodehelper_set_disable_depth(UMH_ENABLED); |
| 378 | usermodehelper_disabled = 0; | ||
| 379 | up_write(&umhelper_sem); | ||
| 380 | return -EAGAIN; | 456 | return -EAGAIN; |
| 381 | } | 457 | } |
| 382 | 458 | ||
| 383 | /** | ||
| 384 | * usermodehelper_enable - allow new helpers to be started again | ||
| 385 | */ | ||
| 386 | void usermodehelper_enable(void) | ||
| 387 | { | ||
| 388 | down_write(&umhelper_sem); | ||
| 389 | usermodehelper_disabled = 0; | ||
| 390 | up_write(&umhelper_sem); | ||
| 391 | } | ||
| 392 | |||
| 393 | /** | ||
| 394 | * usermodehelper_is_disabled - check if new helpers are allowed to be started | ||
| 395 | */ | ||
| 396 | bool usermodehelper_is_disabled(void) | ||
| 397 | { | ||
| 398 | return usermodehelper_disabled; | ||
| 399 | } | ||
| 400 | EXPORT_SYMBOL_GPL(usermodehelper_is_disabled); | ||
| 401 | |||
| 402 | static void helper_lock(void) | 459 | static void helper_lock(void) |
| 403 | { | 460 | { |
| 404 | atomic_inc(&running_helpers); | 461 | atomic_inc(&running_helpers); |
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index 0a186cfde788..e09dfbfeecee 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c | |||
| @@ -16,7 +16,6 @@ | |||
| 16 | #include <linux/string.h> | 16 | #include <linux/string.h> |
| 17 | #include <linux/device.h> | 17 | #include <linux/device.h> |
| 18 | #include <linux/async.h> | 18 | #include <linux/async.h> |
| 19 | #include <linux/kmod.h> | ||
| 20 | #include <linux/delay.h> | 19 | #include <linux/delay.h> |
| 21 | #include <linux/fs.h> | 20 | #include <linux/fs.h> |
| 22 | #include <linux/mount.h> | 21 | #include <linux/mount.h> |
| @@ -611,14 +610,10 @@ int hibernate(void) | |||
| 611 | if (error) | 610 | if (error) |
| 612 | goto Exit; | 611 | goto Exit; |
| 613 | 612 | ||
