diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-02-21 16:33:19 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-02-21 16:33:19 -0800 |
commit | 20f8d2a49360980f1dc0afe2ea227e3ba887e575 (patch) | |
tree | d2891d4604d3fd40da7a21650d07f83e73ae8d8e /kernel | |
parent | e6364cd3a1a3e7c3e9a80bad15698afe6cc7ee75 (diff) | |
parent | 1f1519ef597ae4628dbd47244f0f68d700231523 (diff) |
Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6
* 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6: (26 commits)
PM: Make suspend_device() static
PCI ACPI: Fix comment describing acpi_pci_choose_state
Hibernation: Handle DEBUG_PAGEALLOC on x86
ACPI: fix build warning
ACPI: TSC breaks atkbd suspend
ACPI: remove is_processor_present prototype
acer-wmi: Add DMI match for mail LED on Acer TravelMate 4200 series
ACPI: sparse fix, replace macro with static function
ACPI: thinkpad-acpi: add tablet-mode reporting
ACPI: thinkpad-acpi: minor hotkey_radio_sw fixes
ACPI: thinkpad-acpi: improve thinkpad-acpi input device documentation
ACPI: thinkpad-acpi: issue input events for tablet swivel events
ACPI: thinkpad-acpi: make the video output feature optional
ACPI: thinkpad-acpi: synchronize input device switches
ACPI: thinkpad-acpi: always track input device open/close
ACPI: thinkpad-acpi: trivial fix to documentation
ACPI: thinkpad-acpi: trivial fix to module_desc typo
intel_menlo: extract return values using PTR_ERR
ACPI video: check for error from thermal_cooling_device_register
ACPI thermal: extract return values using PTR_ERR
...
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/power/snapshot.c | 42 |
1 files changed, 29 insertions, 13 deletions
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index 95250d7c8d9..72a020cabb4 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c @@ -875,8 +875,8 @@ static inline void *saveable_highmem_page(unsigned long pfn) { return NULL; } #endif /* CONFIG_HIGHMEM */ /** - * saveable - Determine whether a non-highmem page should be included in - * the suspend image. + * saveable_page - Determine whether a non-highmem page should be included + * in the suspend image. * * We should save the page if it isn't Nosave, and is not in the range * of pages statically defined as 'unsaveable', and it isn't a part of @@ -897,7 +897,8 @@ static struct page *saveable_page(unsigned long pfn) if (swsusp_page_is_forbidden(page) || swsusp_page_is_free(page)) return NULL; - if (PageReserved(page) && pfn_is_nosave(pfn)) + if (PageReserved(page) + && (!kernel_page_present(page) || pfn_is_nosave(pfn))) return NULL; return page; @@ -938,6 +939,25 @@ static inline void do_copy_page(long *dst, long *src) *dst++ = *src++; } + +/** + * safe_copy_page - check if the page we are going to copy is marked as + * present in the kernel page tables (this always is the case if + * CONFIG_DEBUG_PAGEALLOC is not set and in that case + * kernel_page_present() always returns 'true'). + */ +static void safe_copy_page(void *dst, struct page *s_page) +{ + if (kernel_page_present(s_page)) { + do_copy_page(dst, page_address(s_page)); + } else { + kernel_map_pages(s_page, 1, 1); + do_copy_page(dst, page_address(s_page)); + kernel_map_pages(s_page, 1, 0); + } +} + + #ifdef CONFIG_HIGHMEM static inline struct page * page_is_saveable(struct zone *zone, unsigned long pfn) @@ -946,8 +966,7 @@ page_is_saveable(struct zone *zone, unsigned long pfn) saveable_highmem_page(pfn) : saveable_page(pfn); } -static inline void -copy_data_page(unsigned long dst_pfn, unsigned long src_pfn) +static void copy_data_page(unsigned long dst_pfn, unsigned long src_pfn) { struct page *s_page, *d_page; void *src, *dst; @@ -961,29 +980,26 @@ copy_data_page(unsigned long dst_pfn, unsigned long src_pfn) kunmap_atomic(src, KM_USER0); kunmap_atomic(dst, KM_USER1); } else { - src = page_address(s_page); if (PageHighMem(d_page)) { /* Page pointed to by src may contain some kernel * data modified by kmap_atomic() */ - do_copy_page(buffer, src); + safe_copy_page(buffer, s_page); dst = kmap_atomic(pfn_to_page(dst_pfn), KM_USER0); memcpy(dst, buffer, PAGE_SIZE); kunmap_atomic(dst, KM_USER0); } else { - dst = page_address(d_page); - do_copy_page(dst, src); + safe_copy_page(page_address(d_page), s_page); } } } #else #define page_is_saveable(zone, pfn) saveable_page(pfn) -static inline void -copy_data_page(unsigned long dst_pfn, unsigned long src_pfn) +static inline void copy_data_page(unsigned long dst_pfn, unsigned long src_pfn) { - do_copy_page(page_address(pfn_to_page(dst_pfn)), - page_address(pfn_to_page(src_pfn))); + safe_copy_page(page_address(pfn_to_page(dst_pfn)), + pfn_to_page(src_pfn)); } #endif /* CONFIG_HIGHMEM */ |