summaryrefslogtreecommitdiffstats
path: root/kernel/power/swsusp.c
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2006-01-06 09:13:46 +0100
committerLinus Torvalds <torvalds@g5.osdl.org>2006-01-06 17:33:40 +0100
commit72a97e08394a3b2e75481ff680ec2a0591e3cba4 (patch)
treed8ba72d6e81ad31ed10876386d3d2067921979e3 /kernel/power/swsusp.c
parent[PATCH] swsusp: introduce the swap map structure (diff)
downloadlinux-72a97e08394a3b2e75481ff680ec2a0591e3cba4.tar.xz
linux-72a97e08394a3b2e75481ff680ec2a0591e3cba4.zip
[PATCH] swsusp: improve freeing of memory
This patch makes swsusp free only as much memory as needed to complete the suspend and not as much as possible.  In the most of cases this should speed up the suspend and make the system much more responsive after resume, especially if a GUI (eg. X Windows) is used. If needed, the old behavior (ie to free as much memory as possible during suspend) can be restored by unsetting FAST_FREE in power.h Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Acked-by: Pavel Machek <pavel@suse.cz> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'kernel/power/swsusp.c')
-rw-r--r--kernel/power/swsusp.c52
1 files changed, 51 insertions, 1 deletions
diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c
index b09bd7c0998d..f77f9397a364 100644
--- a/kernel/power/swsusp.c
+++ b/kernel/power/swsusp.c
@@ -70,11 +70,13 @@
#include "power.h"
#ifdef CONFIG_HIGHMEM
+unsigned int count_highmem_pages(void);
int save_highmem(void);
int restore_highmem(void);
#else
static int save_highmem(void) { return 0; }
static int restore_highmem(void) { return 0; }
+static unsigned int count_highmem_pages(void) { return 0; }
#endif
extern char resume_file[];
@@ -611,6 +613,52 @@ int swsusp_write(struct pbe *pblist, unsigned int nr_pages)
return error;
}
+/**
+ * swsusp_shrink_memory - Try to free as much memory as needed
+ *
+ * ... but do not OOM-kill anyone
+ *
+ * Notice: all userland should be stopped before it is called, or
+ * livelock is possible.
+ */
+
+#define SHRINK_BITE 10000
+
+int swsusp_shrink_memory(void)
+{
+ long tmp;
+ struct zone *zone;
+ unsigned long pages = 0;
+ unsigned int i = 0;
+ char *p = "-\\|/";
+
+ printk("Shrinking memory... ");
+ do {
+#ifdef FAST_FREE
+ tmp = 2 * count_highmem_pages();
+ tmp += tmp / 50 + count_data_pages();
+ tmp += (tmp + PBES_PER_PAGE - 1) / PBES_PER_PAGE +
+ PAGES_FOR_IO;
+ for_each_zone (zone)
+ if (!is_highmem(zone))
+ tmp -= zone->free_pages;
+ if (tmp > 0) {
+ tmp = shrink_all_memory(SHRINK_BITE);
+ if (!tmp)
+ return -ENOMEM;
+ pages += tmp;
+ }
+#else
+ tmp = shrink_all_memory(SHRINK_BITE);
+ pages += tmp;
+#endif
+ printk("\b%c", p[i++%4]);
+ } while (tmp > 0);
+ printk("\bdone (%lu pages freed)\n", pages);
+
+ return 0;
+}
+
int swsusp_suspend(void)
{
int error;
@@ -1030,8 +1078,10 @@ static int read_suspend_image(struct pbe **pblist_ptr)
/* Allocate memory for the image and read the data from swap */
if (!error)
error = alloc_data_pages(pblist, GFP_ATOMIC, 1);
- if (!error)
+ if (!error) {
+ release_eaten_pages();
error = load_image_data(pblist, &handle, nr_pages);
+ }
if (!error)
*pblist_ptr = pblist;
}