Commit 2c22f5c8 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] swsusp update: supports discontingmem/highmem fixes

From: Pavel Machek <pavel@ucw.cz>

It makes swsusp behave correctly w.r.t.  discontingmem, and adds highmem
handling.
parent 69a03ded
.text .text
/* Originally gcc generated, modified by hand */ /* Originally gcc generated, modified by hand
*
* This may not use any stack, nor any variable that is not "NoSave":
*
* Its rewriting one kernel image with another. What is stack in "old"
* image could very well be data page in "new" image, and overwriting
* your own stack under you is bad idea.
*/
#include <linux/linkage.h> #include <linux/linkage.h>
#include <asm/segment.h> #include <asm/segment.h>
......
...@@ -225,7 +225,7 @@ static void mark_swapfiles(swp_entry_t prev, int mode) ...@@ -225,7 +225,7 @@ static void mark_swapfiles(swp_entry_t prev, int mode)
static void read_swapfiles(void) /* This is called before saving image */ static void read_swapfiles(void) /* This is called before saving image */
{ {
int i, len; int i, len;
char buff[sizeof(resume_file)], *sname; static char buff[sizeof(resume_file)], *sname;
len=strlen(resume_file); len=strlen(resume_file);
root_swap = 0xFFFF; root_swap = 0xFFFF;
...@@ -366,6 +366,7 @@ static int write_suspend_image(void) ...@@ -366,6 +366,7 @@ static int write_suspend_image(void)
return 0; return 0;
} }
#ifdef CONFIG_HIGHMEM
struct highmem_page { struct highmem_page {
char *data; char *data;
struct page *page; struct page *page;
...@@ -374,7 +375,7 @@ struct highmem_page { ...@@ -374,7 +375,7 @@ struct highmem_page {
struct highmem_page *highmem_copy = NULL; struct highmem_page *highmem_copy = NULL;
static void save_highmem_zone(struct zone *zone) static int save_highmem_zone(struct zone *zone)
{ {
unsigned long zone_pfn; unsigned long zone_pfn;
for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn) { for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn) {
...@@ -384,7 +385,7 @@ static void save_highmem_zone(struct zone *zone) ...@@ -384,7 +385,7 @@ static void save_highmem_zone(struct zone *zone)
unsigned long pfn = zone_pfn + zone->zone_start_pfn; unsigned long pfn = zone_pfn + zone->zone_start_pfn;
int chunk_size; int chunk_size;
if (!(pfn%200)) if (!(pfn%1000))
printk("."); printk(".");
if (!pfn_valid(pfn)) if (!pfn_valid(pfn))
continue; continue;
...@@ -397,7 +398,7 @@ static void save_highmem_zone(struct zone *zone) ...@@ -397,7 +398,7 @@ static void save_highmem_zone(struct zone *zone)
*/ */
if (PageReserved(page)) { if (PageReserved(page)) {
printk("highmem reserved page?!\n"); printk("highmem reserved page?!\n");
BUG(); continue;
} }
if ((chunk_size = is_head_of_free_region(page))) { if ((chunk_size = is_head_of_free_region(page))) {
pfn += chunk_size - 1; pfn += chunk_size - 1;
...@@ -406,26 +407,33 @@ static void save_highmem_zone(struct zone *zone) ...@@ -406,26 +407,33 @@ static void save_highmem_zone(struct zone *zone)
} }
save = kmalloc(sizeof(struct highmem_page), GFP_ATOMIC); save = kmalloc(sizeof(struct highmem_page), GFP_ATOMIC);
if (!save) if (!save)
panic("Not enough memory"); return -ENOMEM;
save->next = highmem_copy; save->next = highmem_copy;
save->page = page; save->page = page;
save->data = (void *) get_zeroed_page(GFP_ATOMIC); save->data = (void *) get_zeroed_page(GFP_ATOMIC);
if (!save->data) if (!save->data) {
panic("Not enough memory"); kfree(save);
return -ENOMEM;
}
kaddr = kmap_atomic(page, KM_USER0); kaddr = kmap_atomic(page, KM_USER0);
memcpy(save->data, kaddr, PAGE_SIZE); memcpy(save->data, kaddr, PAGE_SIZE);
kunmap_atomic(kaddr, KM_USER0); kunmap_atomic(kaddr, KM_USER0);
highmem_copy = save; highmem_copy = save;
} }
return 0;
} }
static void save_highmem(void) static int save_highmem(void)
{ {
struct zone *zone; struct zone *zone;
int res = 0;
for_each_zone(zone) { for_each_zone(zone) {
if (is_highmem(zone)) if (is_highmem(zone))
save_highmem_zone(zone); res = save_highmem_zone(zone);
if (res)
return res;
} }
return 0;
} }
static int restore_highmem(void) static int restore_highmem(void)
...@@ -443,6 +451,7 @@ static int restore_highmem(void) ...@@ -443,6 +451,7 @@ static int restore_highmem(void)
} }
return 0; return 0;
} }
#endif
static int pfn_is_nosave(unsigned long pfn) static int pfn_is_nosave(unsigned long pfn)
{ {
...@@ -460,7 +469,7 @@ static int count_and_copy_zone(struct zone *zone, struct pbe **pagedir_p) ...@@ -460,7 +469,7 @@ static int count_and_copy_zone(struct zone *zone, struct pbe **pagedir_p)
struct page *page; struct page *page;
unsigned long pfn = zone_pfn + zone->zone_start_pfn; unsigned long pfn = zone_pfn + zone->zone_start_pfn;
if (!(pfn%200)) if (!(pfn%1000))
printk("."); printk(".");
if (!pfn_valid(pfn)) if (!pfn_valid(pfn))
continue; continue;
...@@ -548,7 +557,7 @@ static suspend_pagedir_t *create_suspend_pagedir(int nr_copy_pages) ...@@ -548,7 +557,7 @@ static suspend_pagedir_t *create_suspend_pagedir(int nr_copy_pages)
while(nr_copy_pages--) { while(nr_copy_pages--) {
p->address = get_zeroed_page(GFP_ATOMIC | __GFP_COLD); p->address = get_zeroed_page(GFP_ATOMIC | __GFP_COLD);
if(!p->address) { if (!p->address) {
free_suspend_pagedir((unsigned long) pagedir); free_suspend_pagedir((unsigned long) pagedir);
return NULL; return NULL;
} }
...@@ -589,10 +598,17 @@ static int suspend_prepare_image(void) ...@@ -589,10 +598,17 @@ static int suspend_prepare_image(void)
unsigned int nr_needed_pages = 0; unsigned int nr_needed_pages = 0;
pagedir_nosave = NULL; pagedir_nosave = NULL;
printk( "/critical section: Handling highmem" ); printk( "/critical section: ");
save_highmem(); #ifdef CONFIG_HIGHMEM
printk( "handling highmem" );
if (save_highmem()) {
printk(KERN_CRIT "%sNot enough free pages for highmem\n", name_suspend);
return -ENOMEM;
}
printk(", ");
#endif
printk(", counting pages to copy" ); printk("counting pages to copy" );
drain_local_pages(); drain_local_pages();
nr_copy_pages = count_and_copy_data_pages(NULL); nr_copy_pages = count_and_copy_data_pages(NULL);
nr_needed_pages = nr_copy_pages + PAGES_FOR_IO; nr_needed_pages = nr_copy_pages + PAGES_FOR_IO;
...@@ -602,23 +618,22 @@ static int suspend_prepare_image(void) ...@@ -602,23 +618,22 @@ static int suspend_prepare_image(void)
printk(KERN_CRIT "%sCouldn't get enough free pages, on %d pages short\n", printk(KERN_CRIT "%sCouldn't get enough free pages, on %d pages short\n",
name_suspend, nr_needed_pages-nr_free_pages()); name_suspend, nr_needed_pages-nr_free_pages());
root_swap = 0xFFFF; root_swap = 0xFFFF;
return 1; return -ENOMEM;
} }
si_swapinfo(&i); /* FIXME: si_swapinfo(&i) returns all swap devices information. si_swapinfo(&i); /* FIXME: si_swapinfo(&i) returns all swap devices information.
We should only consider resume_device. */ We should only consider resume_device. */
if (i.freeswap < nr_needed_pages) { if (i.freeswap < nr_needed_pages) {
printk(KERN_CRIT "%sThere's not enough swap space available, on %ld pages short\n", printk(KERN_CRIT "%sThere's not enough swap space available, on %ld pages short\n",
name_suspend, nr_needed_pages-i.freeswap); name_suspend, nr_needed_pages-i.freeswap);
return 1; return -ENOSPC;
} }
PRINTK( "Alloc pagedir\n" ); PRINTK( "Alloc pagedir\n" );
pagedir_save = pagedir_nosave = create_suspend_pagedir(nr_copy_pages); pagedir_save = pagedir_nosave = create_suspend_pagedir(nr_copy_pages);
if(!pagedir_nosave) { if (!pagedir_nosave) {
/* Shouldn't happen */ /* Pagedir is big, one-chunk allocation. It is easily possible for this allocation to fail */
printk(KERN_CRIT "%sCouldn't allocate enough pages\n",name_suspend); printk(KERN_CRIT "%sCouldn't allocate continuous pagedir\n", name_suspend);
panic("Really should not happen"); return -ENOMEM;
return 1;
} }
nr_copy_pages_check = nr_copy_pages; nr_copy_pages_check = nr_copy_pages;
pagedir_order_check = pagedir_order; pagedir_order_check = pagedir_order;
...@@ -702,8 +717,10 @@ asmlinkage void do_magic_resume_2(void) ...@@ -702,8 +717,10 @@ asmlinkage void do_magic_resume_2(void)
PRINTK( "Freeing prev allocated pagedir\n" ); PRINTK( "Freeing prev allocated pagedir\n" );
free_suspend_pagedir((unsigned long) pagedir_save); free_suspend_pagedir((unsigned long) pagedir_save);
#ifdef CONFIG_HIGHMEM
printk( "Restoring highmem\n" ); printk( "Restoring highmem\n" );
restore_highmem(); restore_highmem();
#endif
printk("done, devices\n"); printk("done, devices\n");
device_power_up(); device_power_up();
......
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