aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 {
16 int cpus; 16 int cpus;
17 unsigned long image_pages; 17 unsigned long image_pages;
18 unsigned long pages; 18 unsigned long pages;
19 swp_entry_t start;
20} __attribute__((aligned(PAGE_SIZE))); 19} __attribute__((aligned(PAGE_SIZE)));
21 20
22 21
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[];
93 93
94static struct swsusp_header { 94static struct swsusp_header {
95 char reserved[PAGE_SIZE - 20 - sizeof(swp_entry_t)]; 95 char reserved[PAGE_SIZE - 20 - sizeof(swp_entry_t)];
96 swp_entry_t swsusp_info; 96 swp_entry_t image;
97 char orig_sig[10]; 97 char orig_sig[10];
98 char sig[10]; 98 char sig[10];
99} __attribute__((packed, aligned(PAGE_SIZE))) swsusp_header; 99} __attribute__((packed, aligned(PAGE_SIZE))) swsusp_header;
@@ -106,7 +106,7 @@ static struct swsusp_info swsusp_info;
106 106
107static unsigned short root_swap = 0xffff; 107static unsigned short root_swap = 0xffff;
108 108
109static int mark_swapfiles(swp_entry_t prev) 109static int mark_swapfiles(swp_entry_t start)
110{ 110{
111 int error; 111 int error;
112 112
@@ -117,7 +117,7 @@ static int mark_swapfiles(swp_entry_t prev)
117 !memcmp("SWAPSPACE2",swsusp_header.sig, 10)) { 117 !memcmp("SWAPSPACE2",swsusp_header.sig, 10)) {
118 memcpy(swsusp_header.orig_sig,swsusp_header.sig, 10); 118 memcpy(swsusp_header.orig_sig,swsusp_header.sig, 10);
119 memcpy(swsusp_header.sig,SWSUSP_SIG, 10); 119 memcpy(swsusp_header.sig,SWSUSP_SIG, 10);
120 swsusp_header.swsusp_info = prev; 120 swsusp_header.image = start;
121 error = rw_swap_page_sync(WRITE, 121 error = rw_swap_page_sync(WRITE,
122 swp_entry(root_swap, 0), 122 swp_entry(root_swap, 0),
123 virt_to_page((unsigned long) 123 virt_to_page((unsigned long)
@@ -423,22 +423,7 @@ static void init_header(unsigned int nr_pages)
423 swsusp_info.cpus = num_online_cpus(); 423 swsusp_info.cpus = num_online_cpus();
424 swsusp_info.image_pages = nr_pages; 424 swsusp_info.image_pages = nr_pages;
425 swsusp_info.pages = nr_pages + 425 swsusp_info.pages = nr_pages +
426 ((nr_pages * sizeof(long) + PAGE_SIZE - 1) >> PAGE_SHIFT); 426 ((nr_pages * sizeof(long) + PAGE_SIZE - 1) >> PAGE_SHIFT) + 1;
427}
428
429static int close_swap(void)
430{
431 swp_entry_t entry;
432 int error;
433
434 dump_info();
435 error = write_page((unsigned long)&swsusp_info, &entry);
436 if (!error) {
437 printk( "S" );
438 error = mark_swapfiles(entry);
439 printk( "|\n" );
440 }
441 return error;
442} 427}
443 428
444/** 429/**
@@ -522,6 +507,7 @@ int swsusp_write(struct pbe *pblist, unsigned int nr_pages)
522{ 507{
523 struct swap_map_page *swap_map; 508 struct swap_map_page *swap_map;
524 struct swap_map_handle handle; 509 struct swap_map_handle handle;
510 swp_entry_t start;
525 int error; 511 int error;
526 512
527 if ((error = swsusp_swap_check())) { 513 if ((error = swsusp_swap_check())) {
@@ -539,18 +525,23 @@ int swsusp_write(struct pbe *pblist, unsigned int nr_pages)
539 return -ENOMEM; 525 return -ENOMEM;
540 init_swap_map_handle(&handle, swap_map); 526 init_swap_map_handle(&handle, swap_map);
541 527
542 error = save_image_metadata(pblist, &handle); 528 error = swap_map_write_page(&handle, (unsigned long)&swsusp_info);
529 if (!error)
530 error = save_image_metadata(pblist, &handle);
543 if (!error) 531 if (!error)
544 error = save_image_data(pblist, &handle, nr_pages); 532 error = save_image_data(pblist, &handle, nr_pages);
545 if (error) 533 if (error)
546 goto Free_image_entries; 534 goto Free_image_entries;
547 535
548 swap_map = reverse_swap_map(swap_map); 536 swap_map = reverse_swap_map(swap_map);
549 error = save_swap_map(swap_map, &swsusp_info.start); 537 error = save_swap_map(swap_map, &start);
550 if (error) 538 if (error)
551 goto Free_map_entries; 539 goto Free_map_entries;
552 540
553 error = close_swap(); 541 dump_info();
542 printk( "S" );
543 error = mark_swapfiles(start);
544 printk( "|\n" );
554 if (error) 545 if (error)
555 goto Free_map_entries; 546 goto Free_map_entries;
556 547
@@ -840,70 +831,28 @@ static inline int swap_map_read_page(struct swap_map_handle *handle, void *buf)
840 return error; 831 return error;
841} 832}
842 833
843/* 834static int check_header(void)
844 * Sanity check if this image makes sense with this kernel/swap context
845 * I really don't think that it's foolproof but more than nothing..
846 */
847
848static const char *sanity_check(void)
849{ 835{
836 char *reason = NULL;
837
850 dump_info(); 838 dump_info();
851 if (swsusp_info.version_code != LINUX_VERSION_CODE) 839 if (swsusp_info.version_code != LINUX_VERSION_CODE)
852 return "kernel version"; 840 reason = "kernel version";
853 if (swsusp_info.num_physpages != num_physpages) 841 if (swsusp_info.num_physpages != num_physpages)
854 return "memory size"; 842 reason = "memory size";
855 if (strcmp(swsusp_info.uts.sysname,system_utsname.sysname)) 843 if (strcmp(swsusp_info.uts.sysname,system_utsname.sysname))
856 return "system type"; 844 reason = "system type";
857 if (strcmp(swsusp_info.uts.release,system_utsname.release)) 845 if (strcmp(swsusp_info.uts.release,system_utsname.release))
858 return "kernel release"; 846 reason = "kernel release";
859 if (strcmp(swsusp_info.uts.version,system_utsname.version)) 847 if (strcmp(swsusp_info.uts.version,system_utsname.version))
860 return "version"; 848 reason = "version";
861 if (strcmp(swsusp_info.uts.machine,system_utsname.machine)) 849 if (strcmp(swsusp_info.uts.machine,system_utsname.machine))
862 return "machine"; 850 reason = "machine";
863#if 0 851 if (reason) {
864 /* We can't use number of online CPUs when we use hotplug to remove them ;-))) */ 852 printk(KERN_ERR "swsusp: Resume mismatch: %s\n", reason);
865 if (swsusp_info.cpus != num_possible_cpus())
866 return "number of cpus";
867#endif
868 return NULL;
869}
870
871static int check_header(void)
872{
873 const char *reason = NULL;
874 int error;
875
876 if ((error = bio_read_page(swp_offset(swsusp_header.swsusp_info), &swsusp_info)))
877 return error;
878
879 /* Is this same machine? */
880 if ((reason = sanity_check())) {
881 printk(KERN_ERR "swsusp: Resume mismatch: %s\n",reason);
882 return -EPERM; 853 return -EPERM;
883 } 854 }
884 return error; 855 return 0;
885}
886
887static int check_sig(void)
888{
889 int error;
890
891 memset(&swsusp_header, 0, sizeof(swsusp_header));
892 if ((error = bio_read_page(0, &swsusp_header)))
893 return error;
894 if (!memcmp(SWSUSP_SIG, swsusp_header.sig, 10)) {
895 memcpy(swsusp_header.sig, swsusp_header.orig_sig, 10);
896
897 /*
898 * Reset swap signature now.
899 */
900 error = bio_write_page(0, &swsusp_header);
901 } else {
902 return -EINVAL;
903 }
904 if (!error)
905 pr_debug("swsusp: Signature found, resuming\n");
906 return error;
907} 856}
908 857
909/** 858/**
@@ -989,33 +938,29 @@ static int load_image_metadata(struct pbe *pblist, struct swap_map_handle *handl
989 return error; 938 return error;
990} 939}
991 940
992static int check_suspend_image(void) 941int swsusp_read(struct pbe **pblist_ptr)
993{
994 int error = 0;
995
996 if ((error = check_sig()))
997 return error;
998
999 if ((error = check_header()))
1000 return error;
1001
1002 return 0;
1003}
1004
1005static int read_suspend_image(struct pbe **pblist_ptr)
1006{ 942{
1007 int error = 0; 943 int error;
1008 struct pbe *p, *pblist; 944 struct pbe *p, *pblist;
1009 struct swap_map_handle handle; 945 struct swap_map_handle handle;
1010 unsigned int nr_pages = swsusp_info.image_pages; 946 unsigned int nr_pages;
1011 947
948 if (IS_ERR(resume_bdev)) {
949 pr_debug("swsusp: block device not initialised\n");
950 return PTR_ERR(resume_bdev);
951 }
952
953 error = get_swap_map_reader(&handle, swsusp_header.image);
954 if (!error)
955 error = swap_map_read_page(&handle, &swsusp_info);
956 if (!error)
957 error = check_header();
958 if (error)
959 return error;
960 nr_pages = swsusp_info.image_pages;
1012 p = alloc_pagedir(nr_pages, GFP_ATOMIC, 0); 961 p = alloc_pagedir(nr_pages, GFP_ATOMIC, 0);
1013 if (!p) 962 if (!p)
1014 return -ENOMEM; 963 return -ENOMEM;
1015 error = get_swap_map_reader(&handle, swsusp_info.start);
1016 if (error)
1017 /* The PBE list at p will be released by swsusp_free() */
1018 return error;
1019 error = load_image_metadata(p, &handle); 964 error = load_image_metadata(p, &handle);
1020 if (!error) { 965 if (!error) {
1021 mark_unsafe_pages(p); 966 mark_unsafe_pages(p);
@@ -1037,11 +982,18 @@ static int read_suspend_image(struct pbe **pblist_ptr)
1037 *pblist_ptr = pblist; 982 *pblist_ptr = pblist;
1038 } 983 }
1039 release_swap_map_reader(&handle); 984 release_swap_map_reader(&handle);
985
986 blkdev_put(resume_bdev);
987
988 if (!error)
989 pr_debug("swsusp: Reading resume file was successful\n");
990 else
991 pr_debug("swsusp: Error %d resuming\n", error);
1040 return error; 992 return error;
1041} 993}
1042 994
1043/** 995/**
1044 * swsusp_check - Check for saved image in swap 996 * swsusp_check - Check for swsusp signature in the resume device
1045 */ 997 */
1046 998
1047int swsusp_check(void) 999int swsusp_check(void)
@@ -1051,39 +1003,27 @@ int swsusp_check(void)
1051 resume_bdev = open_by_devnum(swsusp_resume_device, FMODE_READ); 1003 resume_bdev = open_by_devnum(swsusp_resume_device, FMODE_READ);
1052 if (!IS_ERR(resume_bdev)) { 1004 if (!IS_ERR(resume_bdev)) {
1053 set_blocksize(resume_bdev, PAGE_SIZE); 1005 set_blocksize(resume_bdev, PAGE_SIZE);
1054 error = check_suspend_image(); 1006 memset(&swsusp_header, 0, sizeof(swsusp_header));
1007 if ((error = bio_read_page(0, &swsusp_header)))
1008 return error;
1009 if (!memcmp(SWSUSP_SIG, swsusp_header.sig, 10)) {
1010 memcpy(swsusp_header.sig, swsusp_header.orig_sig, 10);
1011 /* Reset swap signature now */
1012 error = bio_write_page(0, &swsusp_header);
1013 } else {
1014 return -EINVAL;
1015 }
1055 if (error) 1016 if (error)
1056 blkdev_put(resume_bdev); 1017 blkdev_put(resume_bdev);
1057 } else 1018 else
1019 pr_debug("swsusp: Signature found, resuming\n");
1020 } else {
1058 error = PTR_ERR(resume_bdev); 1021 error = PTR_ERR(resume_bdev);
1059
1060 if (!error)
1061 pr_debug("swsusp: resume file found\n");
1062 else
1063 pr_debug("swsusp: Error %d check for resume file\n", error);
1064 return error;
1065}
1066
1067/**
1068 * swsusp_read - Read saved image from swap.
1069 */
1070
1071int swsusp_read(struct pbe **pblist_ptr)
1072{
1073 int error;
1074
1075 if (IS_ERR(resume_bdev)) {
1076 pr_debug("swsusp: block device not initialised\n");
1077 return PTR_ERR(resume_bdev);
1078 } 1022 }
1079 1023
1080 error = read_suspend_image(pblist_ptr); 1024 if (error)
1081 blkdev_put(resume_bdev); 1025 pr_debug("swsusp: Error %d check for resume file\n", error);
1082 1026
1083 if (!error)
1084 pr_debug("swsusp: Reading resume file was successful\n");
1085 else
1086 pr_debug("swsusp: Error %d resuming\n", error);
1087 return error; 1027 return error;
1088} 1028}
1089 1029