aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/power/snapshot.c
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2006-01-06 03:13:46 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-01-06 11:33:40 -0500
commit72a97e08394a3b2e75481ff680ec2a0591e3cba4 (patch)
treed8ba72d6e81ad31ed10876386d3d2067921979e3 /kernel/power/snapshot.c
parent7088a5c00103ef48782d6c359cd12b13a10666e6 (diff)
[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/snapshot.c')
-rw-r--r--kernel/power/snapshot.c65
1 files changed, 60 insertions, 5 deletions
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
index 152d56cdf017..e80d282dbf58 100644
--- a/kernel/power/snapshot.c
+++ b/kernel/power/snapshot.c
@@ -37,6 +37,31 @@ struct pbe *pagedir_nosave;
37unsigned int nr_copy_pages; 37unsigned int nr_copy_pages;
38 38
39#ifdef CONFIG_HIGHMEM 39#ifdef CONFIG_HIGHMEM
40unsigned int count_highmem_pages(void)
41{
42 struct zone *zone;
43 unsigned long zone_pfn;
44 unsigned int n = 0;
45
46 for_each_zone (zone)
47 if (is_highmem(zone)) {
48 mark_free_pages(zone);
49 for (zone_pfn = 0; zone_pfn < zone->spanned_pages; zone_pfn++) {
50 struct page *page;
51 unsigned long pfn = zone_pfn + zone->zone_start_pfn;
52 if (!pfn_valid(pfn))
53 continue;
54 page = pfn_to_page(pfn);
55 if (PageReserved(page))
56 continue;
57 if (PageNosaveFree(page))
58 continue;
59 n++;
60 }
61 }
62 return n;
63}
64
40struct highmem_page { 65struct highmem_page {
41 char *data; 66 char *data;
42 struct page *page; 67 struct page *page;
@@ -152,17 +177,15 @@ static int saveable(struct zone *zone, unsigned long *zone_pfn)
152 BUG_ON(PageReserved(page) && PageNosave(page)); 177 BUG_ON(PageReserved(page) && PageNosave(page));
153 if (PageNosave(page)) 178 if (PageNosave(page))
154 return 0; 179 return 0;
155 if (PageReserved(page) && pfn_is_nosave(pfn)) { 180 if (PageReserved(page) && pfn_is_nosave(pfn))
156 pr_debug("[nosave pfn 0x%lx]", pfn);
157 return 0; 181 return 0;
158 }
159 if (PageNosaveFree(page)) 182 if (PageNosaveFree(page))
160 return 0; 183 return 0;
161 184
162 return 1; 185 return 1;
163} 186}
164 187
165static unsigned count_data_pages(void) 188unsigned int count_data_pages(void)
166{ 189{
167 struct zone *zone; 190 struct zone *zone;
168 unsigned long zone_pfn; 191 unsigned long zone_pfn;
@@ -267,6 +290,35 @@ static inline void create_pbe_list(struct pbe *pblist, unsigned int nr_pages)
267} 290}
268 291
269/** 292/**
293 * On resume it is necessary to trace and eventually free the unsafe
294 * pages that have been allocated, because they are needed for I/O
295 * (on x86-64 we likely will "eat" these pages once again while
296 * creating the temporary page translation tables)
297 */
298
299struct eaten_page {
300 struct eaten_page *next;
301 char padding[PAGE_SIZE - sizeof(void *)];
302};
303
304static struct eaten_page *eaten_pages = NULL;
305
306void release_eaten_pages(void)
307{
308 struct eaten_page *p, *q;
309
310 p = eaten_pages;
311 while (p) {
312 q = p->next;
313 /* We don't want swsusp_free() to free this page again */
314 ClearPageNosave(virt_to_page(p));
315 free_page((unsigned long)p);
316 p = q;
317 }
318 eaten_pages = NULL;
319}
320
321/**
270 * @safe_needed - on resume, for storing the PBE list and the image, 322 * @safe_needed - on resume, for storing the PBE list and the image,
271 * we can only use memory pages that do not conflict with the pages 323 * we can only use memory pages that do not conflict with the pages
272 * which had been used before suspend. 324 * which had been used before suspend.
@@ -284,9 +336,12 @@ static inline void *alloc_image_page(gfp_t gfp_mask, int safe_needed)
284 if (safe_needed) 336 if (safe_needed)
285 do { 337 do {
286 res = (void *)get_zeroed_page(gfp_mask); 338 res = (void *)get_zeroed_page(gfp_mask);
287 if (res && PageNosaveFree(virt_to_page(res))) 339 if (res && PageNosaveFree(virt_to_page(res))) {
288 /* This is for swsusp_free() */ 340 /* This is for swsusp_free() */
289 SetPageNosave(virt_to_page(res)); 341 SetPageNosave(virt_to_page(res));
342 ((struct eaten_page *)res)->next = eaten_pages;
343 eaten_pages = res;
344 }
290 } while (res && PageNosaveFree(virt_to_page(res))); 345 } while (res && PageNosaveFree(virt_to_page(res)));
291 else 346 else
292 res = (void *)get_zeroed_page(gfp_mask); 347 res = (void *)get_zeroed_page(gfp_mask);