diff options
-rw-r--r-- | kernel/power/power.h | 4 | ||||
-rw-r--r-- | kernel/power/snapshot.c | 80 | ||||
-rw-r--r-- | kernel/power/swsusp.c | 76 |
3 files changed, 79 insertions, 81 deletions
diff --git a/kernel/power/power.h b/kernel/power/power.h index 46b5ec7a3afb..ec4dbdfb07b4 100644 --- a/kernel/power/power.h +++ b/kernel/power/power.h | |||
@@ -74,7 +74,7 @@ extern asmlinkage int swsusp_arch_resume(void); | |||
74 | 74 | ||
75 | extern int create_basic_memory_bitmaps(void); | 75 | extern int create_basic_memory_bitmaps(void); |
76 | extern void free_basic_memory_bitmaps(void); | 76 | extern void free_basic_memory_bitmaps(void); |
77 | extern unsigned int count_data_pages(void); | 77 | extern int swsusp_shrink_memory(void); |
78 | 78 | ||
79 | /** | 79 | /** |
80 | * Auxiliary structure used for reading the snapshot image data and | 80 | * Auxiliary structure used for reading the snapshot image data and |
@@ -149,7 +149,6 @@ extern int swsusp_swap_in_use(void); | |||
149 | 149 | ||
150 | /* kernel/power/disk.c */ | 150 | /* kernel/power/disk.c */ |
151 | extern int swsusp_check(void); | 151 | extern int swsusp_check(void); |
152 | extern int swsusp_shrink_memory(void); | ||
153 | extern void swsusp_free(void); | 152 | extern void swsusp_free(void); |
154 | extern int swsusp_read(unsigned int *flags_p); | 153 | extern int swsusp_read(unsigned int *flags_p); |
155 | extern int swsusp_write(unsigned int flags); | 154 | extern int swsusp_write(unsigned int flags); |
@@ -176,7 +175,6 @@ extern int pm_notifier_call_chain(unsigned long val); | |||
176 | #endif | 175 | #endif |
177 | 176 | ||
178 | #ifdef CONFIG_HIGHMEM | 177 | #ifdef CONFIG_HIGHMEM |
179 | unsigned int count_highmem_pages(void); | ||
180 | int restore_highmem(void); | 178 | int restore_highmem(void); |
181 | #else | 179 | #else |
182 | static inline unsigned int count_highmem_pages(void) { return 0; } | 180 | static inline unsigned int count_highmem_pages(void) { return 0; } |
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index 33e2e4a819f9..523a451b45d3 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c | |||
@@ -39,6 +39,14 @@ static int swsusp_page_is_free(struct page *); | |||
39 | static void swsusp_set_page_forbidden(struct page *); | 39 | static void swsusp_set_page_forbidden(struct page *); |
40 | static void swsusp_unset_page_forbidden(struct page *); | 40 | static void swsusp_unset_page_forbidden(struct page *); |
41 | 41 | ||
42 | /* | ||
43 | * Preferred image size in bytes (tunable via /sys/power/image_size). | ||
44 | * When it is set to N, swsusp will do its best to ensure the image | ||
45 | * size will not exceed N bytes, but if that is impossible, it will | ||
46 | * try to create the smallest image possible. | ||
47 | */ | ||
48 | unsigned long image_size = 500 * 1024 * 1024; | ||
49 | |||
42 | /* List of PBEs needed for restoring the pages that were allocated before | 50 | /* List of PBEs needed for restoring the pages that were allocated before |
43 | * the suspend and included in the suspend image, but have also been | 51 | * the suspend and included in the suspend image, but have also been |
44 | * allocated by the "resume" kernel, so their contents cannot be written | 52 | * allocated by the "resume" kernel, so their contents cannot be written |
@@ -840,7 +848,7 @@ static struct page *saveable_highmem_page(struct zone *zone, unsigned long pfn) | |||
840 | * pages. | 848 | * pages. |
841 | */ | 849 | */ |
842 | 850 | ||
843 | unsigned int count_highmem_pages(void) | 851 | static unsigned int count_highmem_pages(void) |
844 | { | 852 | { |
845 | struct zone *zone; | 853 | struct zone *zone; |
846 | unsigned int n = 0; | 854 | unsigned int n = 0; |
@@ -902,7 +910,7 @@ static struct page *saveable_page(struct zone *zone, unsigned long pfn) | |||
902 | * pages. | 910 | * pages. |
903 | */ | 911 | */ |
904 | 912 | ||
905 | unsigned int count_data_pages(void) | 913 | static unsigned int count_data_pages(void) |
906 | { | 914 | { |
907 | struct zone *zone; | 915 | struct zone *zone; |
908 | unsigned long pfn, max_zone_pfn; | 916 | unsigned long pfn, max_zone_pfn; |
@@ -1058,6 +1066,74 @@ void swsusp_free(void) | |||
1058 | buffer = NULL; | 1066 | buffer = NULL; |
1059 | } | 1067 | } |
1060 | 1068 | ||
1069 | /** | ||
1070 | * swsusp_shrink_memory - Try to free as much memory as needed | ||
1071 | * | ||
1072 | * ... but do not OOM-kill anyone | ||
1073 | * | ||
1074 | * Notice: all userland should be stopped before it is called, or | ||
1075 | * livelock is possible. | ||
1076 | */ | ||
1077 | |||
1078 | #define SHRINK_BITE 10000 | ||
1079 | static inline unsigned long __shrink_memory(long tmp) | ||
1080 | { | ||
1081 | if (tmp > SHRINK_BITE) | ||
1082 | tmp = SHRINK_BITE; | ||
1083 | return shrink_all_memory(tmp); | ||
1084 | } | ||
1085 | |||
1086 | int swsusp_shrink_memory(void) | ||
1087 | { | ||
1088 | long tmp; | ||
1089 | struct zone *zone; | ||
1090 | unsigned long pages = 0; | ||
1091 | unsigned int i = 0; | ||
1092 | char *p = "-\\|/"; | ||
1093 | struct timeval start, stop; | ||
1094 | |||
1095 | printk(KERN_INFO "PM: Shrinking memory... "); | ||
1096 | do_gettimeofday(&start); | ||
1097 | do { | ||
1098 | long size, highmem_size; | ||
1099 | |||
1100 | highmem_size = count_highmem_pages(); | ||
1101 | size = count_data_pages() + PAGES_FOR_IO + SPARE_PAGES; | ||
1102 | tmp = size; | ||
1103 | size += highmem_size; | ||
1104 | for_each_populated_zone(zone) { | ||
1105 | tmp += snapshot_additional_pages(zone); | ||
1106 | if (is_highmem(zone)) { | ||
1107 | highmem_size -= | ||
1108 | zone_page_state(zone, NR_FREE_PAGES); | ||
1109 | } else { | ||
1110 | tmp -= zone_page_state(zone, NR_FREE_PAGES); | ||
1111 | tmp += zone->lowmem_reserve[ZONE_NORMAL]; | ||
1112 | } | ||
1113 | } | ||
1114 | |||
1115 | if (highmem_size < 0) | ||
1116 | highmem_size = 0; | ||
1117 | |||
1118 | tmp += highmem_size; | ||
1119 | if (tmp > 0) { | ||
1120 | tmp = __shrink_memory(tmp); | ||
1121 | if (!tmp) | ||
1122 | return -ENOMEM; | ||
1123 | pages += tmp; | ||
1124 | } else if (size > image_size / PAGE_SIZE) { | ||
1125 | tmp = __shrink_memory(size - (image_size / PAGE_SIZE)); | ||
1126 | pages += tmp; | ||
1127 | } | ||
1128 | printk("\b%c", p[i++%4]); | ||
1129 | } while (tmp > 0); | ||
1130 | do_gettimeofday(&stop); | ||
1131 | printk("\bdone (%lu pages freed)\n", pages); | ||
1132 | swsusp_show_speed(&start, &stop, pages, "Freed"); | ||
1133 | |||
1134 | return 0; | ||
1135 | } | ||
1136 | |||
1061 | #ifdef CONFIG_HIGHMEM | 1137 | #ifdef CONFIG_HIGHMEM |
1062 | /** | 1138 | /** |
1063 | * count_pages_for_highmem - compute the number of non-highmem pages | 1139 | * count_pages_for_highmem - compute the number of non-highmem pages |
diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c index 78c35047586d..87b901cb3927 100644 --- a/kernel/power/swsusp.c +++ b/kernel/power/swsusp.c | |||
@@ -55,14 +55,6 @@ | |||
55 | 55 | ||
56 | #include "power.h" | 56 | #include "power.h" |
57 | 57 | ||
58 | /* | ||
59 | * Preferred image size in bytes (tunable via /sys/power/image_size). | ||
60 | * When it is set to N, swsusp will do its best to ensure the image | ||
61 | * size will not exceed N bytes, but if that is impossible, it will | ||
62 | * try to create the smallest image possible. | ||
63 | */ | ||
64 | unsigned long image_size = 500 * 1024 * 1024; | ||
65 | |||
66 | int in_suspend __nosavedata = 0; | 58 | int in_suspend __nosavedata = 0; |
67 | 59 | ||
68 | /** | 60 | /** |
@@ -195,74 +187,6 @@ void swsusp_show_speed(struct timeval *start, struct timeval *stop, | |||
195 | kps / 1000, (kps % 1000) / 10); | 187 | kps / 1000, (kps % 1000) / 10); |
196 | } | 188 | } |
197 | 189 | ||
198 | /** | ||
199 | * swsusp_shrink_memory - Try to free as much memory as needed | ||
200 | * | ||
201 | * ... but do not OOM-kill anyone | ||
202 | * | ||
203 | * Notice: all userland should be stopped before it is called, or | ||
204 | * livelock is possible. | ||
205 | */ | ||
206 | |||
207 | #define SHRINK_BITE 10000 | ||
208 | static inline unsigned long __shrink_memory(long tmp) | ||
209 | { | ||
210 | if (tmp > SHRINK_BITE) | ||
211 | tmp = SHRINK_BITE; | ||
212 | return shrink_all_memory(tmp); | ||
213 | } | ||
214 | |||
215 | int swsusp_shrink_memory(void) | ||
216 | { | ||
217 | long tmp; | ||
218 | struct zone *zone; | ||
219 | unsigned long pages = 0; | ||
220 | unsigned int i = 0; | ||
221 | char *p = "-\\|/"; | ||
222 | struct timeval start, stop; | ||
223 | |||
224 | printk(KERN_INFO "PM: Shrinking memory... "); | ||
225 | do_gettimeofday(&start); | ||
226 | do { | ||
227 | long size, highmem_size; | ||
228 | |||
229 | highmem_size = count_highmem_pages(); | ||
230 | size = count_data_pages() + PAGES_FOR_IO + SPARE_PAGES; | ||
231 | tmp = size; | ||
232 | size += highmem_size; | ||
233 | for_each_populated_zone(zone) { | ||
234 | tmp += snapshot_additional_pages(zone); | ||
235 | if (is_highmem(zone)) { | ||
236 | highmem_size -= | ||
237 | zone_page_state(zone, NR_FREE_PAGES); | ||
238 | } else { | ||
239 | tmp -= zone_page_state(zone, NR_FREE_PAGES); | ||
240 | tmp += zone->lowmem_reserve[ZONE_NORMAL]; | ||
241 | } | ||
242 | } | ||
243 | |||
244 | if (highmem_size < 0) | ||
245 | highmem_size = 0; | ||
246 | |||
247 | tmp += highmem_size; | ||
248 | if (tmp > 0) { | ||
249 | tmp = __shrink_memory(tmp); | ||
250 | if (!tmp) | ||
251 | return -ENOMEM; | ||
252 | pages += tmp; | ||
253 | } else if (size > image_size / PAGE_SIZE) { | ||
254 | tmp = __shrink_memory(size - (image_size / PAGE_SIZE)); | ||
255 | pages += tmp; | ||
256 | } | ||
257 | printk("\b%c", p[i++%4]); | ||
258 | } while (tmp > 0); | ||
259 | do_gettimeofday(&stop); | ||
260 | printk("\bdone (%lu pages freed)\n", pages); | ||
261 | swsusp_show_speed(&start, &stop, pages, "Freed"); | ||
262 | |||
263 | return 0; | ||
264 | } | ||
265 | |||
266 | /* | 190 | /* |
267 | * Platforms, like ACPI, may want us to save some memory used by them during | 191 | * Platforms, like ACPI, may want us to save some memory used by them during |
268 | * hibernation and to restore the contents of this memory during the subsequent | 192 | * hibernation and to restore the contents of this memory during the subsequent |