Commit d324cd65 authored by Patrick Mochel's avatar Patrick Mochel

[Power Mgmt] Merge first part of image writing code.

- Introduce helpers to swsusp - swsusp_write_page(), swsusp_data_write() and
  swsusp_data_free(). 
- Delete duplicate copies from pmdisk and fixup names in calls. 
- Clean up write_suspend_image() in swsusp and use the helpers.
parent 13c9f31a
...@@ -138,85 +138,9 @@ static int mark_swapfiles(swp_entry_t prev) ...@@ -138,85 +138,9 @@ static int mark_swapfiles(swp_entry_t prev)
return error; return error;
} }
extern int swsusp_write_page(unsigned long addr, swp_entry_t * entry);
extern int swsusp_data_write(void);
/** extern void swsusp_data_free(void);
* write_swap_page - Write one page to a fresh swap location.
* @addr: Address we're writing.
* @loc: Place to store the entry we used.
*
* Allocate a new swap entry and 'sync' it. Note we discard -EIO
* errors. That is an artifact left over from swsusp. It did not
* check the return of rw_swap_page_sync() at all, since most pages
* written back to swap would return -EIO.
* This is a partial improvement, since we will at least return other
* errors, though we need to eventually fix the damn code.
*/
static int write_swap_page(unsigned long addr, swp_entry_t * loc)
{
swp_entry_t entry;
int error = 0;
entry = get_swap_page();
if (swp_offset(entry) &&
swapfile_used[swp_type(entry)] == SWAPFILE_SUSPEND) {
error = rw_swap_page_sync(WRITE, entry,
virt_to_page(addr));
if (error == -EIO)
error = 0;
if (!error)
*loc = entry;
} else
error = -ENOSPC;
return error;
}
/**
* free_data - Free the swap entries used by the saved image.
*
* Walk the list of used swap entries and free each one.
*/
static void free_data(void)
{
swp_entry_t entry;
int i;
for (i = 0; i < nr_copy_pages; i++) {
entry = (pagedir_nosave + i)->swap_address;
if (entry.val)
swap_free(entry);
else
break;
(pagedir_nosave + i)->swap_address = (swp_entry_t){0};
}
}
/**
* write_data - Write saved image to swap.
*
* Walk the list of pages in the image and sync each one to swap.
*/
static int write_data(void)
{
int error = 0;
int i;
printk( "Writing data to swap (%d pages): ", nr_copy_pages );
for (i = 0; i < nr_copy_pages && !error; i++) {
if (!(i%100))
printk( "." );
error = write_swap_page((pagedir_nosave+i)->address,
&((pagedir_nosave+i)->swap_address));
}
printk(" %d Pages done.\n",i);
return error;
}
/** /**
* free_pagedir - Free pages used by the page directory. * free_pagedir - Free pages used by the page directory.
...@@ -247,7 +171,7 @@ static int write_pagedir(void) ...@@ -247,7 +171,7 @@ static int write_pagedir(void)
pmdisk_info.pagedir_pages = n; pmdisk_info.pagedir_pages = n;
printk( "Writing pagedir (%d pages)\n", n); printk( "Writing pagedir (%d pages)\n", n);
for (i = 0; i < n && !error; i++, addr += PAGE_SIZE) for (i = 0; i < n && !error; i++, addr += PAGE_SIZE)
error = write_swap_page(addr,&pmdisk_info.pagedir[i]); error = swsusp_write_page(addr,&pmdisk_info.pagedir[i]);
return error; return error;
} }
...@@ -283,6 +207,7 @@ static void init_header(void) ...@@ -283,6 +207,7 @@ static void init_header(void)
pmdisk_info.cpus = num_online_cpus(); pmdisk_info.cpus = num_online_cpus();
pmdisk_info.image_pages = nr_copy_pages; pmdisk_info.image_pages = nr_copy_pages;
dump_pmdisk_info();
} }
/** /**
...@@ -297,8 +222,7 @@ static void init_header(void) ...@@ -297,8 +222,7 @@ static void init_header(void)
static int write_header(swp_entry_t * entry) static int write_header(swp_entry_t * entry)
{ {
dump_pmdisk_info(); return swsusp_write_page((unsigned long)&pmdisk_info,entry);
return write_swap_page((unsigned long)&pmdisk_info,entry);
} }
...@@ -313,9 +237,7 @@ static int write_suspend_image(void) ...@@ -313,9 +237,7 @@ static int write_suspend_image(void)
int error; int error;
swp_entry_t prev = { 0 }; swp_entry_t prev = { 0 };
init_header(); if ((error = swsusp_data_write()))
if ((error = write_data()))
goto FreeData; goto FreeData;
if ((error = write_pagedir())) if ((error = write_pagedir()))
...@@ -330,7 +252,7 @@ static int write_suspend_image(void) ...@@ -330,7 +252,7 @@ static int write_suspend_image(void)
FreePagedir: FreePagedir:
free_pagedir_entries(); free_pagedir_entries();
FreeData: FreeData:
free_data(); swsusp_data_free();
goto Done; goto Done;
} }
......
...@@ -295,6 +295,87 @@ void swsusp_swap_lock(void) ...@@ -295,6 +295,87 @@ void swsusp_swap_lock(void)
swap_list_unlock(); swap_list_unlock();
} }
/**
* write_swap_page - Write one page to a fresh swap location.
* @addr: Address we're writing.
* @loc: Place to store the entry we used.
*
* Allocate a new swap entry and 'sync' it. Note we discard -EIO
* errors. That is an artifact left over from swsusp. It did not
* check the return of rw_swap_page_sync() at all, since most pages
* written back to swap would return -EIO.
* This is a partial improvement, since we will at least return other
* errors, though we need to eventually fix the damn code.
*/
int swsusp_write_page(unsigned long addr, swp_entry_t * loc)
{
swp_entry_t entry;
int error = 0;
entry = get_swap_page();
if (swp_offset(entry) &&
swapfile_used[swp_type(entry)] == SWAPFILE_SUSPEND) {
error = rw_swap_page_sync(WRITE, entry,
virt_to_page(addr));
if (error == -EIO)
error = 0;
if (!error)
*loc = entry;
} else
error = -ENOSPC;
return error;
}
/**
* free_data - Free the swap entries used by the saved image.
*
* Walk the list of used swap entries and free each one.
*/
void swsusp_data_free(void)
{
swp_entry_t entry;
int i;
for (i = 0; i < nr_copy_pages; i++) {
entry = (pagedir_nosave + i)->swap_address;
if (entry.val)
swap_free(entry);
else
break;
(pagedir_nosave + i)->swap_address = (swp_entry_t){0};
}
}
/**
* write_data - Write saved image to swap.
*
* Walk the list of pages in the image and sync each one to swap.
*/
int swsusp_data_write(void)
{
int error = 0;
int i;
printk( "Writing data to swap (%d pages): ", nr_copy_pages );
for (i = 0; i < nr_copy_pages && !error; i++) {
if (!(i%100))
printk( "." );
error = swsusp_write_page((pagedir_nosave+i)->address,
&((pagedir_nosave+i)->swap_address));
}
printk(" %d Pages done.\n",i);
return error;
}
/** /**
* write_suspend_image - Write entire image to disk. * write_suspend_image - Write entire image to disk.
* *
...@@ -309,78 +390,39 @@ void swsusp_swap_lock(void) ...@@ -309,78 +390,39 @@ void swsusp_swap_lock(void)
static int write_suspend_image(void) static int write_suspend_image(void)
{ {
int i; int i;
swp_entry_t entry, prev = { 0 }; int error = 0;
swp_entry_t entry = { 0 };
int nr_pgdir_pages = SUSPEND_PD_PAGES(nr_copy_pages); int nr_pgdir_pages = SUSPEND_PD_PAGES(nr_copy_pages);
union diskpage *cur, *buffer = (union diskpage *)get_zeroed_page(GFP_ATOMIC); union diskpage *cur, *buffer = (union diskpage *)get_zeroed_page(GFP_ATOMIC);
unsigned long address; unsigned long addr;
struct page *page;
if (!buffer) if (!buffer)
return -ENOMEM; return -ENOMEM;
printk( "Writing data to swap (%d pages): ", nr_copy_pages ); swsusp_data_write();
for (i=0; i<nr_copy_pages; i++) {
if (!(i%100))
printk( "." );
entry = get_swap_page();
if (!entry.val)
panic("\nNot enough swapspace when writing data" );
if (swapfile_used[swp_type(entry)] != SWAPFILE_SUSPEND)
panic("\nPage %d: not enough swapspace on suspend device", i );
address = (pagedir_nosave+i)->address;
page = virt_to_page(address);
rw_swap_page_sync(WRITE, entry, page);
(pagedir_nosave+i)->swap_address = entry;
}
printk( "|\n" );
printk( "Writing pagedir (%d pages): ", nr_pgdir_pages); printk( "Writing pagedir (%d pages): ", nr_pgdir_pages);
for (i=0; i<nr_pgdir_pages; i++) { addr = (unsigned long)pagedir_nosave;
cur = (union diskpage *)((char *) pagedir_nosave)+i; for (i=0; i<nr_pgdir_pages && !error; i++, addr += PAGE_SIZE) {
BUG_ON ((char *) cur != (((char *) pagedir_nosave) + i*PAGE_SIZE)); cur = (union diskpage *)addr;
cur->link.next = entry;
printk( "." ); printk( "." );
entry = get_swap_page(); error = swsusp_write_page(addr,&entry);
if (!entry.val) {
printk(KERN_CRIT "Not enough swapspace when writing pgdir\n" );
panic("Don't know how to recover");
free_page((unsigned long) buffer);
return -ENOSPC;
}
if(swapfile_used[swp_type(entry)] != SWAPFILE_SUSPEND)
panic("\nNot enough swapspace for pagedir on suspend device" );
BUG_ON (sizeof(swp_entry_t) != sizeof(long));
BUG_ON (PAGE_SIZE % sizeof(struct pbe));
cur->link.next = prev;
page = virt_to_page((unsigned long)cur);
rw_swap_page_sync(WRITE, entry, page);
prev = entry;
} }
printk("H"); printk("H");
BUG_ON (sizeof(struct suspend_header) > PAGE_SIZE-sizeof(swp_entry_t)); BUG_ON (sizeof(struct suspend_header) > PAGE_SIZE-sizeof(swp_entry_t));
BUG_ON (sizeof(union diskpage) != PAGE_SIZE); BUG_ON (sizeof(union diskpage) != PAGE_SIZE);
BUG_ON (sizeof(struct link) != PAGE_SIZE); BUG_ON (sizeof(struct link) != PAGE_SIZE);
entry = get_swap_page();
if (!entry.val)
panic( "\nNot enough swapspace when writing header" );
if (swapfile_used[swp_type(entry)] != SWAPFILE_SUSPEND)
panic("\nNot enough swapspace for header on suspend device" );
cur = (void *) buffer; cur = (void *) buffer;
if (fill_suspend_header(&cur->sh)) if (fill_suspend_header(&cur->sh))
BUG(); /* Not a BUG_ON(): we want fill_suspend_header to be called, always */ BUG(); /* Not a BUG_ON(): we want fill_suspend_header to be called, always */
cur->link.next = prev; cur->link.next = entry;
if ((error = swsusp_write_page((unsigned long)cur,&entry)))
page = virt_to_page((unsigned long)cur); return error;
rw_swap_page_sync(WRITE, entry, page);
prev = entry;
printk( "S" ); printk( "S" );
mark_swapfiles(prev, MARK_SWAP_SUSPEND); mark_swapfiles(entry, MARK_SWAP_SUSPEND);
printk( "|\n" ); printk( "|\n" );
MDELAY(1000); MDELAY(1000);
......
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