Skip to content

Commit f8262d4

Browse files
bsmojverrjwysocki
authored andcommitted
PM / Hibernate: fix the number of pages used for hibernate/thaw buffering
Hibernation regression fix, since 3.2. Calculate the number of required free pages based on non-high memory pages only, because that is where the buffers will come from. Commit 081a9d0 introduced a new buffer page allocation logic during hibernation, in order to improve the performance. The amount of pages allocated was calculated based on total amount of pages available, although only non-high memory pages are usable for this purpose. This caused hibernation code to attempt to over allocate pages on platforms that have high memory, which led to hangs. Signed-off-by: Bojan Smojver <[email protected]> Signed-off-by: Rafael J. Wysocki <[email protected]>
1 parent 66f75a5 commit f8262d4

File tree

1 file changed

+22
-6
lines changed

1 file changed

+22
-6
lines changed

kernel/power/swap.c

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,23 @@
5151

5252
#define MAP_PAGE_ENTRIES (PAGE_SIZE / sizeof(sector_t) - 1)
5353

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+
5471
struct swap_map_page {
5572
sector_t entries[MAP_PAGE_ENTRIES];
5673
sector_t next_swap;
@@ -72,7 +89,7 @@ struct swap_map_handle {
7289
sector_t cur_swap;
7390
sector_t first_sector;
7491
unsigned int k;
75-
unsigned long nr_free_pages, written;
92+
unsigned long reqd_free_pages;
7693
u32 crc32;
7794
};
7895

@@ -316,8 +333,7 @@ static int get_swap_writer(struct swap_map_handle *handle)
316333
goto err_rel;
317334
}
318335
handle->k = 0;
319-
handle->nr_free_pages = nr_free_pages() >> 1;
320-
handle->written = 0;
336+
handle->reqd_free_pages = reqd_free_pages();
321337
handle->first_sector = handle->cur_swap;
322338
return 0;
323339
err_rel:
@@ -352,11 +368,11 @@ static int swap_write_page(struct swap_map_handle *handle, void *buf,
352368
handle->cur_swap = offset;
353369
handle->k = 0;
354370
}
355-
if (bio_chain && ++handle->written > handle->nr_free_pages) {
371+
if (bio_chain && low_free_pages() <= handle->reqd_free_pages) {
356372
error = hib_wait_on_bio_chain(bio_chain);
357373
if (error)
358374
goto out;
359-
handle->written = 0;
375+
handle->reqd_free_pages = reqd_free_pages();
360376
}
361377
out:
362378
return error;
@@ -618,7 +634,7 @@ static int save_image_lzo(struct swap_map_handle *handle,
618634
* Adjust number of free pages after all allocations have been done.
619635
* We don't want to run out of pages when writing.
620636
*/
621-
handle->nr_free_pages = nr_free_pages() >> 1;
637+
handle->reqd_free_pages = reqd_free_pages();
622638

623639
/*
624640
* Start the CRC32 thread.

0 commit comments

Comments
 (0)