aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/power/swsusp.c
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2006-01-06 03:17:58 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-01-06 11:33:43 -0500
commit277c6e2ad7369558dbd7ffbcc6dcbe16458bf723 (patch)
tree4b45284c5c5c13c41d2723f603ea3645d999ce54 /kernel/power/swsusp.c
parent1adf6c8ea916bc4a2587a881ec7715fece63fb5e (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/power/swsusp.c')
-rw-r--r--kernel/power/swsusp.c190
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
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