diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-04-29 18:00:44 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-04-29 18:00:44 -0400 |
| commit | 6cfdd02b886aac866098f33262d409565f101ce0 (patch) | |
| tree | 178b5abf48eb98b9ef0a29d865d7214798ed8b57 | |
| parent | 64f371bc3107e69efce563a3d0f0e6880de0d537 (diff) | |
| parent | 26e0f90fded422f309deb6169dfbccb204435698 (diff) | |
Merge tag 'pm-for-3.4-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
Pull power management fixes from Rafael J. Wysocki:
"Fix for an issue causing hibernation to hang on systems with highmem
(that practically means i386) due to broken memory management (bug
introduced in 3.2, so -stable material) and PM documentation update
making the freezer documentation follow the code again after some
recent updates."
* tag 'pm-for-3.4-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
PM / Freezer / Docs: Update documentation about freezing of tasks
PM / Hibernate: fix the number of pages used for hibernate/thaw buffering
| -rw-r--r-- | Documentation/power/freezing-of-tasks.txt | 37 | ||||
| -rw-r--r-- | kernel/power/swap.c | 28 |
2 files changed, 41 insertions, 24 deletions
diff --git a/Documentation/power/freezing-of-tasks.txt b/Documentation/power/freezing-of-tasks.txt index ec715cd78fbb..6ec291ea1c78 100644 --- a/Documentation/power/freezing-of-tasks.txt +++ b/Documentation/power/freezing-of-tasks.txt | |||
| @@ -9,7 +9,7 @@ architectures). | |||
| 9 | 9 | ||
| 10 | II. How does it work? | 10 | II. How does it work? |
| 11 | 11 | ||
| 12 | There are four per-task flags used for that, PF_NOFREEZE, PF_FROZEN, TIF_FREEZE | 12 | There are three per-task flags used for that, PF_NOFREEZE, PF_FROZEN |
| 13 | and PF_FREEZER_SKIP (the last one is auxiliary). The tasks that have | 13 | and PF_FREEZER_SKIP (the last one is auxiliary). The tasks that have |
| 14 | PF_NOFREEZE unset (all user space processes and some kernel threads) are | 14 | PF_NOFREEZE unset (all user space processes and some kernel threads) are |
| 15 | regarded as 'freezable' and treated in a special way before the system enters a | 15 | regarded as 'freezable' and treated in a special way before the system enters a |
| @@ -17,30 +17,31 @@ suspend state as well as before a hibernation image is created (in what follows | |||
| 17 | we only consider hibernation, but the description also applies to suspend). | 17 | we only consider hibernation, but the description also applies to suspend). |
| 18 | 18 | ||
| 19 | Namely, as the first step of the hibernation procedure the function | 19 | Namely, as the first step of the hibernation procedure the function |
| 20 | freeze_processes() (defined in kernel/power/process.c) is called. It executes | 20 | freeze_processes() (defined in kernel/power/process.c) is called. A system-wide |
| 21 | try_to_freeze_tasks() that sets TIF_FREEZE for all of the freezable tasks and | 21 | variable system_freezing_cnt (as opposed to a per-task flag) is used to indicate |
| 22 | either wakes them up, if they are kernel threads, or sends fake signals to them, | 22 | whether the system is to undergo a freezing operation. And freeze_processes() |
| 23 | if they are user space processes. A task that has TIF_FREEZE set, should react | 23 | sets this variable. After this, it executes try_to_freeze_tasks() that sends a |
| 24 | to it by calling the function called __refrigerator() (defined in | 24 | fake signal to all user space processes, and wakes up all the kernel threads. |
| 25 | kernel/freezer.c), which sets the task's PF_FROZEN flag, changes its state | 25 | All freezable tasks must react to that by calling try_to_freeze(), which |
| 26 | to TASK_UNINTERRUPTIBLE and makes it loop until PF_FROZEN is cleared for it. | 26 | results in a call to __refrigerator() (defined in kernel/freezer.c), which sets |
| 27 | Then, we say that the task is 'frozen' and therefore the set of functions | 27 | the task's PF_FROZEN flag, changes its state to TASK_UNINTERRUPTIBLE and makes |
| 28 | handling this mechanism is referred to as 'the freezer' (these functions are | 28 | it loop until PF_FROZEN is cleared for it. Then, we say that the task is |
| 29 | defined in kernel/power/process.c, kernel/freezer.c & include/linux/freezer.h). | 29 | 'frozen' and therefore the set of functions handling this mechanism is referred |
| 30 | User space processes are generally frozen before kernel threads. | 30 | to as 'the freezer' (these functions are defined in kernel/power/process.c, |
| 31 | kernel/freezer.c & include/linux/freezer.h). User space processes are generally | ||
| 32 | frozen before kernel threads. | ||
| 31 | 33 | ||
| 32 | __refrigerator() must not be called directly. Instead, use the | 34 | __refrigerator() must not be called directly. Instead, use the |
| 33 | try_to_freeze() function (defined in include/linux/freezer.h), that checks | 35 | try_to_freeze() function (defined in include/linux/freezer.h), that checks |
| 34 | the task's TIF_FREEZE flag and makes the task enter __refrigerator() if the | 36 | if the task is to be frozen and makes the task enter __refrigerator(). |
| 35 | flag is set. | ||
| 36 | 37 | ||
| 37 | For user space processes try_to_freeze() is called automatically from the | 38 | For user space processes try_to_freeze() is called automatically from the |
| 38 | signal-handling code, but the freezable kernel threads need to call it | 39 | signal-handling code, but the freezable kernel threads need to call it |
| 39 | explicitly in suitable places or use the wait_event_freezable() or | 40 | explicitly in suitable places or use the wait_event_freezable() or |
| 40 | wait_event_freezable_timeout() macros (defined in include/linux/freezer.h) | 41 | wait_event_freezable_timeout() macros (defined in include/linux/freezer.h) |
| 41 | that combine interruptible sleep with checking if TIF_FREEZE is set and calling | 42 | that combine interruptible sleep with checking if the task is to be frozen and |
| 42 | try_to_freeze(). The main loop of a freezable kernel thread may look like the | 43 | calling try_to_freeze(). The main loop of a freezable kernel thread may look |
| 43 | following one: | 44 | like the following one: |
| 44 | 45 | ||
| 45 | set_freezable(); | 46 | set_freezable(); |
| 46 | do { | 47 | do { |
| @@ -53,7 +54,7 @@ following one: | |||
| 53 | (from drivers/usb/core/hub.c::hub_thread()). | 54 | (from drivers/usb/core/hub.c::hub_thread()). |
| 54 | 55 | ||
| 55 | If a freezable kernel thread fails to call try_to_freeze() after the freezer has | 56 | If a freezable kernel thread fails to call try_to_freeze() after the freezer has |
| 56 | set TIF_FREEZE for it, the freezing of tasks will fail and the entire | 57 | initiated a freezing operation, the freezing of tasks will fail and the entire |
| 57 | hibernation operation will be cancelled. For this reason, freezable kernel | 58 | hibernation operation will be cancelled. For this reason, freezable kernel |
| 58 | threads must call try_to_freeze() somewhere or use one of the | 59 | threads must call try_to_freeze() somewhere or use one of the |
| 59 | wait_event_freezable() and wait_event_freezable_timeout() macros. | 60 | wait_event_freezable() and wait_event_freezable_timeout() macros. |
diff --git a/kernel/power/swap.c b/kernel/power/swap.c index 8742fd013a94..eef311a58a64 100644 --- a/kernel/power/swap.c +++ b/kernel/power/swap.c | |||
| @@ -51,6 +51,23 @@ | |||
| 51 | 51 | ||
| 52 | #define MAP_PAGE_ENTRIES (PAGE_SIZE / sizeof(sector_t) - 1) | 52 | #define MAP_PAGE_ENTRIES (PAGE_SIZE / sizeof(sector_t) - 1) |
| 53 | 53 | ||
| 54 | /* | ||
| 55 | * Number of free pages that are not high. | ||
| 56 | */ | ||
| 57 | static inline unsigned long low_free_pages(void) | ||
| 58 | { | ||
| 59 | return nr_free_pages() - nr_free_highpages(); | ||
| 60 | } | ||
| 61 | |||
| 62 | /* | ||
| 63 | * Number of pages required to be kept free while writing the image. Always | ||
| 64 | * half of all available low pages before the writing starts. | ||
| 65 | */ | ||
| 66 | static inline unsigned long reqd_free_pages(void) | ||
| 67 | { | ||
| 68 | return low_free_pages() / 2; | ||
| 69 | } | ||
| 70 | |||
| 54 | struct swap_map_page { | 71 | struct swap_map_page { |
| 55 | sector_t entries[MAP_PAGE_ENTRIES]; | 72 | sector_t entries[MAP_PAGE_ENTRIES]; |
| 56 | sector_t next_swap; | 73 | sector_t next_swap; |
| @@ -72,7 +89,7 @@ struct swap_map_handle { | |||
| 72 | sector_t cur_swap; | 89 | sector_t cur_swap; |
| 73 | sector_t first_sector; | 90 | sector_t first_sector; |
| 74 | unsigned int k; | 91 | unsigned int k; |
| 75 | unsigned long nr_free_pages, written; | 92 | unsigned long reqd_free_pages; |
| 76 | u32 crc32; | 93 | u32 crc32; |
| 77 | }; | 94 | }; |
| 78 | 95 | ||
| @@ -316,8 +333,7 @@ static int get_swap_writer(struct swap_map_handle *handle) | |||
| 316 | goto err_rel; | 333 | goto err_rel; |
| 317 | } | 334 | } |
| 318 | handle->k = 0; | 335 | handle->k = 0; |
| 319 | handle->nr_free_pages = nr_free_pages() >> 1; | 336 | handle->reqd_free_pages = reqd_free_pages(); |
| 320 | handle->written = 0; | ||
| 321 | handle->first_sector = handle->cur_swap; | 337 | handle->first_sector = handle->cur_swap; |
| 322 | return 0; | 338 | return 0; |
| 323 | err_rel: | 339 | err_rel: |
| @@ -352,11 +368,11 @@ static int swap_write_page(struct swap_map_handle *handle, void *buf, | |||
| 352 | handle->cur_swap = offset; | 368 | handle->cur_swap = offset; |
| 353 | handle->k = 0; | 369 | handle->k = 0; |
| 354 | } | 370 | } |
| 355 | if (bio_chain && ++handle->written > handle->nr_free_pages) { | 371 | if (bio_chain && low_free_pages() <= handle->reqd_free_pages) { |
| 356 | error = hib_wait_on_bio_chain(bio_chain); | 372 | error = hib_wait_on_bio_chain(bio_chain); |
| 357 | if (error) | 373 | if (error) |
| 358 | goto out; | 374 | goto out; |
| 359 | handle->written = 0; | 375 | handle->reqd_free_pages = reqd_free_pages(); |
| 360 | } | 376 | } |
| 361 | out: | 377 | out: |
| 362 | return error; | 378 | return error; |
| @@ -618,7 +634,7 @@ static int save_image_lzo(struct swap_map_handle *handle, | |||
| 618 | * Adjust number of free pages after all allocations have been done. | 634 | * Adjust number of free pages after all allocations have been done. |
| 619 | * We don't want to run out of pages when writing. | 635 | * We don't want to run out of pages when writing. |
| 620 | */ | 636 | */ |
| 621 | handle->nr_free_pages = nr_free_pages() >> 1; | 637 | handle->reqd_free_pages = reqd_free_pages(); |
| 622 | 638 | ||
| 623 | /* | 639 | /* |
| 624 | * Start the CRC32 thread. | 640 | * Start the CRC32 thread. |
