[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>
This commit is contained in:
committed by
Linus Torvalds
parent
054bd4c188
commit
ed14b52701
@@ -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)
|
|||||||
* 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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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 */
|
static void copy_page_backup_list(struct pbe *dst, struct pbe *src)
|
||||||
|
{
|
||||||
for_each_pb_page (pbpage, pblist) {
|
/* We assume both lists contain the same number of elements */
|
||||||
if (PageNosaveFree(virt_to_page((unsigned long)pbpage))) {
|
while (src) {
|
||||||
m = (void *)get_safe_page(GFP_ATOMIC | __GFP_COLD);
|
dst->orig_address = src->orig_address;
|
||||||
if (!m)
|
dst->swap_address = src->swap_address;
|
||||||
return NULL;
|
dst = dst->next;
|
||||||
memcpy(m, (void *)pbpage, PAGE_SIZE);
|
src = src->next;
|
||||||
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() */
|
|
||||||
for_each_pb_page (pbpage, pblist) {
|
|
||||||
SetPageNosave(virt_to_page(pbpage));
|
|
||||||
SetPageNosaveFree(virt_to_page(pbpage));
|
|
||||||
}
|
|
||||||
|
|
||||||
printk("swsusp: Relocated %d pages\n", rel);
|
|
||||||
|
|
||||||
return pblist;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -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 */
|
||||||
|
Reference in New Issue
Block a user