diff options
Diffstat (limited to 'kernel/power/snapshot.c')
-rw-r--r-- | kernel/power/snapshot.c | 62 |
1 files changed, 32 insertions, 30 deletions
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index 591301ae8b7d..979096c27773 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c | |||
@@ -156,7 +156,7 @@ static inline int save_highmem(void) {return 0;} | |||
156 | static inline int restore_highmem(void) {return 0;} | 156 | static inline int restore_highmem(void) {return 0;} |
157 | #endif | 157 | #endif |
158 | 158 | ||
159 | static int pfn_is_nosave(unsigned long pfn) | 159 | static inline int pfn_is_nosave(unsigned long pfn) |
160 | { | 160 | { |
161 | unsigned long nosave_begin_pfn = __pa(&__nosave_begin) >> PAGE_SHIFT; | 161 | unsigned long nosave_begin_pfn = __pa(&__nosave_begin) >> PAGE_SHIFT; |
162 | unsigned long nosave_end_pfn = PAGE_ALIGN(__pa(&__nosave_end)) >> PAGE_SHIFT; | 162 | unsigned long nosave_end_pfn = PAGE_ALIGN(__pa(&__nosave_end)) >> PAGE_SHIFT; |
@@ -167,43 +167,43 @@ static int pfn_is_nosave(unsigned long pfn) | |||
167 | * saveable - Determine whether a page should be cloned or not. | 167 | * saveable - Determine whether a page should be cloned or not. |
168 | * @pfn: The page | 168 | * @pfn: The page |
169 | * | 169 | * |
170 | * We save a page if it's Reserved, and not in the range of pages | 170 | * We save a page if it isn't Nosave, and is not in the range of pages |
171 | * statically defined as 'unsaveable', or if it isn't reserved, and | 171 | * statically defined as 'unsaveable', and it |
172 | * isn't part of a free chunk of pages. | 172 | * isn't a part of a free chunk of pages. |
173 | */ | 173 | */ |
174 | 174 | ||
175 | static int saveable(struct zone *zone, unsigned long *zone_pfn) | 175 | static struct page *saveable_page(unsigned long pfn) |
176 | { | 176 | { |
177 | unsigned long pfn = *zone_pfn + zone->zone_start_pfn; | ||
178 | struct page *page; | 177 | struct page *page; |
179 | 178 | ||
180 | if (!pfn_valid(pfn)) | 179 | if (!pfn_valid(pfn)) |
181 | return 0; | 180 | return NULL; |
182 | 181 | ||
183 | page = pfn_to_page(pfn); | 182 | page = pfn_to_page(pfn); |
184 | BUG_ON(PageReserved(page) && PageNosave(page)); | 183 | |
185 | if (PageNosave(page)) | 184 | if (PageNosave(page)) |
186 | return 0; | 185 | return NULL; |
187 | if (PageReserved(page) && pfn_is_nosave(pfn)) | 186 | if (PageReserved(page) && pfn_is_nosave(pfn)) |
188 | return 0; | 187 | return NULL; |
189 | if (PageNosaveFree(page)) | 188 | if (PageNosaveFree(page)) |
190 | return 0; | 189 | return NULL; |
191 | 190 | ||
192 | return 1; | 191 | return page; |
193 | } | 192 | } |
194 | 193 | ||
195 | unsigned int count_data_pages(void) | 194 | unsigned int count_data_pages(void) |
196 | { | 195 | { |
197 | struct zone *zone; | 196 | struct zone *zone; |
198 | unsigned long zone_pfn; | 197 | unsigned long pfn, max_zone_pfn; |
199 | unsigned int n = 0; | 198 | unsigned int n = 0; |
200 | 199 | ||
201 | for_each_zone (zone) { | 200 | for_each_zone (zone) { |
202 | if (is_highmem(zone)) | 201 | if (is_highmem(zone)) |
203 | continue; | 202 | continue; |
204 | mark_free_pages(zone); | 203 | mark_free_pages(zone); |
205 | for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn) | 204 | max_zone_pfn = zone->zone_start_pfn + zone->spanned_pages; |
206 | n += saveable(zone, &zone_pfn); | 205 | for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++) |
206 | n += !!saveable_page(pfn); | ||
207 | } | 207 | } |
208 | return n; | 208 | return n; |
209 | } | 209 | } |
@@ -211,7 +211,7 @@ unsigned int count_data_pages(void) | |||
211 | static void copy_data_pages(struct pbe *pblist) | 211 | static void copy_data_pages(struct pbe *pblist) |
212 | { | 212 | { |
213 | struct zone *zone; | 213 | struct zone *zone; |
214 | unsigned long zone_pfn; | 214 | unsigned long pfn, max_zone_pfn; |
215 | struct pbe *pbe, *p; | 215 | struct pbe *pbe, *p; |
216 | 216 | ||
217 | pbe = pblist; | 217 | pbe = pblist; |
@@ -224,13 +224,14 @@ static void copy_data_pages(struct pbe *pblist) | |||
224 | SetPageNosaveFree(virt_to_page(p)); | 224 | SetPageNosaveFree(virt_to_page(p)); |
225 | for_each_pbe (p, pblist) | 225 | for_each_pbe (p, pblist) |
226 | SetPageNosaveFree(virt_to_page(p->address)); | 226 | SetPageNosaveFree(virt_to_page(p->address)); |
227 | for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn) { | 227 | max_zone_pfn = zone->zone_start_pfn + zone->spanned_pages; |
228 | if (saveable(zone, &zone_pfn)) { | 228 | for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++) { |
229 | struct page *page; | 229 | struct page *page = saveable_page(pfn); |
230 | |||
231 | if (page) { | ||
230 | long *src, *dst; | 232 | long *src, *dst; |
231 | int n; | 233 | int n; |
232 | 234 | ||
233 | page = pfn_to_page(zone_pfn + zone->zone_start_pfn); | ||
234 | BUG_ON(!pbe); | 235 | BUG_ON(!pbe); |
235 | pbe->orig_address = (unsigned long)page_address(page); | 236 | pbe->orig_address = (unsigned long)page_address(page); |
236 | /* copy_page and memcpy are not usable for copying task structs. */ | 237 | /* copy_page and memcpy are not usable for copying task structs. */ |
@@ -383,13 +384,14 @@ static struct pbe *alloc_pagedir(unsigned int nr_pages, gfp_t gfp_mask, | |||
383 | void swsusp_free(void) | 384 | void swsusp_free(void) |
384 | { | 385 | { |
385 | struct zone *zone; | 386 | struct zone *zone; |
386 | unsigned long zone_pfn; | 387 | unsigned long pfn, max_zone_pfn; |
387 | 388 | ||
388 | for_each_zone(zone) { | 389 | for_each_zone(zone) { |
389 | for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn) | 390 | max_zone_pfn = zone->zone_start_pfn + zone->spanned_pages; |
390 | if (pfn_valid(zone_pfn + zone->zone_start_pfn)) { | 391 | for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++) |
391 | struct page *page; | 392 | if (pfn_valid(pfn)) { |
392 | page = pfn_to_page(zone_pfn + zone->zone_start_pfn); | 393 | struct page *page = pfn_to_page(pfn); |
394 | |||
393 | if (PageNosave(page) && PageNosaveFree(page)) { | 395 | if (PageNosave(page) && PageNosaveFree(page)) { |
394 | ClearPageNosave(page); | 396 | ClearPageNosave(page); |
395 | ClearPageNosaveFree(page); | 397 | ClearPageNosaveFree(page); |
@@ -598,7 +600,7 @@ int snapshot_read_next(struct snapshot_handle *handle, size_t count) | |||
598 | static int mark_unsafe_pages(struct pbe *pblist) | 600 | static int mark_unsafe_pages(struct pbe *pblist) |
599 | { | 601 | { |
600 | struct zone *zone; | 602 | struct zone *zone; |
601 | unsigned long zone_pfn; | 603 | unsigned long pfn, max_zone_pfn; |
602 | struct pbe *p; | 604 | struct pbe *p; |
603 | 605 | ||
604 | if (!pblist) /* a sanity check */ | 606 | if (!pblist) /* a sanity check */ |
@@ -606,10 +608,10 @@ static int mark_unsafe_pages(struct pbe *pblist) | |||
606 | 608 | ||
607 | /* Clear page flags */ | 609 | /* Clear page flags */ |
608 | for_each_zone (zone) { | 610 | for_each_zone (zone) { |
609 | for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn) | 611 | max_zone_pfn = zone->zone_start_pfn + zone->spanned_pages; |
610 | if (pfn_valid(zone_pfn + zone->zone_start_pfn)) | 612 | for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++) |
611 | ClearPageNosaveFree(pfn_to_page(zone_pfn + | 613 | if (pfn_valid(pfn)) |
612 | zone->zone_start_pfn)); | 614 | ClearPageNosaveFree(pfn_to_page(pfn)); |
613 | } | 615 | } |
614 | 616 | ||
615 | /* Mark orig addresses */ | 617 | /* Mark orig addresses */ |