Commit 7c548885 authored by Pavel Machek's avatar Pavel Machek Committed by Linus Torvalds

[PATCH] swsusp: 64-bit compatibility

This makes swsusp 64bit compatible, and makes it work in case of two
mirrors of physical memory (x86-64 works like that). It also contains
few accumulated cleanups.
parent ba95d79a
...@@ -80,9 +80,9 @@ unsigned char software_suspend_enabled = 0; ...@@ -80,9 +80,9 @@ unsigned char software_suspend_enabled = 0;
#endif #endif
#define TIMEOUT (6 * HZ) /* Timeout for stopping processes */ #define TIMEOUT (6 * HZ) /* Timeout for stopping processes */
#define ADDRESS(x) ((unsigned long) phys_to_virt(((x) << PAGE_SHIFT))) #define __ADDRESS(x) ((unsigned long) phys_to_virt(x))
#define ADDRESS(x) __ADDRESS((x) << PAGE_SHIFT)
extern int C_A_D; #define ADDRESS2(x) __ADDRESS(__pa(x)) /* Needed for x86-64 where some pages are in memory twice */
/* References to section boundaries */ /* References to section boundaries */
extern char _text, _etext, _edata, __bss_start, _end; extern char _text, _etext, _edata, __bss_start, _end;
...@@ -145,10 +145,10 @@ static const char name_resume[] = "Resume Machine: "; ...@@ -145,10 +145,10 @@ static const char name_resume[] = "Resume Machine: ";
/* /*
* Debug * Debug
*/ */
#undef DEBUG_DEFAULT #define DEBUG_DEFAULT
#undef DEBUG_PROCESS #undef DEBUG_PROCESS
#undef DEBUG_SLOW #undef DEBUG_SLOW
#define TEST_SWSUSP 1 /* Set to 1 to reboot instead of halt machine after suspension */ #define TEST_SWSUSP 0 /* Set to 1 to reboot instead of halt machine after suspension */
#ifdef DEBUG_DEFAULT #ifdef DEBUG_DEFAULT
# define PRINTK(f, a...) printk(f, ## a) # define PRINTK(f, a...) printk(f, ## a)
...@@ -235,6 +235,7 @@ int freeze_processes(void) ...@@ -235,6 +235,7 @@ int freeze_processes(void)
} while(todo); } while(todo);
printk( "|\n" ); printk( "|\n" );
BUG_ON(in_atomic());
return 0; return 0;
} }
...@@ -322,20 +323,20 @@ static void mark_swapfiles(swp_entry_t prev, int mode) ...@@ -322,20 +323,20 @@ static void mark_swapfiles(swp_entry_t prev, int mode)
rw_swap_page_sync(READ, entry, page); rw_swap_page_sync(READ, entry, page);
if (mode == MARK_SWAP_RESUME) { if (mode == MARK_SWAP_RESUME) {
if (!memcmp("SUSP1R",cur->swh.magic.magic,6)) if (!memcmp("S1",cur->swh.magic.magic,2))
memcpy(cur->swh.magic.magic,"SWAP-SPACE",10); memcpy(cur->swh.magic.magic,"SWAP-SPACE",10);
else if (!memcmp("SUSP2R",cur->swh.magic.magic,6)) else if (!memcmp("S2",cur->swh.magic.magic,2))
memcpy(cur->swh.magic.magic,"SWAPSPACE2",10); memcpy(cur->swh.magic.magic,"SWAPSPACE2",10);
else printk("%sUnable to find suspended-data signature (%.10s - misspelled?\n", else printk("%sUnable to find suspended-data signature (%.10s - misspelled?\n",
name_resume, cur->swh.magic.magic); name_resume, cur->swh.magic.magic);
} else { } else {
if ((!memcmp("SWAP-SPACE",cur->swh.magic.magic,10))) if ((!memcmp("SWAP-SPACE",cur->swh.magic.magic,10)))
memcpy(cur->swh.magic.magic,"SUSP1R....",10); memcpy(cur->swh.magic.magic,"S1SUSP....",10);
else if ((!memcmp("SWAPSPACE2",cur->swh.magic.magic,10))) else if ((!memcmp("SWAPSPACE2",cur->swh.magic.magic,10)))
memcpy(cur->swh.magic.magic,"SUSP2R....",10); memcpy(cur->swh.magic.magic,"S2SUSP....",10);
else panic("\nSwapspace is not swapspace (%.10s)\n", cur->swh.magic.magic); else panic("\nSwapspace is not swapspace (%.10s)\n", cur->swh.magic.magic);
cur->link.next = prev; /* prev is the first/last swap page of the resume area */ cur->link.next = prev; /* prev is the first/last swap page of the resume area */
/* link.next lies *no more* in last 4 bytes of magic */ /* link.next lies *no more* in last 4/8 bytes of magic */
} }
rw_swap_page_sync(WRITE, entry, page); rw_swap_page_sync(WRITE, entry, page);
__free_page(page); __free_page(page);
...@@ -489,7 +490,6 @@ static int count_and_copy_data_pages(struct pbe *pagedir_p) ...@@ -489,7 +490,6 @@ static int count_and_copy_data_pages(struct pbe *pagedir_p)
if (PageNosave(page)) if (PageNosave(page))
continue; continue;
if ((chunk_size=is_head_of_free_region(page))!=0) { if ((chunk_size=is_head_of_free_region(page))!=0) {
pfn += chunk_size - 1; pfn += chunk_size - 1;
continue; continue;
...@@ -500,10 +500,9 @@ static int count_and_copy_data_pages(struct pbe *pagedir_p) ...@@ -500,10 +500,9 @@ static int count_and_copy_data_pages(struct pbe *pagedir_p)
/* /*
* Just copy whole code segment. Hopefully it is not that big. * Just copy whole code segment. Hopefully it is not that big.
*/ */
if (ADDRESS(pfn) >= (unsigned long) if ((ADDRESS(pfn) >= (unsigned long) ADDRESS2(&__nosave_begin)) &&
&__nosave_begin && ADDRESS(pfn) < (ADDRESS(pfn) < (unsigned long) ADDRESS2(&__nosave_end))) {
(unsigned long)&__nosave_end) { PRINTK("[nosave %lx]", ADDRESS(pfn));
PRINTK("[nosave %x]", ADDRESS(pfn));
continue; continue;
} }
/* Hmm, perhaps copying all reserved pages is not too healthy as they may contain /* Hmm, perhaps copying all reserved pages is not too healthy as they may contain
...@@ -513,7 +512,7 @@ static int count_and_copy_data_pages(struct pbe *pagedir_p) ...@@ -513,7 +512,7 @@ static int count_and_copy_data_pages(struct pbe *pagedir_p)
nr_copy_pages++; nr_copy_pages++;
if (pagedir_p) { if (pagedir_p) {
pagedir_p->orig_address = ADDRESS(pfn); pagedir_p->orig_address = ADDRESS(pfn);
copy_page(pagedir_p->address, pagedir_p->orig_address); copy_page((void *) pagedir_p->address, (void *) pagedir_p->orig_address);
pagedir_p++; pagedir_p++;
} }
} }
...@@ -549,7 +548,7 @@ static suspend_pagedir_t *create_suspend_pagedir(int nr_copy_pages) ...@@ -549,7 +548,7 @@ static suspend_pagedir_t *create_suspend_pagedir(int nr_copy_pages)
pagedir_order = get_bitmask_order(SUSPEND_PD_PAGES(nr_copy_pages)); pagedir_order = get_bitmask_order(SUSPEND_PD_PAGES(nr_copy_pages));
p = pagedir = (suspend_pagedir_t *)__get_free_pages(GFP_ATOMIC, pagedir_order); p = pagedir = (suspend_pagedir_t *)__get_free_pages(GFP_ATOMIC | __GFP_COLD, pagedir_order);
if(!pagedir) if(!pagedir)
return NULL; return NULL;
...@@ -558,11 +557,12 @@ static suspend_pagedir_t *create_suspend_pagedir(int nr_copy_pages) ...@@ -558,11 +557,12 @@ static suspend_pagedir_t *create_suspend_pagedir(int nr_copy_pages)
SetPageNosave(page++); SetPageNosave(page++);
while(nr_copy_pages--) { while(nr_copy_pages--) {
p->address = get_zeroed_page(GFP_ATOMIC); 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;
} }
printk(".");
SetPageNosave(virt_to_page(p->address)); SetPageNosave(virt_to_page(p->address));
p->orig_address = 0; p->orig_address = 0;
p++; p++;
...@@ -623,7 +623,7 @@ static int prepare_suspend_processes(void) ...@@ -623,7 +623,7 @@ static int prepare_suspend_processes(void)
static void free_some_memory(void) static void free_some_memory(void)
{ {
printk("Freeing memory: "); printk("Freeing memory: ");
while (try_to_free_pages(&contig_page_data.node_zones[ZONE_HIGHMEM], GFP_KSWAPD, 0)) while (shrink_all_memory(10000))
printk("."); printk(".");
printk("|\n"); printk("|\n");
} }
...@@ -676,7 +676,7 @@ static void drivers_resume(int flags) ...@@ -676,7 +676,7 @@ static void drivers_resume(int flags)
} }
} }
static int suspend_save_image(void) static int suspend_prepare_image(void)
{ {
struct sysinfo i; struct sysinfo i;
unsigned int nr_needed_pages = 0; unsigned int nr_needed_pages = 0;
...@@ -725,9 +725,15 @@ static int suspend_save_image(void) ...@@ -725,9 +725,15 @@ static int suspend_save_image(void)
* *
* Following line enforces not writing to disk until we choose. * Following line enforces not writing to disk until we choose.
*/ */
drivers_unsuspend();
spin_unlock_irq(&suspend_pagedir_lock);
printk( "critical section/: done (%d pages copied)\n", nr_copy_pages ); printk( "critical section/: done (%d pages copied)\n", nr_copy_pages );
spin_unlock_irq(&suspend_pagedir_lock);
return 0;
}
static void suspend_save_image(void)
{
drivers_unsuspend();
lock_swapdevices(); lock_swapdevices();
write_suspend_image(); write_suspend_image();
...@@ -738,11 +744,11 @@ static int suspend_save_image(void) ...@@ -738,11 +744,11 @@ static int suspend_save_image(void)
* filesystem clean: it is not. (And it does not matter, if we resume * filesystem clean: it is not. (And it does not matter, if we resume
* correctly, we'll mark system clean, anyway.) * correctly, we'll mark system clean, anyway.)
*/ */
return 0;
} }
void suspend_power_down(void) static void suspend_power_down(void)
{ {
extern int C_A_D;
C_A_D = 0; C_A_D = 0;
printk(KERN_EMERG "%s%s Trying to power down.\n", name_suspend, TEST_SWSUSP ? "Disable TEST_SWSUSP. NOT ": ""); printk(KERN_EMERG "%s%s Trying to power down.\n", name_suspend, TEST_SWSUSP ? "Disable TEST_SWSUSP. NOT ": "");
#ifdef CONFIG_VT #ifdef CONFIG_VT
...@@ -788,8 +794,8 @@ void do_magic_resume_2(void) ...@@ -788,8 +794,8 @@ 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);
drivers_resume(RESUME_ALL_PHASES);
spin_unlock_irq(&suspend_pagedir_lock); spin_unlock_irq(&suspend_pagedir_lock);
drivers_resume(RESUME_ALL_PHASES);
PRINTK( "Fixing swap signatures... " ); PRINTK( "Fixing swap signatures... " );
mark_swapfiles(((swp_entry_t) {0}), MARK_SWAP_RESUME); mark_swapfiles(((swp_entry_t) {0}), MARK_SWAP_RESUME);
...@@ -804,14 +810,17 @@ void do_magic_suspend_1(void) ...@@ -804,14 +810,17 @@ void do_magic_suspend_1(void)
{ {
mb(); mb();
barrier(); barrier();
BUG_ON(in_atomic());
spin_lock_irq(&suspend_pagedir_lock); spin_lock_irq(&suspend_pagedir_lock);
} }
void do_magic_suspend_2(void) void do_magic_suspend_2(void)
{ {
read_swapfiles(); read_swapfiles();
if (!suspend_save_image()) if (!suspend_prepare_image()) { /* suspend_save_image realeses suspend_pagedir_lock */
suspend_save_image();
suspend_power_down(); /* FIXME: if suspend_power_down is commented out, console is lost after few suspends ?! */ suspend_power_down(); /* FIXME: if suspend_power_down is commented out, console is lost after few suspends ?! */
}
printk(KERN_EMERG "%sSuspend failed, trying to recover...\n", name_suspend); printk(KERN_EMERG "%sSuspend failed, trying to recover...\n", name_suspend);
MDELAY(1000); /* So user can wait and report us messages if armageddon comes :-) */ MDELAY(1000); /* So user can wait and report us messages if armageddon comes :-) */
...@@ -827,7 +836,7 @@ void do_magic_suspend_2(void) ...@@ -827,7 +836,7 @@ void do_magic_suspend_2(void)
PRINTK(KERN_WARNING "%sLeaving do_magic_suspend_2...\n", name_suspend); PRINTK(KERN_WARNING "%sLeaving do_magic_suspend_2...\n", name_suspend);
} }
void do_software_suspend(void) static void do_software_suspend(void)
{ {
arch_prepare_suspend(); arch_prepare_suspend();
if (prepare_suspend_console()) if (prepare_suspend_console())
...@@ -1069,9 +1078,9 @@ static int __read_suspend_image(struct block_device *bdev, union diskpage *cur, ...@@ -1069,9 +1078,9 @@ static int __read_suspend_image(struct block_device *bdev, union diskpage *cur,
PREPARENEXT; /* We have to read next position before we overwrite it */ PREPARENEXT; /* We have to read next position before we overwrite it */
if (!memcmp("SUSP1R",cur->swh.magic.magic,6)) if (!memcmp("S1",cur->swh.magic.magic,2))
memcpy(cur->swh.magic.magic,"SWAP-SPACE",10); memcpy(cur->swh.magic.magic,"SWAP-SPACE",10);
else if (!memcmp("SUSP2R",cur->swh.magic.magic,6)) else if (!memcmp("S2",cur->swh.magic.magic,2))
memcpy(cur->swh.magic.magic,"SWAPSPACE2",10); memcpy(cur->swh.magic.magic,"SWAPSPACE2",10);
else { else {
panic("%sUnable to find suspended-data signature (%.10s - misspelled?\n", panic("%sUnable to find suspended-data signature (%.10s - misspelled?\n",
......
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