aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/power/snapshot.c
diff options
context:
space:
mode:
authorJeff Garzik <jgarzik@pobox.com>2005-11-10 04:12:10 -0500
committerJeff Garzik <jgarzik@pobox.com>2005-11-10 04:12:10 -0500
commit2f67bdb23d74a6c6fd4f98f64239c5c34d1833cc (patch)
treefe533abe3e7c400848647b95e4806f5125c654c3 /kernel/power/snapshot.c
parentd40d9d29c020f8466c96f8e3ad4b7c014ff1085d (diff)
parent3b44f137b9a846c5452d9e6e1271b79b1dbcc942 (diff)
Merge branch 'master'
Diffstat (limited to 'kernel/power/snapshot.c')
-rw-r--r--kernel/power/snapshot.c100
1 files changed, 59 insertions, 41 deletions
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
index 42a628704398..4a6dbcefd378 100644
--- a/kernel/power/snapshot.c
+++ b/kernel/power/snapshot.c
@@ -88,8 +88,7 @@ static int save_highmem_zone(struct zone *zone)
88 return 0; 88 return 0;
89} 89}
90 90
91 91int save_highmem(void)
92static int save_highmem(void)
93{ 92{
94 struct zone *zone; 93 struct zone *zone;
95 int res = 0; 94 int res = 0;
@@ -120,11 +119,7 @@ int restore_highmem(void)
120 } 119 }
121 return 0; 120 return 0;
122} 121}
123#else 122#endif
124static int save_highmem(void) { return 0; }
125int restore_highmem(void) { return 0; }
126#endif /* CONFIG_HIGHMEM */
127
128 123
129static int pfn_is_nosave(unsigned long pfn) 124static int pfn_is_nosave(unsigned long pfn)
130{ 125{
@@ -168,9 +163,8 @@ static unsigned count_data_pages(void)
168{ 163{
169 struct zone *zone; 164 struct zone *zone;
170 unsigned long zone_pfn; 165 unsigned long zone_pfn;
171 unsigned n; 166 unsigned int n = 0;
172 167
173 n = 0;
174 for_each_zone (zone) { 168 for_each_zone (zone) {
175 if (is_highmem(zone)) 169 if (is_highmem(zone))
176 continue; 170 continue;
@@ -217,7 +211,7 @@ static void copy_data_pages(struct pbe *pblist)
217 * free_pagedir - free pages allocated with alloc_pagedir() 211 * free_pagedir - free pages allocated with alloc_pagedir()
218 */ 212 */
219 213
220static void free_pagedir(struct pbe *pblist) 214void free_pagedir(struct pbe *pblist)
221{ 215{
222 struct pbe *pbe; 216 struct pbe *pbe;
223 217
@@ -250,10 +244,10 @@ static inline void fill_pb_page(struct pbe *pbpage)
250 * of memory pages allocated with alloc_pagedir() 244 * of memory pages allocated with alloc_pagedir()
251 */ 245 */
252 246
253void create_pbe_list(struct pbe *pblist, unsigned nr_pages) 247void create_pbe_list(struct pbe *pblist, unsigned int nr_pages)
254{ 248{
255 struct pbe *pbpage, *p; 249 struct pbe *pbpage, *p;
256 unsigned num = PBES_PER_PAGE; 250 unsigned int num = PBES_PER_PAGE;
257 251
258 for_each_pb_page (pbpage, pblist) { 252 for_each_pb_page (pbpage, pblist) {
259 if (num >= nr_pages) 253 if (num >= nr_pages)
@@ -270,9 +264,30 @@ void create_pbe_list(struct pbe *pblist, unsigned nr_pages)
270 pr_debug("create_pbe_list(): initialized %d PBEs\n", num); 264 pr_debug("create_pbe_list(): initialized %d PBEs\n", num);
271} 265}
272 266
273static void *alloc_image_page(void) 267/**
268 * @safe_needed - on resume, for storing the PBE list and the image,
269 * we can only use memory pages that do not conflict with the pages
270 * which had been used before suspend.
271 *
272 * The unsafe pages are marked with the PG_nosave_free flag
273 *
274 * Allocated but unusable (ie eaten) memory pages should be marked
275 * so that swsusp_free() can release them
276 */
277
278static inline void *alloc_image_page(gfp_t gfp_mask, int safe_needed)
274{ 279{
275 void *res = (void *)get_zeroed_page(GFP_ATOMIC | __GFP_COLD); 280 void *res;
281
282 if (safe_needed)
283 do {
284 res = (void *)get_zeroed_page(gfp_mask);
285 if (res && PageNosaveFree(virt_to_page(res)))
286 /* This is for swsusp_free() */
287 SetPageNosave(virt_to_page(res));
288 } while (res && PageNosaveFree(virt_to_page(res)));
289 else
290 res = (void *)get_zeroed_page(gfp_mask);
276 if (res) { 291 if (res) {
277 SetPageNosave(virt_to_page(res)); 292 SetPageNosave(virt_to_page(res));
278 SetPageNosaveFree(virt_to_page(res)); 293 SetPageNosaveFree(virt_to_page(res));
@@ -280,6 +295,11 @@ static void *alloc_image_page(void)
280 return res; 295 return res;
281} 296}
282 297
298unsigned long get_safe_page(gfp_t gfp_mask)
299{
300 return (unsigned long)alloc_image_page(gfp_mask, 1);
301}
302
283/** 303/**
284 * alloc_pagedir - Allocate the page directory. 304 * alloc_pagedir - Allocate the page directory.
285 * 305 *
@@ -293,21 +313,21 @@ static void *alloc_image_page(void)
293 * On each page we set up a list of struct_pbe elements. 313 * On each page we set up a list of struct_pbe elements.
294 */ 314 */
295 315
296struct pbe *alloc_pagedir(unsigned nr_pages) 316struct pbe *alloc_pagedir(unsigned int nr_pages, gfp_t gfp_mask, int safe_needed)
297{ 317{
298 unsigned num; 318 unsigned int num;
299 struct pbe *pblist, *pbe; 319 struct pbe *pblist, *pbe;
300 320
301 if (!nr_pages) 321 if (!nr_pages)
302 return NULL; 322 return NULL;
303 323
304 pr_debug("alloc_pagedir(): nr_pages = %d\n", nr_pages); 324 pr_debug("alloc_pagedir(): nr_pages = %d\n", nr_pages);
305 pblist = alloc_image_page(); 325 pblist = alloc_image_page(gfp_mask, safe_needed);
306 /* FIXME: rewrite this ugly loop */ 326 /* FIXME: rewrite this ugly loop */
307 for (pbe = pblist, num = PBES_PER_PAGE; pbe && num < nr_pages; 327 for (pbe = pblist, num = PBES_PER_PAGE; pbe && num < nr_pages;
308 pbe = pbe->next, num += PBES_PER_PAGE) { 328 pbe = pbe->next, num += PBES_PER_PAGE) {
309 pbe += PB_PAGE_SKIP; 329 pbe += PB_PAGE_SKIP;
310 pbe->next = alloc_image_page(); 330 pbe->next = alloc_image_page(gfp_mask, safe_needed);
311 } 331 }
312 if (!pbe) { /* get_zeroed_page() failed */ 332 if (!pbe) { /* get_zeroed_page() failed */
313 free_pagedir(pblist); 333 free_pagedir(pblist);
@@ -329,7 +349,7 @@ void swsusp_free(void)
329 for_each_zone(zone) { 349 for_each_zone(zone) {
330 for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn) 350 for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn)
331 if (pfn_valid(zone_pfn + zone->zone_start_pfn)) { 351 if (pfn_valid(zone_pfn + zone->zone_start_pfn)) {
332 struct page * page; 352 struct page *page;
333 page = pfn_to_page(zone_pfn + zone->zone_start_pfn); 353 page = pfn_to_page(zone_pfn + zone->zone_start_pfn);
334 if (PageNosave(page) && PageNosaveFree(page)) { 354 if (PageNosave(page) && PageNosaveFree(page)) {
335 ClearPageNosave(page); 355 ClearPageNosave(page);
@@ -348,31 +368,39 @@ void swsusp_free(void)
348 * free pages. 368 * free pages.
349 */ 369 */
350 370
351static int enough_free_mem(unsigned nr_pages) 371static int enough_free_mem(unsigned int nr_pages)
352{ 372{
353 pr_debug("swsusp: available memory: %u pages\n", nr_free_pages()); 373 pr_debug("swsusp: available memory: %u pages\n", nr_free_pages());
354 return nr_free_pages() > (nr_pages + PAGES_FOR_IO + 374 return nr_free_pages() > (nr_pages + PAGES_FOR_IO +
355 (nr_pages + PBES_PER_PAGE - 1) / PBES_PER_PAGE); 375 (nr_pages + PBES_PER_PAGE - 1) / PBES_PER_PAGE);
356} 376}
357 377
378int alloc_data_pages(struct pbe *pblist, gfp_t gfp_mask, int safe_needed)
379{
380 struct pbe *p;
358 381
359static struct pbe *swsusp_alloc(unsigned nr_pages) 382 for_each_pbe (p, pblist) {
383 p->address = (unsigned long)alloc_image_page(gfp_mask, safe_needed);
384 if (!p->address)
385 return -ENOMEM;
386 }
387 return 0;
388}
389
390static struct pbe *swsusp_alloc(unsigned int nr_pages)
360{ 391{
361 struct pbe *pblist, *p; 392 struct pbe *pblist;
362 393
363 if (!(pblist = alloc_pagedir(nr_pages))) { 394 if (!(pblist = alloc_pagedir(nr_pages, GFP_ATOMIC | __GFP_COLD, 0))) {
364 printk(KERN_ERR "suspend: Allocating pagedir failed.\n"); 395 printk(KERN_ERR "suspend: Allocating pagedir failed.\n");
365 return NULL; 396 return NULL;
366 } 397 }
367 create_pbe_list(pblist, nr_pages); 398 create_pbe_list(pblist, nr_pages);
368 399
369 for_each_pbe (p, pblist) { 400 if (alloc_data_pages(pblist, GFP_ATOMIC | __GFP_COLD, 0)) {
370 p->address = (unsigned long)alloc_image_page(); 401 printk(KERN_ERR "suspend: Allocating image pages failed.\n");
371 if (!p->address) { 402 swsusp_free();
372 printk(KERN_ERR "suspend: Allocating image pages failed.\n"); 403 return NULL;
373 swsusp_free();
374 return NULL;
375 }
376 } 404 }
377 405
378 return pblist; 406 return pblist;
@@ -380,14 +408,9 @@ static struct pbe *swsusp_alloc(unsigned nr_pages)
380 408
381asmlinkage int swsusp_save(void) 409asmlinkage int swsusp_save(void)
382{ 410{
383 unsigned nr_pages; 411 unsigned int nr_pages;
384 412
385 pr_debug("swsusp: critical section: \n"); 413 pr_debug("swsusp: critical section: \n");
386 if (save_highmem()) {
387 printk(KERN_CRIT "swsusp: Not enough free pages for highmem\n");
388 restore_highmem();
389 return -ENOMEM;
390 }
391 414
392 drain_local_pages(); 415 drain_local_pages();
393 nr_pages = count_data_pages(); 416 nr_pages = count_data_pages();
@@ -407,11 +430,6 @@ asmlinkage int swsusp_save(void)
407 return -ENOMEM; 430 return -ENOMEM;
408 } 431 }
409 432
410 if (!enough_swap(nr_pages)) {
411 printk(KERN_ERR "swsusp: Not enough free swap\n");
412 return -ENOSPC;
413 }
414
415 pagedir_nosave = swsusp_alloc(nr_pages); 433 pagedir_nosave = swsusp_alloc(nr_pages);
416 if (!pagedir_nosave) 434 if (!pagedir_nosave)
417 return -ENOMEM; 435 return -ENOMEM;