diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index da5288e..2e245d9 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -262,6 +262,7 @@ static int create_image(int platform_mode) if (error || hibernation_test(TEST_PLATFORM)) goto Platform_finish; + check_free(GFP_NOWAIT); error = disable_nonboot_cpus(); if (error || hibernation_test(TEST_CPUS) || hibernation_testmode(HIBERNATION_TEST)) diff --git a/kernel/power/power.h b/kernel/power/power.h index 46c5a26..d2178dc 100644 --- a/kernel/power/power.h +++ b/kernel/power/power.h @@ -236,3 +236,53 @@ static inline void suspend_thaw_processes(void) { } #endif + +/* An empirical check on the number of free pages */ +static inline int check_free_pages(gfp_t gfp_flags, const char *gfp_name, int order) +{ + int ret; + int count = 0; + void *first = NULL; + void **p = &first; + unsigned long page; + + /* Allocate free pages into a linked list, headed by "first" */ + while(count < ((PAGES_FOR_IO + SPARE_PAGES) >> order)) { + page = __get_free_pages(gfp_flags|__GFP_NOWARN, order); + if (!page) + break; + *p = (void *)page; + p = (void **)page; + count++; + } + *p = NULL; + + ret = count; + printk(KERN_INFO + "%d %s allocations of order %d are possible\n", + count, gfp_name, order); + + /* Free the pages again */ + p = first; + while(p) { + page = (unsigned long) p; + p = *p; + free_pages(page, order); + count--; + } + BUG_ON(count != 0); + + return ret; +} + +static inline void __check_free(gfp_t gfp_flags, const char *gfp_name) +{ + int order; + + for (order = 0; order < 3; order++) + if (check_free_pages(gfp_flags, gfp_name, order) <= 0) + break; +} + +#define check_free(flags) __check_free(flags, #flags) + diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index 36cb168..605b7b7 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c @@ -1261,6 +1261,8 @@ int hibernate_preallocate_memory(void) struct timeval start, stop; int error; + check_free(GFP_NOWAIT); + check_free(GFP_KERNEL); printk(KERN_INFO "PM: Preallocating image memory... "); do_gettimeofday(&start); @@ -1350,7 +1352,10 @@ int hibernate_preallocate_memory(void) * pages in memory, but we have allocated more. Release the excessive * ones now. */ + check_free(GFP_NOWAIT); free_unnecessary_pages(); + check_free(GFP_NOWAIT); + check_free(GFP_KERNEL); out: do_gettimeofday(&stop);