diff options
| -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 | ||
