summaryrefslogtreecommitdiffstats
path: root/kernel/power
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/power')
-rw-r--r--kernel/power/power.h1
-rw-r--r--kernel/power/swsusp.c190
2 files changed, 65 insertions, 126 deletions
diff --git a/kernel/power/power.h b/kernel/power/power.h
index 273a5b1d70be..7e8492fd1423 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -16,7 +16,6 @@ struct swsusp_info {
int cpus;
unsigned long image_pages;
unsigned long pages;
- swp_entry_t start;
} __attribute__((aligned(PAGE_SIZE)));
diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c
index 0479c9be7d71..55a18d26abed 100644
--- a/kernel/power/swsusp.c
+++ b/kernel/power/swsusp.c
@@ -93,7 +93,7 @@ extern char resume_file[];
static struct swsusp_header {
char reserved[PAGE_SIZE - 20 - sizeof(swp_entry_t)];
- swp_entry_t swsusp_info;
+ swp_entry_t image;
char orig_sig[10];
char sig[10];
} __attribute__((packed, aligned(PAGE_SIZE))) swsusp_header;
@@ -106,7 +106,7 @@ static struct swsusp_info swsusp_info;
static unsigned short root_swap = 0xffff;
-static int mark_swapfiles(swp_entry_t prev)
+static int mark_swapfiles(swp_entry_t start)
{
int error;
@@ -117,7 +117,7 @@ static int mark_swapfiles(swp_entry_t prev)
!memcmp("SWAPSPACE2",swsusp_header.sig, 10)) {
memcpy(swsusp_header.orig_sig,swsusp_header.sig, 10);
memcpy(swsusp_header.sig,SWSUSP_SIG, 10);
- swsusp_header.swsusp_info = prev;
+ swsusp_header.image = start;
error = rw_swap_page_sync(WRITE,
swp_entry(root_swap, 0),
virt_to_page((unsigned long)
@@ -423,22 +423,7 @@ static void init_header(unsigned int nr_pages)
swsusp_info.cpus = num_online_cpus();
swsusp_info.image_pages = nr_pages;
swsusp_info.pages = nr_pages +
- ((nr_pages * sizeof(long) + PAGE_SIZE - 1) >> PAGE_SHIFT);
-}
-
-static int close_swap(void)
-{
- swp_entry_t entry;
- int error;
-
- dump_info();
- error = write_page((unsigned long)&swsusp_info, &entry);
- if (!error) {
- printk( "S" );
- error = mark_swapfiles(entry);
- printk( "|\n" );
- }
- return error;
+ ((nr_pages * sizeof(long) + PAGE_SIZE - 1) >> PAGE_SHIFT) + 1;
}
/**
@@ -522,6 +507,7 @@ int swsusp_write(struct pbe *pblist, unsigned int nr_pages)
{
struct swap_map_page *swap_map;
struct swap_map_handle handle;
+ swp_entry_t start;
int error;
if ((error = swsusp_swap_check())) {
@@ -539,18 +525,23 @@ int swsusp_write(struct pbe *pblist, unsigned int nr_pages)
return -ENOMEM;
init_swap_map_handle(&handle, swap_map);
- error = save_image_metadata(pblist, &handle);
+ error = swap_map_write_page(&handle, (unsigned long)&swsusp_info);
+ if (!error)
+ error = save_image_metadata(pblist, &handle);
if (!error)
error = save_image_data(pblist, &handle, nr_pages);
if (error)
goto Free_image_entries;
swap_map = reverse_swap_map(swap_map);
- error = save_swap_map(swap_map, &swsusp_info.start);
+ error = save_swap_map(swap_map, &start);
if (error)
goto Free_map_entries;
- error = close_swap();
+ dump_info();
+ printk( "S" );
+ error = mark_swapfiles(start);
+ printk( "|\n" );
if (error)
goto Free_map_entries;
@@ -840,70 +831,28 @@ static inline int swap_map_read_page(struct swap_map_handle *handle, void *buf)
return error;
}
-/*
- * Sanity check if this image makes sense with this kernel/swap context
- * I really don't think that it's foolproof but more than nothing..
- */
-
-static const char *sanity_check(void)
+static int check_header(void)
{
+ char *reason = NULL;
+
dump_info();
if (swsusp_info.version_code != LINUX_VERSION_CODE)
- return "kernel version";
+ reason = "kernel version";
if (swsusp_info.num_physpages != num_physpages)
- return "memory size";
+ reason = "memory size";
if (strcmp(swsusp_info.uts.sysname,system_utsname.sysname))
- return "system type";
+ reason = "system type";
if (strcmp(swsusp_info.uts.release,system_utsname.release))
- return "kernel release";
+ reason = "kernel release";
if (strcmp(swsusp_info.uts.version,system_utsname.version))
- return "version";
+ reason = "version";
if (strcmp(swsusp_info.uts.machine,system_utsname.machine))
- return "machine";
-#if 0
- /* We can't use number of online CPUs when we use hotplug to remove them ;-))) */
- if (swsusp_info.cpus != num_possible_cpus())
- return "number of cpus";
-#endif
- return NULL;
-}
-
-static int check_header(void)
-{
- const char *reason = NULL;
- int error;
-
- if ((error = bio_read_page(swp_offset(swsusp_header.swsusp_info), &swsusp_info)))
- return error;
-
- /* Is this same machine? */
- if ((reason = sanity_check())) {
- printk(KERN_ERR "swsusp: Resume mismatch: %s\n",reason);
+ reason = "machine";
+ if (reason) {
+ printk(KERN_ERR "swsusp: Resume mismatch: %s\n", reason);
return -EPERM;
}
- return error;
-}
-
-static int check_sig(void)
-{
- int error;
-
- memset(&swsusp_header, 0, sizeof(swsusp_header));
- if ((error = bio_read_page(0, &swsusp_header)))
- return error;
- if (!memcmp(SWSUSP_SIG, swsusp_header.sig, 10)) {
- memcpy(swsusp_header.sig, swsusp_header.orig_sig, 10);
-
- /*
- * Reset swap signature now.
- */
- error = bio_write_page(0, &swsusp_header);
- } else {
- return -EINVAL;
- }
- if (!error)
- pr_debug("swsusp: Signature found, resuming\n");
- return error;
+ return 0;
}
/**
@@ -989,33 +938,29 @@ static int load_image_metadata(struct pbe *pblist, struct swap_map_handle *handl
return error;
}
-static int check_suspend_image(void)
-{
- int error = 0;
-
- if ((error = check_sig()))
- return error;
-
- if ((error = check_header()))
- return error;
-
- return 0;
-}
-
-static int read_suspend_image(struct pbe **pblist_ptr)
+int swsusp_read(struct pbe **pblist_ptr)
{
- int error = 0;
+ int error;
struct pbe *p, *pblist;
struct swap_map_handle handle;
- unsigned int nr_pages = swsusp_info.image_pages;
+ unsigned int nr_pages;
+ if (IS_ERR(resume_bdev)) {
+ pr_debug("swsusp: block device not initialised\n");
+ return PTR_ERR(resume_bdev);
+ }
+
+ error = get_swap_map_reader(&handle, swsusp_header.image);
+ if (!error)
+ error = swap_map_read_page(&handle, &swsusp_info);
+ if (!error)
+ error = check_header();
+ if (error)
+ return error;
+ nr_pages = swsusp_info.image_pages;
p = alloc_pagedir(nr_pages, GFP_ATOMIC, 0);
if (!p)
return -ENOMEM;
- error = get_swap_map_reader(&handle, swsusp_info.start);
- if (error)
- /* The PBE list at p will be released by swsusp_free() */
- return error;
error = load_image_metadata(p, &handle);
if (!error) {
mark_unsafe_pages(p);
@@ -1037,11 +982,18 @@ static int read_suspend_image(struct pbe **pblist_ptr)
*pblist_ptr = pblist;
}
release_swap_map_reader(&handle);
+
+ blkdev_put(resume_bdev);
+
+ if (!error)
+ pr_debug("swsusp: Reading resume file was successful\n");
+ else
+ pr_debug("swsusp: Error %d resuming\n", error);
return error;
}
/**
- * swsusp_check - Check for saved image in swap
+ * swsusp_check - Check for swsusp signature in the resume device
*/
int swsusp_check(void)
@@ -1051,39 +1003,27 @@ int swsusp_check(void)
resume_bdev = open_by_devnum(swsusp_resume_device, FMODE_READ);
if (!IS_ERR(resume_bdev)) {
set_blocksize(resume_bdev, PAGE_SIZE);
- error = check_suspend_image();
+ memset(&swsusp_header, 0, sizeof(swsusp_header));
+ if ((error = bio_read_page(0, &swsusp_header)))
+ return error;
+ if (!memcmp(SWSUSP_SIG, swsusp_header.sig, 10)) {
+ memcpy(swsusp_header.sig, swsusp_header.orig_sig, 10);
+ /* Reset swap signature now */
+ error = bio_write_page(0, &swsusp_header);
+ } else {
+ return -EINVAL;
+ }
if (error)
- blkdev_put(resume_bdev);
- } else
+ blkdev_put(resume_bdev);
+ else
+ pr_debug("swsusp: Signature found, resuming\n");
+ } else {
error = PTR_ERR(resume_bdev);
-
- if (!error)
- pr_debug("swsusp: resume file found\n");
- else
- pr_debug("swsusp: Error %d check for resume file\n", error);
- return error;
-}
-
-/**
- * swsusp_read - Read saved image from swap.
- */
-
-int swsusp_read(struct pbe **pblist_ptr)
-{
- int error;
-
- if (IS_ERR(resume_bdev)) {
- pr_debug("swsusp: block device not initialised\n");
- return PTR_ERR(resume_bdev);
}
- error = read_suspend_image(pblist_ptr);
- blkdev_put(resume_bdev);
+ if (error)
+ pr_debug("swsusp: Error %d check for resume file\n", error);
- if (!error)
- pr_debug("swsusp: Reading resume file was successful\n");
- else
- pr_debug("swsusp: Error %d resuming\n", error);
return error;
}
OpenPOWER on IntegriCloud