aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2005-11-09 00:34:40 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2005-11-09 10:55:52 -0500
commited14b52701e6ef5a5aaf7bdb75932d5ea5dd7387 (patch)
treed69e6cb3777daab9e7b98aaad5b3a96491044862 /kernel
parent054bd4c18853f3a3851bd97aa90e11022a69dc42 (diff)
[PATCH] swsusp: simplify pagedir relocation
This patch simplifies the relocation of the page backup list (aka pagedir) during resume. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Cc: Pavel Machek <pavel@ucw.cz> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/power/power.h1
-rw-r--r--kernel/power/snapshot.c2
-rw-r--r--kernel/power/swsusp.c78
3 files changed, 28 insertions, 53 deletions
diff --git a/kernel/power/power.h b/kernel/power/power.h
index c98923e13e7..893ee655085 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -66,6 +66,7 @@ extern asmlinkage int swsusp_arch_suspend(void);
66extern asmlinkage int swsusp_arch_resume(void); 66extern asmlinkage int swsusp_arch_resume(void);
67 67
68extern int restore_highmem(void); 68extern int restore_highmem(void);
69extern void free_pagedir(struct pbe *pblist);
69extern struct pbe *alloc_pagedir(unsigned nr_pages, gfp_t gfp_mask, int safe_needed); 70extern struct pbe *alloc_pagedir(unsigned nr_pages, gfp_t gfp_mask, int safe_needed);
70extern void create_pbe_list(struct pbe *pblist, unsigned nr_pages); 71extern void create_pbe_list(struct pbe *pblist, unsigned nr_pages);
71extern void swsusp_free(void); 72extern void swsusp_free(void);
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
index 96cc3e21e97..b8a2e9a6320 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
219static void free_pagedir(struct pbe *pblist) 219void 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 a456ffe7a3c..8511c7f3386 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
637static struct pbe *swsusp_pagedir_relocate(struct pbe *pblist) 637static 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() */ 660static 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 */