diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/power/power.h | 11 | ||||
-rw-r--r-- | kernel/power/snapshot.c | 416 | ||||
-rw-r--r-- | kernel/power/swap.c | 4 | ||||
-rw-r--r-- | kernel/power/user.c | 1 |
4 files changed, 186 insertions, 246 deletions
diff --git a/kernel/power/power.h b/kernel/power/power.h index 6e9e2acc34f8..bfe999f7b272 100644 --- a/kernel/power/power.h +++ b/kernel/power/power.h | |||
@@ -81,16 +81,6 @@ struct snapshot_handle { | |||
81 | unsigned int prev; /* number of the block of PAGE_SIZE bytes that | 81 | unsigned int prev; /* number of the block of PAGE_SIZE bytes that |
82 | * was the current one previously | 82 | * was the current one previously |
83 | */ | 83 | */ |
84 | struct pbe *pbe; /* PBE that corresponds to 'buffer' */ | ||
85 | struct pbe *last_pbe; /* When the image is restored (eg. read | ||
86 | * from disk) we can store some image | ||
87 | * data directly in the page frames | ||
88 | * in which they were before suspend. | ||
89 | * In such a case the PBEs that | ||
90 | * correspond to them will be unused. | ||
91 | * This is the last PBE, so far, that | ||
92 | * does not correspond to such data. | ||
93 | */ | ||
94 | void *buffer; /* address of the block to read from | 84 | void *buffer; /* address of the block to read from |
95 | * or write to | 85 | * or write to |
96 | */ | 86 | */ |
@@ -113,6 +103,7 @@ extern unsigned int snapshot_additional_pages(struct zone *zone); | |||
113 | extern int snapshot_read_next(struct snapshot_handle *handle, size_t count); | 103 | extern int snapshot_read_next(struct snapshot_handle *handle, size_t count); |
114 | extern int snapshot_write_next(struct snapshot_handle *handle, size_t count); | 104 | extern int snapshot_write_next(struct snapshot_handle *handle, size_t count); |
115 | extern int snapshot_image_loaded(struct snapshot_handle *handle); | 105 | extern int snapshot_image_loaded(struct snapshot_handle *handle); |
106 | extern void snapshot_free_unused_memory(struct snapshot_handle *handle); | ||
116 | 107 | ||
117 | #define SNAPSHOT_IOC_MAGIC '3' | 108 | #define SNAPSHOT_IOC_MAGIC '3' |
118 | #define SNAPSHOT_FREEZE _IO(SNAPSHOT_IOC_MAGIC, 1) | 109 | #define SNAPSHOT_FREEZE _IO(SNAPSHOT_IOC_MAGIC, 1) |
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index 852e0df41719..1b84313cbab5 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c | |||
@@ -39,7 +39,7 @@ struct pbe *restore_pblist; | |||
39 | 39 | ||
40 | static unsigned int nr_copy_pages; | 40 | static unsigned int nr_copy_pages; |
41 | static unsigned int nr_meta_pages; | 41 | static unsigned int nr_meta_pages; |
42 | static unsigned long *buffer; | 42 | static void *buffer; |
43 | 43 | ||
44 | #ifdef CONFIG_HIGHMEM | 44 | #ifdef CONFIG_HIGHMEM |
45 | unsigned int count_highmem_pages(void) | 45 | unsigned int count_highmem_pages(void) |
@@ -172,7 +172,7 @@ static inline int restore_highmem(void) {return 0;} | |||
172 | #define PG_UNSAFE_CLEAR 1 | 172 | #define PG_UNSAFE_CLEAR 1 |
173 | #define PG_UNSAFE_KEEP 0 | 173 | #define PG_UNSAFE_KEEP 0 |
174 | 174 | ||
175 | static unsigned int unsafe_pages; | 175 | static unsigned int allocated_unsafe_pages; |
176 | 176 | ||
177 | static void *alloc_image_page(gfp_t gfp_mask, int safe_needed) | 177 | static void *alloc_image_page(gfp_t gfp_mask, int safe_needed) |
178 | { | 178 | { |
@@ -183,7 +183,7 @@ static void *alloc_image_page(gfp_t gfp_mask, int safe_needed) | |||
183 | while (res && PageNosaveFree(virt_to_page(res))) { | 183 | while (res && PageNosaveFree(virt_to_page(res))) { |
184 | /* The page is unsafe, mark it for swsusp_free() */ | 184 | /* The page is unsafe, mark it for swsusp_free() */ |
185 | SetPageNosave(virt_to_page(res)); | 185 | SetPageNosave(virt_to_page(res)); |
186 | unsafe_pages++; | 186 | allocated_unsafe_pages++; |
187 | res = (void *)get_zeroed_page(gfp_mask); | 187 | res = (void *)get_zeroed_page(gfp_mask); |
188 | } | 188 | } |
189 | if (res) { | 189 | if (res) { |
@@ -772,101 +772,10 @@ copy_data_pages(struct memory_bitmap *copy_bm, struct memory_bitmap *orig_bm) | |||
772 | } | 772 | } |
773 | 773 | ||
774 | /** | 774 | /** |
775 | * free_pagedir - free pages allocated with alloc_pagedir() | 775 | * swsusp_free - free pages allocated for the suspend. |
776 | */ | ||
777 | |||
778 | static void free_pagedir(struct pbe *pblist, int clear_nosave_free) | ||
779 | { | ||
780 | struct pbe *pbe; | ||
781 | |||
782 | while (pblist) { | ||
783 | pbe = (pblist + PB_PAGE_SKIP)->next; | ||
784 | free_image_page(pblist, clear_nosave_free); | ||
785 | pblist = pbe; | ||
786 | } | ||
787 | } | ||
788 | |||
789 | /** | ||
790 | * fill_pb_page - Create a list of PBEs on a given memory page | ||
791 | */ | ||
792 | |||
793 | static inline void fill_pb_page(struct pbe *pbpage, unsigned int n) | ||
794 | { | ||
795 | struct pbe *p; | ||
796 | |||
797 | p = pbpage; | ||
798 | pbpage += n - 1; | ||
799 | do | ||
800 | p->next = p + 1; | ||
801 | while (++p < pbpage); | ||
802 | } | ||
803 | |||
804 | /** | ||
805 | * create_pbe_list - Create a list of PBEs on top of a given chain | ||
806 | * of memory pages allocated with alloc_pagedir() | ||
807 | * | 776 | * |
808 | * This function assumes that pages allocated by alloc_image_page() will | 777 | * Suspend pages are alocated before the atomic copy is made, so we |
809 | * always be zeroed. | 778 | * need to release them after the resume. |
810 | */ | ||
811 | |||
812 | static inline void create_pbe_list(struct pbe *pblist, unsigned int nr_pages) | ||
813 | { | ||
814 | struct pbe *pbpage; | ||
815 | unsigned int num = PBES_PER_PAGE; | ||
816 | |||
817 | for_each_pb_page (pbpage, pblist) { | ||
818 | if (num >= nr_pages) | ||
819 | break; | ||
820 | |||
821 | fill_pb_page(pbpage, PBES_PER_PAGE); | ||
822 | num += PBES_PER_PAGE; | ||
823 | } | ||
824 | if (pbpage) { | ||
825 | num -= PBES_PER_PAGE; | ||
826 | fill_pb_page(pbpage, nr_pages - num); | ||
827 | } | ||
828 | } | ||
829 | |||
830 | /** | ||
831 | * alloc_pagedir - Allocate the page directory. | ||
832 | * | ||
833 | * First, determine exactly how many pages we need and | ||
834 | * allocate them. | ||
835 | * | ||
836 | * We arrange the pages in a chain: each page is an array of PBES_PER_PAGE | ||
837 | * struct pbe elements (pbes) and the last element in the page points | ||
838 | * to the next page. | ||
839 | * | ||
840 | * On each page we set up a list of struct_pbe elements. | ||
841 | */ | ||
842 | |||
843 | static struct pbe *alloc_pagedir(unsigned int nr_pages, gfp_t gfp_mask, | ||
844 | int safe_needed) | ||
845 | { | ||
846 | unsigned int num; | ||
847 | struct pbe *pblist, *pbe; | ||
848 | |||
849 | if (!nr_pages) | ||
850 | return NULL; | ||
851 | |||
852 | pblist = alloc_image_page(gfp_mask, safe_needed); | ||
853 | pbe = pblist; | ||
854 | for (num = PBES_PER_PAGE; num < nr_pages; num += PBES_PER_PAGE) { | ||
855 | if (!pbe) { | ||
856 | free_pagedir(pblist, PG_UNSAFE_CLEAR); | ||
857 | return NULL; | ||
858 | } | ||
859 | pbe += PB_PAGE_SKIP; | ||
860 | pbe->next = alloc_image_page(gfp_mask, safe_needed); | ||
861 | pbe = pbe->next; | ||
862 | } | ||
863 | create_pbe_list(pblist, nr_pages); | ||
864 | return pblist; | ||
865 | } | ||
866 | |||
867 | /** | ||
868 | * Free pages we allocated for suspend. Suspend pages are alocated | ||
869 | * before atomic copy, so we need to free them after resume. | ||
870 | */ | 779 | */ |
871 | 780 | ||
872 | void swsusp_free(void) | 781 | void swsusp_free(void) |
@@ -904,14 +813,18 @@ void swsusp_free(void) | |||
904 | static int enough_free_mem(unsigned int nr_pages) | 813 | static int enough_free_mem(unsigned int nr_pages) |
905 | { | 814 | { |
906 | struct zone *zone; | 815 | struct zone *zone; |
907 | unsigned int n = 0; | 816 | unsigned int free = 0, meta = 0; |
908 | 817 | ||
909 | for_each_zone (zone) | 818 | for_each_zone (zone) |
910 | if (!is_highmem(zone)) | 819 | if (!is_highmem(zone)) { |
911 | n += zone->free_pages; | 820 | free += zone->free_pages; |
912 | pr_debug("swsusp: available memory: %u pages\n", n); | 821 | meta += snapshot_additional_pages(zone); |
913 | return n > (nr_pages + PAGES_FOR_IO + | 822 | } |
914 | (nr_pages + PBES_PER_PAGE - 1) / PBES_PER_PAGE); | 823 | |
824 | pr_debug("swsusp: pages needed: %u + %u + %u, available pages: %u\n", | ||
825 | nr_pages, PAGES_FOR_IO, meta, free); | ||
826 | |||
827 | return free > nr_pages + PAGES_FOR_IO + meta; | ||
915 | } | 828 | } |
916 | 829 | ||
917 | static int | 830 | static int |
@@ -961,11 +874,6 @@ asmlinkage int swsusp_save(void) | |||
961 | nr_pages = count_data_pages(); | 874 | nr_pages = count_data_pages(); |
962 | printk("swsusp: Need to copy %u pages\n", nr_pages); | 875 | printk("swsusp: Need to copy %u pages\n", nr_pages); |
963 | 876 | ||
964 | pr_debug("swsusp: pages needed: %u + %lu + %u, free: %u\n", | ||
965 | nr_pages, | ||
966 | (nr_pages + PBES_PER_PAGE - 1) / PBES_PER_PAGE, | ||
967 | PAGES_FOR_IO, nr_free_pages()); | ||
968 | |||
969 | if (!enough_free_mem(nr_pages)) { | 877 | if (!enough_free_mem(nr_pages)) { |
970 | printk(KERN_ERR "swsusp: Not enough free memory\n"); | 878 | printk(KERN_ERR "swsusp: Not enough free memory\n"); |
971 | return -ENOMEM; | 879 | return -ENOMEM; |
@@ -1007,22 +915,19 @@ static void init_header(struct swsusp_info *info) | |||
1007 | } | 915 | } |
1008 | 916 | ||
1009 | /** | 917 | /** |
1010 | * pack_addresses - the addresses corresponding to pfns found in the | 918 | * pack_pfns - pfns corresponding to the set bits found in the bitmap @bm |
1011 | * bitmap @bm are stored in the array @buf[] (1 page) | 919 | * are stored in the array @buf[] (1 page at a time) |
1012 | */ | 920 | */ |
1013 | 921 | ||
1014 | static inline void | 922 | static inline void |
1015 | pack_addresses(unsigned long *buf, struct memory_bitmap *bm) | 923 | pack_pfns(unsigned long *buf, struct memory_bitmap *bm) |
1016 | { | 924 | { |
1017 | int j; | 925 | int j; |
1018 | 926 | ||
1019 | for (j = 0; j < PAGE_SIZE / sizeof(long); j++) { | 927 | for (j = 0; j < PAGE_SIZE / sizeof(long); j++) { |
1020 | unsigned long pfn = memory_bm_next_pfn(bm); | 928 | buf[j] = memory_bm_next_pfn(bm); |
1021 | 929 | if (unlikely(buf[j] == BM_END_OF_MAP)) | |
1022 | if (unlikely(pfn == BM_END_OF_MAP)) | ||
1023 | break; | 930 | break; |
1024 | |||
1025 | buf[j] = (unsigned long)page_address(pfn_to_page(pfn)); | ||
1026 | } | 931 | } |
1027 | } | 932 | } |
1028 | 933 | ||
@@ -1068,7 +973,7 @@ int snapshot_read_next(struct snapshot_handle *handle, size_t count) | |||
1068 | if (handle->prev < handle->cur) { | 973 | if (handle->prev < handle->cur) { |
1069 | if (handle->cur <= nr_meta_pages) { | 974 | if (handle->cur <= nr_meta_pages) { |
1070 | memset(buffer, 0, PAGE_SIZE); | 975 | memset(buffer, 0, PAGE_SIZE); |
1071 | pack_addresses(buffer, &orig_bm); | 976 | pack_pfns(buffer, &orig_bm); |
1072 | } else { | 977 | } else { |
1073 | unsigned long pfn = memory_bm_next_pfn(©_bm); | 978 | unsigned long pfn = memory_bm_next_pfn(©_bm); |
1074 | 979 | ||
@@ -1094,14 +999,10 @@ int snapshot_read_next(struct snapshot_handle *handle, size_t count) | |||
1094 | * had been used before suspend | 999 | * had been used before suspend |
1095 | */ | 1000 | */ |
1096 | 1001 | ||
1097 | static int mark_unsafe_pages(struct pbe *pblist) | 1002 | static int mark_unsafe_pages(struct memory_bitmap *bm) |
1098 | { | 1003 | { |
1099 | struct zone *zone; | 1004 | struct zone *zone; |
1100 | unsigned long pfn, max_zone_pfn; | 1005 | unsigned long pfn, max_zone_pfn; |
1101 | struct pbe *p; | ||
1102 | |||
1103 | if (!pblist) /* a sanity check */ | ||
1104 | return -EINVAL; | ||
1105 | 1006 | ||
1106 | /* Clear page flags */ | 1007 | /* Clear page flags */ |
1107 | for_each_zone (zone) { | 1008 | for_each_zone (zone) { |
@@ -1111,30 +1012,37 @@ static int mark_unsafe_pages(struct pbe *pblist) | |||
1111 | ClearPageNosaveFree(pfn_to_page(pfn)); | 1012 | ClearPageNosaveFree(pfn_to_page(pfn)); |
1112 | } | 1013 | } |
1113 | 1014 | ||
1114 | /* Mark orig addresses */ | 1015 | /* Mark pages that correspond to the "original" pfns as "unsafe" */ |
1115 | for_each_pbe (p, pblist) { | 1016 | memory_bm_position_reset(bm); |
1116 | if (virt_addr_valid(p->orig_address)) | 1017 | do { |
1117 | SetPageNosaveFree(virt_to_page(p->orig_address)); | 1018 | pfn = memory_bm_next_pfn(bm); |
1118 | else | 1019 | if (likely(pfn != BM_END_OF_MAP)) { |
1119 | return -EFAULT; | 1020 | if (likely(pfn_valid(pfn))) |
1120 | } | 1021 | SetPageNosaveFree(pfn_to_page(pfn)); |
1022 | else | ||
1023 | return -EFAULT; | ||
1024 | } | ||
1025 | } while (pfn != BM_END_OF_MAP); | ||
1121 | 1026 | ||
1122 | unsafe_pages = 0; | 1027 | allocated_unsafe_pages = 0; |
1123 | 1028 | ||
1124 | return 0; | 1029 | return 0; |
1125 | } | 1030 | } |
1126 | 1031 | ||
1127 | static void copy_page_backup_list(struct pbe *dst, struct pbe *src) | 1032 | static void |
1033 | duplicate_memory_bitmap(struct memory_bitmap *dst, struct memory_bitmap *src) | ||
1128 | { | 1034 | { |
1129 | /* We assume both lists contain the same number of elements */ | 1035 | unsigned long pfn; |
1130 | while (src) { | 1036 | |
1131 | dst->orig_address = src->orig_address; | 1037 | memory_bm_position_reset(src); |
1132 | dst = dst->next; | 1038 | pfn = memory_bm_next_pfn(src); |
1133 | src = src->next; | 1039 | while (pfn != BM_END_OF_MAP) { |
1040 | memory_bm_set_bit(dst, pfn); | ||
1041 | pfn = memory_bm_next_pfn(src); | ||
1134 | } | 1042 | } |
1135 | } | 1043 | } |
1136 | 1044 | ||
1137 | static int check_header(struct swsusp_info *info) | 1045 | static inline int check_header(struct swsusp_info *info) |
1138 | { | 1046 | { |
1139 | char *reason = NULL; | 1047 | char *reason = NULL; |
1140 | 1048 | ||
@@ -1161,19 +1069,14 @@ static int check_header(struct swsusp_info *info) | |||
1161 | * load header - check the image header and copy data from it | 1069 | * load header - check the image header and copy data from it |
1162 | */ | 1070 | */ |
1163 | 1071 | ||
1164 | static int load_header(struct snapshot_handle *handle, | 1072 | static int |
1165 | struct swsusp_info *info) | 1073 | load_header(struct swsusp_info *info) |
1166 | { | 1074 | { |
1167 | int error; | 1075 | int error; |
1168 | struct pbe *pblist; | ||
1169 | 1076 | ||
1077 | restore_pblist = NULL; | ||
1170 | error = check_header(info); | 1078 | error = check_header(info); |
1171 | if (!error) { | 1079 | if (!error) { |
1172 | pblist = alloc_pagedir(info->image_pages, GFP_ATOMIC, PG_ANY); | ||
1173 | if (!pblist) | ||
1174 | return -ENOMEM; | ||
1175 | restore_pblist = pblist; | ||
1176 | handle->pbe = pblist; | ||
1177 | nr_copy_pages = info->image_pages; | 1080 | nr_copy_pages = info->image_pages; |
1178 | nr_meta_pages = info->pages - info->image_pages - 1; | 1081 | nr_meta_pages = info->pages - info->image_pages - 1; |
1179 | } | 1082 | } |
@@ -1181,108 +1084,137 @@ static int load_header(struct snapshot_handle *handle, | |||
1181 | } | 1084 | } |
1182 | 1085 | ||
1183 | /** | 1086 | /** |
1184 | * unpack_orig_addresses - copy the elements of @buf[] (1 page) to | 1087 | * unpack_orig_pfns - for each element of @buf[] (1 page at a time) set |
1185 | * the PBEs in the list starting at @pbe | 1088 | * the corresponding bit in the memory bitmap @bm |
1186 | */ | 1089 | */ |
1187 | 1090 | ||
1188 | static inline struct pbe *unpack_orig_addresses(unsigned long *buf, | 1091 | static inline void |
1189 | struct pbe *pbe) | 1092 | unpack_orig_pfns(unsigned long *buf, struct memory_bitmap *bm) |
1190 | { | 1093 | { |
1191 | int j; | 1094 | int j; |
1192 | 1095 | ||
1193 | for (j = 0; j < PAGE_SIZE / sizeof(long) && pbe; j++) { | 1096 | for (j = 0; j < PAGE_SIZE / sizeof(long); j++) { |
1194 | pbe->orig_address = buf[j]; | 1097 | if (unlikely(buf[j] == BM_END_OF_MAP)) |
1195 | pbe = pbe->next; | 1098 | break; |
1099 | |||
1100 | memory_bm_set_bit(bm, buf[j]); | ||
1196 | } | 1101 | } |
1197 | return pbe; | ||
1198 | } | 1102 | } |
1199 | 1103 | ||
1200 | /** | 1104 | /** |
1201 | * prepare_image - use metadata contained in the PBE list | 1105 | * prepare_image - use the memory bitmap @bm to mark the pages that will |
1202 | * pointed to by restore_pblist to mark the pages that will | 1106 | * be overwritten in the process of restoring the system memory state |
1203 | * be overwritten in the process of restoring the system | 1107 | * from the suspend image ("unsafe" pages) and allocate memory for the |
1204 | * memory state from the image ("unsafe" pages) and allocate | 1108 | * image. |
1205 | * memory for the image | ||
1206 | * | 1109 | * |
1207 | * The idea is to allocate the PBE list first and then | 1110 | * The idea is to allocate a new memory bitmap first and then allocate |
1208 | * allocate as many pages as it's needed for the image data, | 1111 | * as many pages as needed for the image data, but not to assign these |
1209 | * but not to assign these pages to the PBEs initially. | 1112 | * pages to specific tasks initially. Instead, we just mark them as |
1210 | * Instead, we just mark them as allocated and create a list | 1113 | * allocated and create a list of "safe" pages that will be used later. |
1211 | * of "safe" which will be used later | ||
1212 | */ | 1114 | */ |
1213 | 1115 | ||
1214 | static struct linked_page *safe_pages; | 1116 | #define PBES_PER_LINKED_PAGE (LINKED_PAGE_DATA_SIZE / sizeof(struct pbe)) |
1117 | |||
1118 | static struct linked_page *safe_pages_list; | ||
1215 | 1119 | ||
1216 | static int prepare_image(struct snapshot_handle *handle) | 1120 | static int |
1121 | prepare_image(struct memory_bitmap *new_bm, struct memory_bitmap *bm) | ||
1217 | { | 1122 | { |
1218 | int error = 0; | 1123 | unsigned int nr_pages; |
1219 | unsigned int nr_pages = nr_copy_pages; | 1124 | struct linked_page *sp_list, *lp; |
1220 | struct pbe *p, *pblist = NULL; | 1125 | int error; |
1221 | 1126 | ||
1222 | p = restore_pblist; | 1127 | error = mark_unsafe_pages(bm); |
1223 | error = mark_unsafe_pages(p); | 1128 | if (error) |
1224 | if (!error) { | 1129 | goto Free; |
1225 | pblist = alloc_pagedir(nr_pages, GFP_ATOMIC, PG_SAFE); | 1130 | |
1226 | if (pblist) | 1131 | error = memory_bm_create(new_bm, GFP_ATOMIC, PG_SAFE); |
1227 | copy_page_backup_list(pblist, p); | 1132 | if (error) |
1228 | free_pagedir(p, PG_UNSAFE_KEEP); | 1133 | goto Free; |
1229 | if (!pblist) | 1134 | |
1135 | duplicate_memory_bitmap(new_bm, bm); | ||
1136 | memory_bm_free(bm, PG_UNSAFE_KEEP); | ||
1137 | /* Reserve some safe pages for potential later use. | ||
1138 | * | ||
1139 | * NOTE: This way we make sure there will be enough safe pages for the | ||
1140 | * chain_alloc() in get_buffer(). It is a bit wasteful, but | ||
1141 | * nr_copy_pages cannot be greater than 50% of the memory anyway. | ||
1142 | */ | ||
1143 | sp_list = NULL; | ||
1144 | /* nr_copy_pages cannot be lesser than allocated_unsafe_pages */ | ||
1145 | nr_pages = nr_copy_pages - allocated_unsafe_pages; | ||
1146 | nr_pages = DIV_ROUND_UP(nr_pages, PBES_PER_LINKED_PAGE); | ||
1147 | while (nr_pages > 0) { | ||
1148 | lp = alloc_image_page(GFP_ATOMIC, PG_SAFE); | ||
1149 | if (!lp) { | ||
1230 | error = -ENOMEM; | 1150 | error = -ENOMEM; |
1151 | goto Free; | ||
1152 | } | ||
1153 | lp->next = sp_list; | ||
1154 | sp_list = lp; | ||
1155 | nr_pages--; | ||
1231 | } | 1156 | } |
1232 | safe_pages = NULL; | 1157 | /* Preallocate memory for the image */ |
1233 | if (!error && nr_pages > unsafe_pages) { | 1158 | safe_pages_list = NULL; |
1234 | nr_pages -= unsafe_pages; | 1159 | nr_pages = nr_copy_pages - allocated_unsafe_pages; |
1235 | while (nr_pages--) { | 1160 | while (nr_pages > 0) { |
1236 | struct linked_page *ptr; | 1161 | lp = (struct linked_page *)get_zeroed_page(GFP_ATOMIC); |
1237 | 1162 | if (!lp) { | |
1238 | ptr = (void *)get_zeroed_page(GFP_ATOMIC); | 1163 | error = -ENOMEM; |
1239 | if (!ptr) { | 1164 | goto Free; |
1240 | error = -ENOMEM; | 1165 | } |
1241 | break; | 1166 | if (!PageNosaveFree(virt_to_page(lp))) { |
1242 | } | 1167 | /* The page is "safe", add it to the list */ |
1243 | if (!PageNosaveFree(virt_to_page(ptr))) { | 1168 | lp->next = safe_pages_list; |
1244 | /* The page is "safe", add it to the list */ | 1169 | safe_pages_list = lp; |
1245 | ptr->next = safe_pages; | ||
1246 | safe_pages = ptr; | ||
1247 | } | ||
1248 | /* Mark the page as allocated */ | ||
1249 | SetPageNosave(virt_to_page(ptr)); | ||
1250 | SetPageNosaveFree(virt_to_page(ptr)); | ||
1251 | } | 1170 | } |
1171 | /* Mark the page as allocated */ | ||
1172 | SetPageNosave(virt_to_page(lp)); | ||
1173 | SetPageNosaveFree(virt_to_page(lp)); | ||
1174 | nr_pages--; | ||
1252 | } | 1175 | } |
1253 | if (!error) { | 1176 | /* Free the reserved safe pages so that chain_alloc() can use them */ |
1254 | restore_pblist = pblist; | 1177 | while (sp_list) { |
1255 | } else { | 1178 | lp = sp_list->next; |
1256 | handle->pbe = NULL; | 1179 | free_image_page(sp_list, PG_UNSAFE_CLEAR); |
1257 | swsusp_free(); | 1180 | sp_list = lp; |
1258 | } | 1181 | } |
1182 | return 0; | ||
1183 | |||
1184 | Free: | ||
1185 | swsusp_free(); | ||
1259 | return error; | 1186 | return error; |
1260 | } | 1187 | } |
1261 | 1188 | ||
1262 | static void *get_buffer(struct snapshot_handle *handle) | 1189 | /** |
1190 | * get_buffer - compute the address that snapshot_write_next() should | ||
1191 | * set for its caller to write to. | ||
1192 | */ | ||
1193 | |||
1194 | static void *get_buffer(struct memory_bitmap *bm, struct chain_allocator *ca) | ||
1263 | { | 1195 | { |
1264 | struct pbe *pbe = handle->pbe, *last = handle->last_pbe; | 1196 | struct pbe *pbe; |
1265 | struct page *page = virt_to_page(pbe->orig_address); | 1197 | struct page *page = pfn_to_page(memory_bm_next_pfn(bm)); |
1266 | 1198 | ||
1267 | if (PageNosave(page) && PageNosaveFree(page)) { | 1199 | if (PageNosave(page) && PageNosaveFree(page)) |
1268 | /* | 1200 | /* We have allocated the "original" page frame and we can |
1269 | * We have allocated the "original" page frame and we can | 1201 | * use it directly to store the loaded page. |
1270 | * use it directly to store the read page | ||
1271 | */ | 1202 | */ |
1272 | pbe->address = 0; | 1203 | return page_address(page); |
1273 | if (last && last->next) | 1204 | |
1274 | last->next = NULL; | 1205 | /* The "original" page frame has not been allocated and we have to |
1275 | return (void *)pbe->orig_address; | 1206 | * use a "safe" page frame to store the loaded page. |
1276 | } | ||
1277 | /* | ||
1278 | * The "original" page frame has not been allocated and we have to | ||
1279 | * use a "safe" page frame to store the read page | ||
1280 | */ | 1207 | */ |
1281 | pbe->address = (unsigned long)safe_pages; | 1208 | pbe = chain_alloc(ca, sizeof(struct pbe)); |
1282 | safe_pages = safe_pages->next; | 1209 | if (!pbe) { |
1283 | if (last) | 1210 | swsusp_free(); |
1284 | last->next = pbe; | 1211 | return NULL; |
1285 | handle->last_pbe = pbe; | 1212 | } |
1213 | pbe->orig_address = (unsigned long)page_address(page); | ||
1214 | pbe->address = (unsigned long)safe_pages_list; | ||
1215 | safe_pages_list = safe_pages_list->next; | ||
1216 | pbe->next = restore_pblist; | ||
1217 | restore_pblist = pbe; | ||
1286 | return (void *)pbe->address; | 1218 | return (void *)pbe->address; |
1287 | } | 1219 | } |
1288 | 1220 | ||
@@ -1310,10 +1242,13 @@ static void *get_buffer(struct snapshot_handle *handle) | |||
1310 | 1242 | ||
1311 | int snapshot_write_next(struct snapshot_handle *handle, size_t count) | 1243 | int snapshot_write_next(struct snapshot_handle *handle, size_t count) |
1312 | { | 1244 | { |
1245 | static struct chain_allocator ca; | ||
1313 | int error = 0; | 1246 | int error = 0; |
1314 | 1247 | ||
1248 | /* Check if we have already loaded the entire image */ | ||
1315 | if (handle->prev && handle->cur > nr_meta_pages + nr_copy_pages) | 1249 | if (handle->prev && handle->cur > nr_meta_pages + nr_copy_pages) |
1316 | return 0; | 1250 | return 0; |
1251 | |||
1317 | if (!buffer) { | 1252 | if (!buffer) { |
1318 | /* This makes the buffer be freed by swsusp_free() */ | 1253 | /* This makes the buffer be freed by swsusp_free() */ |
1319 | buffer = alloc_image_page(GFP_ATOMIC, PG_ANY); | 1254 | buffer = alloc_image_page(GFP_ATOMIC, PG_ANY); |
@@ -1324,26 +1259,32 @@ int snapshot_write_next(struct snapshot_handle *handle, size_t count) | |||
1324 | handle->buffer = buffer; | 1259 | handle->buffer = buffer; |
1325 | handle->sync_read = 1; | 1260 | handle->sync_read = 1; |
1326 | if (handle->prev < handle->cur) { | 1261 | if (handle->prev < handle->cur) { |
1327 | if (!handle->prev) { | 1262 | if (handle->prev == 0) { |
1328 | error = load_header(handle, | 1263 | error = load_header(buffer); |
1329 | (struct swsusp_info *)buffer); | 1264 | if (error) |
1265 | return error; | ||
1266 | |||
1267 | error = memory_bm_create(©_bm, GFP_ATOMIC, PG_ANY); | ||
1330 | if (error) | 1268 | if (error) |
1331 | return error; | 1269 | return error; |
1270 | |||
1332 | } else if (handle->prev <= nr_meta_pages) { | 1271 | } else if (handle->prev <= nr_meta_pages) { |
1333 | handle->pbe = unpack_orig_addresses(buffer, | 1272 | unpack_orig_pfns(buffer, ©_bm); |
1334 | handle->pbe); | 1273 | if (handle->prev == nr_meta_pages) { |
1335 | if (!handle->pbe) { | 1274 | error = prepare_image(&orig_bm, ©_bm); |
1336 | error = prepare_image(handle); | ||
1337 | if (error) | 1275 | if (error) |
1338 | return error; | 1276 | return error; |
1339 | handle->pbe = restore_pblist; | 1277 | |
1340 | handle->last_pbe = NULL; | 1278 | chain_init(&ca, GFP_ATOMIC, PG_SAFE); |
1341 | handle->buffer = get_buffer(handle); | 1279 | memory_bm_position_reset(&orig_bm); |
1280 | restore_pblist = NULL; | ||
1281 | handle->buffer = get_buffer(&orig_bm, &ca); | ||
1342 | handle->sync_read = 0; | 1282 | handle->sync_read = 0; |
1283 | if (!handle->buffer) | ||
1284 | return -ENOMEM; | ||
1343 | } | 1285 | } |
1344 | } else { | 1286 | } else { |
1345 | handle->pbe = handle->pbe->next; | 1287 | handle->buffer = get_buffer(&orig_bm, &ca); |
1346 | handle->buffer = get_buffer(handle); | ||
1347 | handle->sync_read = 0; | 1288 | handle->sync_read = 0; |
1348 | } | 1289 | } |
1349 | handle->prev = handle->cur; | 1290 | handle->prev = handle->cur; |
@@ -1362,6 +1303,13 @@ int snapshot_write_next(struct snapshot_handle *handle, size_t count) | |||
1362 | 1303 | ||
1363 | int snapshot_image_loaded(struct snapshot_handle *handle) | 1304 | int snapshot_image_loaded(struct snapshot_handle *handle) |
1364 | { | 1305 | { |
1365 | return !(!handle->pbe || handle->pbe->next || !nr_copy_pages || | 1306 | return !(!nr_copy_pages || |
1366 | handle->cur <= nr_meta_pages + nr_copy_pages); | 1307 | handle->cur <= nr_meta_pages + nr_copy_pages); |
1308 | } | ||
1309 | |||
1310 | void snapshot_free_unused_memory(struct snapshot_handle *handle) | ||
1311 | { | ||
1312 | /* Free only if we have loaded the image entirely */ | ||
1313 | if (handle->prev && handle->cur > nr_meta_pages + nr_copy_pages) | ||
1314 | memory_bm_free(&orig_bm, PG_UNSAFE_CLEAR); | ||
1367 | } | 1315 | } |
diff --git a/kernel/power/swap.c b/kernel/power/swap.c index 8309d20b2563..9b2ee5344dee 100644 --- a/kernel/power/swap.c +++ b/kernel/power/swap.c | |||
@@ -331,8 +331,7 @@ static int enough_swap(unsigned int nr_pages) | |||
331 | unsigned int free_swap = count_swap_pages(root_swap, 1); | 331 | unsigned int free_swap = count_swap_pages(root_swap, 1); |
332 | 332 | ||
333 | pr_debug("swsusp: free swap pages: %u\n", free_swap); | 333 | pr_debug("swsusp: free swap pages: %u\n", free_swap); |
334 | return free_swap > (nr_pages + PAGES_FOR_IO + | 334 | return free_swap > nr_pages + PAGES_FOR_IO; |
335 | (nr_pages + PBES_PER_PAGE - 1) / PBES_PER_PAGE); | ||
336 | } | 335 | } |
337 | 336 | ||
338 | /** | 337 | /** |
@@ -547,6 +546,7 @@ static int load_image(struct swap_map_handle *handle, | |||
547 | error = err2; | 546 | error = err2; |
548 | if (!error) { | 547 | if (!error) { |
549 | printk("\b\b\b\bdone\n"); | 548 | printk("\b\b\b\bdone\n"); |
549 | snapshot_free_unused_memory(snapshot); | ||
550 | if (!snapshot_image_loaded(snapshot)) | 550 | if (!snapshot_image_loaded(snapshot)) |
551 | error = -ENODATA; | 551 | error = -ENODATA; |
552 | } | 552 | } |
diff --git a/kernel/power/user.c b/kernel/power/user.c index 0ef5e4ba39e5..2e4499f3e4d9 100644 --- a/kernel/power/user.c +++ b/kernel/power/user.c | |||
@@ -193,6 +193,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp, | |||
193 | error = -EPERM; | 193 | error = -EPERM; |
194 | break; | 194 | break; |
195 | } | 195 | } |
196 | snapshot_free_unused_memory(&data->handle); | ||
196 | down(&pm_sem); | 197 | down(&pm_sem); |
197 | pm_prepare_console(); | 198 | pm_prepare_console(); |
198 | error = device_suspend(PMSG_FREEZE); | 199 | error = device_suspend(PMSG_FREEZE); |