diff options
Diffstat (limited to 'kernel/power')
-rw-r--r-- | kernel/power/power.h | 2 | ||||
-rw-r--r-- | kernel/power/snapshot.c | 78 | ||||
-rw-r--r-- | kernel/power/swsusp.c | 6 |
3 files changed, 43 insertions, 43 deletions
diff --git a/kernel/power/power.h b/kernel/power/power.h index e54dd8435de7..28afcb090149 100644 --- a/kernel/power/power.h +++ b/kernel/power/power.h | |||
@@ -69,4 +69,4 @@ extern int restore_highmem(void); | |||
69 | extern void free_pagedir(struct pbe *pblist); | 69 | extern void free_pagedir(struct pbe *pblist); |
70 | extern struct pbe * alloc_pagedir(unsigned nr_pages); | 70 | extern struct pbe * alloc_pagedir(unsigned nr_pages); |
71 | extern void create_pbe_list(struct pbe *pblist, unsigned nr_pages); | 71 | extern void create_pbe_list(struct pbe *pblist, unsigned nr_pages); |
72 | extern int enough_swap(void); | 72 | extern int enough_swap(unsigned nr_pages); |
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index 0f0a7f306b0d..03916cf3ff02 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c | |||
@@ -187,37 +187,38 @@ static int saveable(struct zone * zone, unsigned long * zone_pfn) | |||
187 | return 1; | 187 | return 1; |
188 | } | 188 | } |
189 | 189 | ||
190 | static void count_data_pages(void) | 190 | static unsigned count_data_pages(void) |
191 | { | 191 | { |
192 | struct zone *zone; | 192 | struct zone *zone; |
193 | unsigned long zone_pfn; | 193 | unsigned long zone_pfn; |
194 | unsigned n; | ||
194 | 195 | ||
195 | nr_copy_pages = 0; | 196 | n = 0; |
196 | |||
197 | for_each_zone (zone) { | 197 | for_each_zone (zone) { |
198 | if (is_highmem(zone)) | 198 | if (is_highmem(zone)) |
199 | continue; | 199 | continue; |
200 | mark_free_pages(zone); | 200 | mark_free_pages(zone); |
201 | for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn) | 201 | for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn) |
202 | nr_copy_pages += saveable(zone, &zone_pfn); | 202 | n += saveable(zone, &zone_pfn); |
203 | } | 203 | } |
204 | return n; | ||
204 | } | 205 | } |
205 | 206 | ||
206 | static void copy_data_pages(void) | 207 | static void copy_data_pages(struct pbe *pblist) |
207 | { | 208 | { |
208 | struct zone *zone; | 209 | struct zone *zone; |
209 | unsigned long zone_pfn; | 210 | unsigned long zone_pfn; |
210 | struct pbe *pbe = pagedir_nosave, *p; | 211 | struct pbe *pbe, *p; |
211 | 212 | ||
212 | pr_debug("copy_data_pages(): pages to copy: %d\n", nr_copy_pages); | 213 | pbe = pblist; |
213 | for_each_zone (zone) { | 214 | for_each_zone (zone) { |
214 | if (is_highmem(zone)) | 215 | if (is_highmem(zone)) |
215 | continue; | 216 | continue; |
216 | mark_free_pages(zone); | 217 | mark_free_pages(zone); |
217 | /* This is necessary for swsusp_free() */ | 218 | /* This is necessary for swsusp_free() */ |
218 | for_each_pb_page (p, pagedir_nosave) | 219 | for_each_pb_page (p, pblist) |
219 | SetPageNosaveFree(virt_to_page(p)); | 220 | SetPageNosaveFree(virt_to_page(p)); |
220 | for_each_pbe(p, pagedir_nosave) | 221 | for_each_pbe (p, pblist) |
221 | SetPageNosaveFree(virt_to_page(p->address)); | 222 | SetPageNosaveFree(virt_to_page(p->address)); |
222 | for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn) { | 223 | for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn) { |
223 | if (saveable(zone, &zone_pfn)) { | 224 | if (saveable(zone, &zone_pfn)) { |
@@ -370,46 +371,39 @@ void swsusp_free(void) | |||
370 | * free pages. | 371 | * free pages. |
371 | */ | 372 | */ |
372 | 373 | ||
373 | static int enough_free_mem(void) | 374 | static int enough_free_mem(unsigned nr_pages) |
374 | { | 375 | { |
375 | pr_debug("swsusp: available memory: %u pages\n", nr_free_pages()); | 376 | pr_debug("swsusp: available memory: %u pages\n", nr_free_pages()); |
376 | return nr_free_pages() > (nr_copy_pages + PAGES_FOR_IO + | 377 | return nr_free_pages() > (nr_pages + PAGES_FOR_IO + |
377 | nr_copy_pages/PBES_PER_PAGE + !!(nr_copy_pages%PBES_PER_PAGE)); | 378 | (nr_pages + PBES_PER_PAGE - 1) / PBES_PER_PAGE); |
378 | } | 379 | } |
379 | 380 | ||
380 | 381 | ||
381 | static int swsusp_alloc(void) | 382 | static struct pbe *swsusp_alloc(unsigned nr_pages) |
382 | { | 383 | { |
383 | struct pbe * p; | 384 | struct pbe *pblist, *p; |
384 | |||
385 | pagedir_nosave = NULL; | ||
386 | |||
387 | if (MAX_PBES < nr_copy_pages / PBES_PER_PAGE + | ||
388 | !!(nr_copy_pages % PBES_PER_PAGE)) | ||
389 | return -ENOSPC; | ||
390 | 385 | ||
391 | if (!(pagedir_save = alloc_pagedir(nr_copy_pages))) { | 386 | if (!(pblist = alloc_pagedir(nr_pages))) { |
392 | printk(KERN_ERR "suspend: Allocating pagedir failed.\n"); | 387 | printk(KERN_ERR "suspend: Allocating pagedir failed.\n"); |
393 | return -ENOMEM; | 388 | return NULL; |
394 | } | 389 | } |
395 | create_pbe_list(pagedir_save, nr_copy_pages); | 390 | create_pbe_list(pblist, nr_pages); |
396 | pagedir_nosave = pagedir_save; | ||
397 | 391 | ||
398 | for_each_pbe (p, pagedir_save) { | 392 | for_each_pbe (p, pblist) { |
399 | p->address = (unsigned long)alloc_image_page(); | 393 | p->address = (unsigned long)alloc_image_page(); |
400 | if (!p->address) { | 394 | if (!p->address) { |
401 | printk(KERN_ERR "suspend: Allocating image pages failed.\n"); | 395 | printk(KERN_ERR "suspend: Allocating image pages failed.\n"); |
402 | swsusp_free(); | 396 | swsusp_free(); |
403 | return -ENOMEM; | 397 | return NULL; |
404 | } | 398 | } |
405 | } | 399 | } |
406 | 400 | ||
407 | return 0; | 401 | return pblist; |
408 | } | 402 | } |
409 | 403 | ||
410 | static int suspend_prepare_image(void) | 404 | static int suspend_prepare_image(void) |
411 | { | 405 | { |
412 | int error; | 406 | unsigned nr_pages; |
413 | 407 | ||
414 | pr_debug("swsusp: critical section: \n"); | 408 | pr_debug("swsusp: critical section: \n"); |
415 | if (save_highmem()) { | 409 | if (save_highmem()) { |
@@ -419,33 +413,37 @@ static int suspend_prepare_image(void) | |||
419 | } | 413 | } |
420 | 414 | ||
421 | drain_local_pages(); | 415 | drain_local_pages(); |
422 | count_data_pages(); | 416 | nr_pages = count_data_pages(); |
423 | printk("swsusp: Need to copy %u pages\n", nr_copy_pages); | 417 | printk("swsusp: Need to copy %u pages\n", nr_pages); |
424 | 418 | ||
425 | pr_debug("swsusp: pages needed: %u + %lu + %u, free: %u\n", | 419 | pr_debug("swsusp: pages needed: %u + %lu + %u, free: %u\n", |
426 | nr_copy_pages, | 420 | nr_pages, |
427 | nr_copy_pages/PBES_PER_PAGE + !!(nr_copy_pages%PBES_PER_PAGE), | 421 | (nr_pages + PBES_PER_PAGE - 1) / PBES_PER_PAGE, |
428 | PAGES_FOR_IO, nr_free_pages()); | 422 | PAGES_FOR_IO, nr_free_pages()); |
429 | 423 | ||
430 | if (!enough_free_mem()) { | 424 | /* This is needed because of the fixed size of swsusp_info */ |
425 | if (MAX_PBES < (nr_pages + PBES_PER_PAGE - 1) / PBES_PER_PAGE) | ||
426 | return -ENOSPC; | ||
427 | |||
428 | if (!enough_free_mem(nr_pages)) { | ||
431 | printk(KERN_ERR "swsusp: Not enough free memory\n"); | 429 | printk(KERN_ERR "swsusp: Not enough free memory\n"); |
432 | return -ENOMEM; | 430 | return -ENOMEM; |
433 | } | 431 | } |
434 | 432 | ||
435 | if (!enough_swap()) { | 433 | if (!enough_swap(nr_pages)) { |
436 | printk(KERN_ERR "swsusp: Not enough free swap\n"); | 434 | printk(KERN_ERR "swsusp: Not enough free swap\n"); |
437 | return -ENOSPC; | 435 | return -ENOSPC; |
438 | } | 436 | } |
439 | 437 | ||
440 | error = swsusp_alloc(); | 438 | pagedir_nosave = swsusp_alloc(nr_pages); |
441 | if (error) | 439 | if (!pagedir_nosave) |
442 | return error; | 440 | return -ENOMEM; |
443 | 441 | ||
444 | /* During allocating of suspend pagedir, new cold pages may appear. | 442 | /* During allocating of suspend pagedir, new cold pages may appear. |
445 | * Kill them. | 443 | * Kill them. |
446 | */ | 444 | */ |
447 | drain_local_pages(); | 445 | drain_local_pages(); |
448 | copy_data_pages(); | 446 | copy_data_pages(pagedir_nosave); |
449 | 447 | ||
450 | /* | 448 | /* |
451 | * End of critical section. From now on, we can write to memory, | 449 | * End of critical section. From now on, we can write to memory, |
@@ -453,7 +451,9 @@ static int suspend_prepare_image(void) | |||
453 | * touch swap space! Except we must write out our image of course. | 451 | * touch swap space! Except we must write out our image of course. |
454 | */ | 452 | */ |
455 | 453 | ||
456 | printk("swsusp: critical section/: done (%d pages copied)\n", nr_copy_pages ); | 454 | nr_copy_pages = nr_pages; |
455 | |||
456 | printk("swsusp: critical section/: done (%d pages copied)\n", nr_pages); | ||
457 | return 0; | 457 | return 0; |
458 | } | 458 | } |
459 | 459 | ||
diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c index fc50b5d2dd26..f6abfdb0a02a 100644 --- a/kernel/power/swsusp.c +++ b/kernel/power/swsusp.c | |||
@@ -550,14 +550,14 @@ static int write_suspend_image(void) | |||
550 | * We should only consider resume_device. | 550 | * We should only consider resume_device. |
551 | */ | 551 | */ |
552 | 552 | ||
553 | int enough_swap(void) | 553 | int enough_swap(unsigned nr_pages) |
554 | { | 554 | { |
555 | struct sysinfo i; | 555 | struct sysinfo i; |
556 | 556 | ||
557 | si_swapinfo(&i); | 557 | si_swapinfo(&i); |
558 | pr_debug("swsusp: available swap: %lu pages\n", i.freeswap); | 558 | pr_debug("swsusp: available swap: %lu pages\n", i.freeswap); |
559 | return i.freeswap > (nr_copy_pages + PAGES_FOR_IO + | 559 | return i.freeswap > (nr_pages + PAGES_FOR_IO + |
560 | nr_copy_pages/PBES_PER_PAGE + !!(nr_copy_pages%PBES_PER_PAGE)); | 560 | (nr_pages + PBES_PER_PAGE - 1) / PBES_PER_PAGE); |
561 | } | 561 | } |
562 | 562 | ||
563 | 563 | ||