diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/power/power.h | 1 | ||||
-rw-r--r-- | kernel/power/snapshot.c | 2 | ||||
-rw-r--r-- | kernel/power/swsusp.c | 78 |
3 files changed, 28 insertions, 53 deletions
diff --git a/kernel/power/power.h b/kernel/power/power.h index c98923e13e75..893ee655085c 100644 --- a/kernel/power/power.h +++ b/kernel/power/power.h | |||
@@ -66,6 +66,7 @@ extern asmlinkage int swsusp_arch_suspend(void); | |||
66 | extern asmlinkage int swsusp_arch_resume(void); | 66 | extern asmlinkage int swsusp_arch_resume(void); |
67 | 67 | ||
68 | extern int restore_highmem(void); | 68 | extern int restore_highmem(void); |
69 | extern void free_pagedir(struct pbe *pblist); | ||
69 | extern struct pbe *alloc_pagedir(unsigned nr_pages, gfp_t gfp_mask, int safe_needed); | 70 | extern struct pbe *alloc_pagedir(unsigned nr_pages, gfp_t gfp_mask, int safe_needed); |
70 | extern void create_pbe_list(struct pbe *pblist, unsigned nr_pages); | 71 | extern void create_pbe_list(struct pbe *pblist, unsigned nr_pages); |
71 | extern void swsusp_free(void); | 72 | extern void swsusp_free(void); |
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index 96cc3e21e97d..b8a2e9a63206 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c | |||
@@ -216,7 +216,7 @@ static void copy_data_pages(struct pbe *pblist) | |||
216 | * free_pagedir - free pages allocated with alloc_pagedir() | 216 | * free_pagedir - free pages allocated with alloc_pagedir() |
217 | */ | 217 | */ |
218 | 218 | ||
219 | static void free_pagedir(struct pbe *pblist) | 219 | void free_pagedir(struct pbe *pblist) |
220 | { | 220 | { |
221 | struct pbe *pbe; | 221 | struct pbe *pbe; |
222 | 222 | ||
diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c index a456ffe7a3c8..8511c7f3386a 100644 --- a/kernel/power/swsusp.c +++ b/kernel/power/swsusp.c | |||
@@ -629,74 +629,43 @@ int swsusp_resume(void) | |||
629 | } | 629 | } |
630 | 630 | ||
631 | /** | 631 | /** |
632 | * swsusp_pagedir_relocate - It is possible, that some memory pages | 632 | * mark_unsafe_pages - mark the pages that cannot be used for storing |
633 | * occupied by the list of PBEs collide with pages where we're going to | 633 | * the image during resume, because they conflict with the pages that |
634 | * restore from the loaded pages later. We relocate them here. | 634 | * had been used before suspend |
635 | */ | 635 | */ |
636 | 636 | ||
637 | static struct pbe *swsusp_pagedir_relocate(struct pbe *pblist) | 637 | static void mark_unsafe_pages(struct pbe *pblist) |
638 | { | 638 | { |
639 | struct zone *zone; | 639 | struct zone *zone; |
640 | unsigned long zone_pfn; | 640 | unsigned long zone_pfn; |
641 | struct pbe *pbpage, *tail, *p; | 641 | struct pbe *p; |
642 | void *m; | ||
643 | int rel = 0; | ||
644 | 642 | ||
645 | if (!pblist) /* a sanity check */ | 643 | if (!pblist) /* a sanity check */ |
646 | return NULL; | 644 | return; |
647 | |||
648 | pr_debug("swsusp: Relocating pagedir (%lu pages to check)\n", | ||
649 | swsusp_info.pagedir_pages); | ||
650 | 645 | ||
651 | /* Clear page flags */ | 646 | /* Clear page flags */ |
652 | |||
653 | for_each_zone (zone) { | 647 | for_each_zone (zone) { |
654 | for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn) | 648 | for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn) |
655 | if (pfn_valid(zone_pfn + zone->zone_start_pfn)) | 649 | if (pfn_valid(zone_pfn + zone->zone_start_pfn)) |
656 | ClearPageNosaveFree(pfn_to_page(zone_pfn + | 650 | ClearPageNosaveFree(pfn_to_page(zone_pfn + |
657 | zone->zone_start_pfn)); | 651 | zone->zone_start_pfn)); |
658 | } | 652 | } |
659 | 653 | ||
660 | /* Mark orig addresses */ | 654 | /* Mark orig addresses */ |
661 | |||
662 | for_each_pbe (p, pblist) | 655 | for_each_pbe (p, pblist) |
663 | SetPageNosaveFree(virt_to_page(p->orig_address)); | 656 | SetPageNosaveFree(virt_to_page(p->orig_address)); |
664 | 657 | ||
665 | tail = pblist + PB_PAGE_SKIP; | 658 | } |
666 | |||
667 | /* Relocate colliding pages */ | ||
668 | |||
669 | for_each_pb_page (pbpage, pblist) { | ||
670 | if (PageNosaveFree(virt_to_page((unsigned long)pbpage))) { | ||
671 | m = (void *)get_safe_page(GFP_ATOMIC | __GFP_COLD); | ||
672 | if (!m) | ||
673 | return NULL; | ||
674 | memcpy(m, (void *)pbpage, PAGE_SIZE); | ||
675 | if (pbpage == pblist) | ||
676 | pblist = (struct pbe *)m; | ||
677 | else | ||
678 | tail->next = (struct pbe *)m; | ||
679 | pbpage = (struct pbe *)m; | ||
680 | |||
681 | /* We have to link the PBEs again */ | ||
682 | for (p = pbpage; p < pbpage + PB_PAGE_SKIP; p++) | ||
683 | if (p->next) /* needed to save the end */ | ||
684 | p->next = p + 1; | ||
685 | |||
686 | rel++; | ||
687 | } | ||
688 | tail = pbpage + PB_PAGE_SKIP; | ||
689 | } | ||
690 | 659 | ||
691 | /* This is for swsusp_free() */ | 660 | static void copy_page_backup_list(struct pbe *dst, struct pbe *src) |
692 | for_each_pb_page (pbpage, pblist) { | 661 | { |
693 | SetPageNosave(virt_to_page(pbpage)); | 662 | /* We assume both lists contain the same number of elements */ |
694 | SetPageNosaveFree(virt_to_page(pbpage)); | 663 | while (src) { |
664 | dst->orig_address = src->orig_address; | ||
665 | dst->swap_address = src->swap_address; | ||
666 | dst = dst->next; | ||
667 | src = src->next; | ||
695 | } | 668 | } |
696 | |||
697 | printk("swsusp: Relocated %d pages\n", rel); | ||
698 | |||
699 | return pblist; | ||
700 | } | 669 | } |
701 | 670 | ||
702 | /* | 671 | /* |
@@ -942,10 +911,15 @@ static int read_suspend_image(void) | |||
942 | 911 | ||
943 | if ((error = read_pagedir(p))) | 912 | if ((error = read_pagedir(p))) |
944 | return error; | 913 | return error; |
945 | |||
946 | create_pbe_list(p, nr_copy_pages); | 914 | create_pbe_list(p, nr_copy_pages); |
947 | 915 | mark_unsafe_pages(p); | |
948 | if (!(pagedir_nosave = swsusp_pagedir_relocate(p))) | 916 | pagedir_nosave = alloc_pagedir(nr_copy_pages, GFP_ATOMIC, 1); |
917 | if (pagedir_nosave) { | ||
918 | create_pbe_list(pagedir_nosave, nr_copy_pages); | ||
919 | copy_page_backup_list(pagedir_nosave, p); | ||
920 | } | ||
921 | free_pagedir(p); | ||
922 | if (!pagedir_nosave) | ||
949 | return -ENOMEM; | 923 | return -ENOMEM; |
950 | 924 | ||
951 | /* Allocate memory for the image and read the data from swap */ | 925 | /* Allocate memory for the image and read the data from swap */ |