diff options
Diffstat (limited to 'kernel/power/swsusp.c')
-rw-r--r-- | kernel/power/swsusp.c | 190 |
1 files changed, 65 insertions, 125 deletions
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 | ||
94 | static struct swsusp_header { | 94 | static 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 | ||
107 | static unsigned short root_swap = 0xffff; | 107 | static unsigned short root_swap = 0xffff; |
108 | 108 | ||
109 | static int mark_swapfiles(swp_entry_t prev) | 109 | static 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 | |||
429 | static 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 | /* | 834 | static 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 | |||
848 | static 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 | |||
871 | static 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 | |||
887 | static 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 | ||
992 | static int check_suspend_image(void) | 941 | int 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 | |||
1005 | static 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 | ||
1047 | int swsusp_check(void) | 999 | int 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 | |||
1071 | int 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 | ||