diff options
author | Rafael J. Wysocki <rjw@sisk.pl> | 2006-01-06 03:17:58 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-01-06 11:33:43 -0500 |
commit | 277c6e2ad7369558dbd7ffbcc6dcbe16458bf723 (patch) | |
tree | 4b45284c5c5c13c41d2723f603ea3645d999ce54 /kernel | |
parent | 1adf6c8ea916bc4a2587a881ec7715fece63fb5e (diff) |
[PATCH] swsusp: save image header first
This makes the swsusp_info structure become the header of the image in the
literal sense (ie. it is saved to the swap and read before any other image
data with the help of the swsusp's swap map structure, so generally it is
treated in the same way as the rest of the image).
The main thing it does is to make swsusp_header contain the offset of the swap
map used to track the image data pages rather than the offset of swsusp_info.
Simultaneously, swsusp_info becomes the first image page written to the swap.
The other changes are generally consequences of the above with a few
exceptions (there's some consolidation in the image reading part as a few
functions turn into trivial wrappers around something else).
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Acked-by: Pavel Machek <pavel@suse.cz>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/power/power.h | 1 | ||||
-rw-r--r-- | kernel/power/swsusp.c | 190 |
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 | ||
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 | ||