diff options
Diffstat (limited to 'kernel/power/snapshot.c')
-rw-r--r-- | kernel/power/snapshot.c | 65 |
1 files changed, 60 insertions, 5 deletions
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index 152d56cdf017..e80d282dbf58 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c | |||
@@ -37,6 +37,31 @@ struct pbe *pagedir_nosave; | |||
37 | unsigned int nr_copy_pages; | 37 | unsigned int nr_copy_pages; |
38 | 38 | ||
39 | #ifdef CONFIG_HIGHMEM | 39 | #ifdef CONFIG_HIGHMEM |
40 | unsigned int count_highmem_pages(void) | ||
41 | { | ||
42 | struct zone *zone; | ||
43 | unsigned long zone_pfn; | ||
44 | unsigned int n = 0; | ||
45 | |||
46 | for_each_zone (zone) | ||
47 | if (is_highmem(zone)) { | ||
48 | mark_free_pages(zone); | ||
49 | for (zone_pfn = 0; zone_pfn < zone->spanned_pages; zone_pfn++) { | ||
50 | struct page *page; | ||
51 | unsigned long pfn = zone_pfn + zone->zone_start_pfn; | ||
52 | if (!pfn_valid(pfn)) | ||
53 | continue; | ||
54 | page = pfn_to_page(pfn); | ||
55 | if (PageReserved(page)) | ||
56 | continue; | ||
57 | if (PageNosaveFree(page)) | ||
58 | continue; | ||
59 | n++; | ||
60 | } | ||
61 | } | ||
62 | return n; | ||
63 | } | ||
64 | |||
40 | struct highmem_page { | 65 | struct highmem_page { |
41 | char *data; | 66 | char *data; |
42 | struct page *page; | 67 | struct page *page; |
@@ -152,17 +177,15 @@ static int saveable(struct zone *zone, unsigned long *zone_pfn) | |||
152 | BUG_ON(PageReserved(page) && PageNosave(page)); | 177 | BUG_ON(PageReserved(page) && PageNosave(page)); |
153 | if (PageNosave(page)) | 178 | if (PageNosave(page)) |
154 | return 0; | 179 | return 0; |
155 | if (PageReserved(page) && pfn_is_nosave(pfn)) { | 180 | if (PageReserved(page) && pfn_is_nosave(pfn)) |
156 | pr_debug("[nosave pfn 0x%lx]", pfn); | ||
157 | return 0; | 181 | return 0; |
158 | } | ||
159 | if (PageNosaveFree(page)) | 182 | if (PageNosaveFree(page)) |
160 | return 0; | 183 | return 0; |
161 | 184 | ||
162 | return 1; | 185 | return 1; |
163 | } | 186 | } |
164 | 187 | ||
165 | static unsigned count_data_pages(void) | 188 | unsigned int count_data_pages(void) |
166 | { | 189 | { |
167 | struct zone *zone; | 190 | struct zone *zone; |
168 | unsigned long zone_pfn; | 191 | unsigned long zone_pfn; |
@@ -267,6 +290,35 @@ static inline void create_pbe_list(struct pbe *pblist, unsigned int nr_pages) | |||
267 | } | 290 | } |
268 | 291 | ||
269 | /** | 292 | /** |
293 | * On resume it is necessary to trace and eventually free the unsafe | ||
294 | * pages that have been allocated, because they are needed for I/O | ||
295 | * (on x86-64 we likely will "eat" these pages once again while | ||
296 | * creating the temporary page translation tables) | ||
297 | */ | ||
298 | |||
299 | struct eaten_page { | ||
300 | struct eaten_page *next; | ||
301 | char padding[PAGE_SIZE - sizeof(void *)]; | ||
302 | }; | ||
303 | |||
304 | static struct eaten_page *eaten_pages = NULL; | ||
305 | |||
306 | void release_eaten_pages(void) | ||
307 | { | ||
308 | struct eaten_page *p, *q; | ||
309 | |||
310 | p = eaten_pages; | ||
311 | while (p) { | ||
312 | q = p->next; | ||
313 | /* We don't want swsusp_free() to free this page again */ | ||
314 | ClearPageNosave(virt_to_page(p)); | ||
315 | free_page((unsigned long)p); | ||
316 | p = q; | ||
317 | } | ||
318 | eaten_pages = NULL; | ||
319 | } | ||
320 | |||
321 | /** | ||
270 | * @safe_needed - on resume, for storing the PBE list and the image, | 322 | * @safe_needed - on resume, for storing the PBE list and the image, |
271 | * we can only use memory pages that do not conflict with the pages | 323 | * we can only use memory pages that do not conflict with the pages |
272 | * which had been used before suspend. | 324 | * which had been used before suspend. |
@@ -284,9 +336,12 @@ static inline void *alloc_image_page(gfp_t gfp_mask, int safe_needed) | |||
284 | if (safe_needed) | 336 | if (safe_needed) |
285 | do { | 337 | do { |
286 | res = (void *)get_zeroed_page(gfp_mask); | 338 | res = (void *)get_zeroed_page(gfp_mask); |
287 | if (res && PageNosaveFree(virt_to_page(res))) | 339 | if (res && PageNosaveFree(virt_to_page(res))) { |
288 | /* This is for swsusp_free() */ | 340 | /* This is for swsusp_free() */ |
289 | SetPageNosave(virt_to_page(res)); | 341 | SetPageNosave(virt_to_page(res)); |
342 | ((struct eaten_page *)res)->next = eaten_pages; | ||
343 | eaten_pages = res; | ||
344 | } | ||
290 | } while (res && PageNosaveFree(virt_to_page(res))); | 345 | } while (res && PageNosaveFree(virt_to_page(res))); |
291 | else | 346 | else |
292 | res = (void *)get_zeroed_page(gfp_mask); | 347 | res = (void *)get_zeroed_page(gfp_mask); |