]> Pileus Git - ~andy/linux/blobdiff - kernel/power/swsusp.c
[PATCH] swsusp: save image header first
[~andy/linux] / kernel / power / swsusp.c
index 0479c9be7d71501be8fa96c0e31ff49f361b6921..55a18d26abeda6a2df3641cdca9de0da2f201ef9 100644 (file)
@@ -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;
 }