Commit ed14b527 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki Committed by Linus Torvalds

[PATCH] swsusp: simplify pagedir relocation

This patch simplifies the relocation of the page backup list (aka pagedir)
during resume.
Signed-off-by: default avatarRafael J. Wysocki <rjw@sisk.pl>
Cc: Pavel Machek <pavel@ucw.cz>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 054bd4c1
...@@ -66,6 +66,7 @@ extern asmlinkage int swsusp_arch_suspend(void); ...@@ -66,6 +66,7 @@ extern asmlinkage int swsusp_arch_suspend(void);
extern asmlinkage int swsusp_arch_resume(void); extern asmlinkage int swsusp_arch_resume(void);
extern int restore_highmem(void); extern int restore_highmem(void);
extern void free_pagedir(struct pbe *pblist);
extern struct pbe *alloc_pagedir(unsigned nr_pages, gfp_t gfp_mask, int safe_needed); extern struct pbe *alloc_pagedir(unsigned nr_pages, gfp_t gfp_mask, int safe_needed);
extern void create_pbe_list(struct pbe *pblist, unsigned nr_pages); extern void create_pbe_list(struct pbe *pblist, unsigned nr_pages);
extern void swsusp_free(void); extern void swsusp_free(void);
......
...@@ -216,7 +216,7 @@ static void copy_data_pages(struct pbe *pblist) ...@@ -216,7 +216,7 @@ static void copy_data_pages(struct pbe *pblist)
* free_pagedir - free pages allocated with alloc_pagedir() * free_pagedir - free pages allocated with alloc_pagedir()
*/ */
static void free_pagedir(struct pbe *pblist) void free_pagedir(struct pbe *pblist)
{ {
struct pbe *pbe; struct pbe *pbe;
......
...@@ -629,74 +629,43 @@ int swsusp_resume(void) ...@@ -629,74 +629,43 @@ int swsusp_resume(void)
} }
/** /**
* swsusp_pagedir_relocate - It is possible, that some memory pages * mark_unsafe_pages - mark the pages that cannot be used for storing
* occupied by the list of PBEs collide with pages where we're going to * the image during resume, because they conflict with the pages that
* restore from the loaded pages later. We relocate them here. * had been used before suspend
*/ */
static struct pbe *swsusp_pagedir_relocate(struct pbe *pblist) static void mark_unsafe_pages(struct pbe *pblist)
{ {
struct zone *zone; struct zone *zone;
unsigned long zone_pfn; unsigned long zone_pfn;
struct pbe *pbpage, *tail, *p; struct pbe *p;
void *m;
int rel = 0;
if (!pblist) /* a sanity check */ if (!pblist) /* a sanity check */
return NULL; return;
pr_debug("swsusp: Relocating pagedir (%lu pages to check)\n",
swsusp_info.pagedir_pages);
/* Clear page flags */ /* Clear page flags */
for_each_zone (zone) { for_each_zone (zone) {
for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn) for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn)
if (pfn_valid(zone_pfn + zone->zone_start_pfn)) if (pfn_valid(zone_pfn + zone->zone_start_pfn))
ClearPageNosaveFree(pfn_to_page(zone_pfn + ClearPageNosaveFree(pfn_to_page(zone_pfn +
zone->zone_start_pfn)); zone->zone_start_pfn));
} }
/* Mark orig addresses */ /* Mark orig addresses */
for_each_pbe (p, pblist) for_each_pbe (p, pblist)
SetPageNosaveFree(virt_to_page(p->orig_address)); SetPageNosaveFree(virt_to_page(p->orig_address));
tail = pblist + PB_PAGE_SKIP; }
/* Relocate colliding pages */
for_each_pb_page (pbpage, pblist) {
if (PageNosaveFree(virt_to_page((unsigned long)pbpage))) {
m = (void *)get_safe_page(GFP_ATOMIC | __GFP_COLD);
if (!m)
return NULL;
memcpy(m, (void *)pbpage, PAGE_SIZE);
if (pbpage == pblist)
pblist = (struct pbe *)m;
else
tail->next = (struct pbe *)m;
pbpage = (struct pbe *)m;
/* We have to link the PBEs again */
for (p = pbpage; p < pbpage + PB_PAGE_SKIP; p++)
if (p->next) /* needed to save the end */
p->next = p + 1;
rel++;
}
tail = pbpage + PB_PAGE_SKIP;
}
/* This is for swsusp_free() */ static void copy_page_backup_list(struct pbe *dst, struct pbe *src)
for_each_pb_page (pbpage, pblist) { {
SetPageNosave(virt_to_page(pbpage)); /* We assume both lists contain the same number of elements */
SetPageNosaveFree(virt_to_page(pbpage)); while (src) {
dst->orig_address = src->orig_address;
dst->swap_address = src->swap_address;
dst = dst->next;
src = src->next;
} }
printk("swsusp: Relocated %d pages\n", rel);
return pblist;
} }
/* /*
...@@ -942,10 +911,15 @@ static int read_suspend_image(void) ...@@ -942,10 +911,15 @@ static int read_suspend_image(void)
if ((error = read_pagedir(p))) if ((error = read_pagedir(p)))
return error; return error;
create_pbe_list(p, nr_copy_pages); create_pbe_list(p, nr_copy_pages);
mark_unsafe_pages(p);
if (!(pagedir_nosave = swsusp_pagedir_relocate(p))) pagedir_nosave = alloc_pagedir(nr_copy_pages, GFP_ATOMIC, 1);
if (pagedir_nosave) {
create_pbe_list(pagedir_nosave, nr_copy_pages);
copy_page_backup_list(pagedir_nosave, p);
}
free_pagedir(p);
if (!pagedir_nosave)
return -ENOMEM; return -ENOMEM;
/* Allocate memory for the image and read the data from swap */ /* Allocate memory for the image and read the data from swap */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment