|
@@ -1122,9 +1122,19 @@ static unsigned long preallocate_image_pages(unsigned long nr_pages, gfp_t mask)
|
|
return nr_alloc;
|
|
return nr_alloc;
|
|
}
|
|
}
|
|
|
|
|
|
-static unsigned long preallocate_image_memory(unsigned long nr_pages)
|
|
|
|
|
|
+static unsigned long preallocate_image_memory(unsigned long nr_pages,
|
|
|
|
+ unsigned long avail_normal)
|
|
{
|
|
{
|
|
- return preallocate_image_pages(nr_pages, GFP_IMAGE);
|
|
|
|
|
|
+ unsigned long alloc;
|
|
|
|
+
|
|
|
|
+ if (avail_normal <= alloc_normal)
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+ alloc = avail_normal - alloc_normal;
|
|
|
|
+ if (nr_pages < alloc)
|
|
|
|
+ alloc = nr_pages;
|
|
|
|
+
|
|
|
|
+ return preallocate_image_pages(alloc, GFP_IMAGE);
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_HIGHMEM
|
|
#ifdef CONFIG_HIGHMEM
|
|
@@ -1170,15 +1180,22 @@ static inline unsigned long preallocate_highmem_fraction(unsigned long nr_pages,
|
|
*/
|
|
*/
|
|
static void free_unnecessary_pages(void)
|
|
static void free_unnecessary_pages(void)
|
|
{
|
|
{
|
|
- unsigned long save_highmem, to_free_normal, to_free_highmem;
|
|
|
|
|
|
+ unsigned long save, to_free_normal, to_free_highmem;
|
|
|
|
|
|
- to_free_normal = alloc_normal - count_data_pages();
|
|
|
|
- save_highmem = count_highmem_pages();
|
|
|
|
- if (alloc_highmem > save_highmem) {
|
|
|
|
- to_free_highmem = alloc_highmem - save_highmem;
|
|
|
|
|
|
+ save = count_data_pages();
|
|
|
|
+ if (alloc_normal >= save) {
|
|
|
|
+ to_free_normal = alloc_normal - save;
|
|
|
|
+ save = 0;
|
|
|
|
+ } else {
|
|
|
|
+ to_free_normal = 0;
|
|
|
|
+ save -= alloc_normal;
|
|
|
|
+ }
|
|
|
|
+ save += count_highmem_pages();
|
|
|
|
+ if (alloc_highmem >= save) {
|
|
|
|
+ to_free_highmem = alloc_highmem - save;
|
|
} else {
|
|
} else {
|
|
to_free_highmem = 0;
|
|
to_free_highmem = 0;
|
|
- to_free_normal -= save_highmem - alloc_highmem;
|
|
|
|
|
|
+ to_free_normal -= save - alloc_highmem;
|
|
}
|
|
}
|
|
|
|
|
|
memory_bm_position_reset(©_bm);
|
|
memory_bm_position_reset(©_bm);
|
|
@@ -1259,7 +1276,7 @@ int hibernate_preallocate_memory(void)
|
|
{
|
|
{
|
|
struct zone *zone;
|
|
struct zone *zone;
|
|
unsigned long saveable, size, max_size, count, highmem, pages = 0;
|
|
unsigned long saveable, size, max_size, count, highmem, pages = 0;
|
|
- unsigned long alloc, save_highmem, pages_highmem;
|
|
|
|
|
|
+ unsigned long alloc, save_highmem, pages_highmem, avail_normal;
|
|
struct timeval start, stop;
|
|
struct timeval start, stop;
|
|
int error;
|
|
int error;
|
|
|
|
|
|
@@ -1296,6 +1313,7 @@ int hibernate_preallocate_memory(void)
|
|
else
|
|
else
|
|
count += zone_page_state(zone, NR_FREE_PAGES);
|
|
count += zone_page_state(zone, NR_FREE_PAGES);
|
|
}
|
|
}
|
|
|
|
+ avail_normal = count;
|
|
count += highmem;
|
|
count += highmem;
|
|
count -= totalreserve_pages;
|
|
count -= totalreserve_pages;
|
|
|
|
|
|
@@ -1310,12 +1328,21 @@ int hibernate_preallocate_memory(void)
|
|
*/
|
|
*/
|
|
if (size >= saveable) {
|
|
if (size >= saveable) {
|
|
pages = preallocate_image_highmem(save_highmem);
|
|
pages = preallocate_image_highmem(save_highmem);
|
|
- pages += preallocate_image_memory(saveable - pages);
|
|
|
|
|
|
+ pages += preallocate_image_memory(saveable - pages, avail_normal);
|
|
goto out;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
|
|
/* Estimate the minimum size of the image. */
|
|
/* Estimate the minimum size of the image. */
|
|
pages = minimum_image_size(saveable);
|
|
pages = minimum_image_size(saveable);
|
|
|
|
+ /*
|
|
|
|
+ * To avoid excessive pressure on the normal zone, leave room in it to
|
|
|
|
+ * accommodate an image of the minimum size (unless it's already too
|
|
|
|
+ * small, in which case don't preallocate pages from it at all).
|
|
|
|
+ */
|
|
|
|
+ if (avail_normal > pages)
|
|
|
|
+ avail_normal -= pages;
|
|
|
|
+ else
|
|
|
|
+ avail_normal = 0;
|
|
if (size < pages)
|
|
if (size < pages)
|
|
size = min_t(unsigned long, pages, max_size);
|
|
size = min_t(unsigned long, pages, max_size);
|
|
|
|
|
|
@@ -1336,16 +1363,34 @@ int hibernate_preallocate_memory(void)
|
|
*/
|
|
*/
|
|
pages_highmem = preallocate_image_highmem(highmem / 2);
|
|
pages_highmem = preallocate_image_highmem(highmem / 2);
|
|
alloc = (count - max_size) - pages_highmem;
|
|
alloc = (count - max_size) - pages_highmem;
|
|
- pages = preallocate_image_memory(alloc);
|
|
|
|
- if (pages < alloc)
|
|
|
|
- goto err_out;
|
|
|
|
- size = max_size - size;
|
|
|
|
- alloc = size;
|
|
|
|
- size = preallocate_highmem_fraction(size, highmem, count);
|
|
|
|
- pages_highmem += size;
|
|
|
|
- alloc -= size;
|
|
|
|
- pages += preallocate_image_memory(alloc);
|
|
|
|
- pages += pages_highmem;
|
|
|
|
|
|
+ pages = preallocate_image_memory(alloc, avail_normal);
|
|
|
|
+ if (pages < alloc) {
|
|
|
|
+ /* We have exhausted non-highmem pages, try highmem. */
|
|
|
|
+ alloc -= pages;
|
|
|
|
+ pages += pages_highmem;
|
|
|
|
+ pages_highmem = preallocate_image_highmem(alloc);
|
|
|
|
+ if (pages_highmem < alloc)
|
|
|
|
+ goto err_out;
|
|
|
|
+ pages += pages_highmem;
|
|
|
|
+ /*
|
|
|
|
+ * size is the desired number of saveable pages to leave in
|
|
|
|
+ * memory, so try to preallocate (all memory - size) pages.
|
|
|
|
+ */
|
|
|
|
+ alloc = (count - pages) - size;
|
|
|
|
+ pages += preallocate_image_highmem(alloc);
|
|
|
|
+ } else {
|
|
|
|
+ /*
|
|
|
|
+ * There are approximately max_size saveable pages at this point
|
|
|
|
+ * and we want to reduce this number down to size.
|
|
|
|
+ */
|
|
|
|
+ alloc = max_size - size;
|
|
|
|
+ size = preallocate_highmem_fraction(alloc, highmem, count);
|
|
|
|
+ pages_highmem += size;
|
|
|
|
+ alloc -= size;
|
|
|
|
+ size = preallocate_image_memory(alloc, avail_normal);
|
|
|
|
+ pages_highmem += preallocate_image_highmem(alloc - size);
|
|
|
|
+ pages += pages_highmem + size;
|
|
|
|
+ }
|
|
|
|
|
|
/*
|
|
/*
|
|
* We only need as many page frames for the image as there are saveable
|
|
* We only need as many page frames for the image as there are saveable
|