diff options
author | Laurent Dufour <ldufour@linux.vnet.ibm.com> | 2014-02-24 11:30:55 -0500 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2014-02-28 02:06:25 -0500 |
commit | f5295bd8ea8a65dc5eac608b151386314cb978f1 (patch) | |
tree | 826f84e36044824ce00d8af118afc720078e37e8 /arch/powerpc/kernel/crash_dump.c | |
parent | 41dd03a94c7d408d2ef32530545097f7d1befe5c (diff) |
powerpc/crashdump : Fix page frame number check in copy_oldmem_page
In copy_oldmem_page, the current check using max_pfn and min_low_pfn to
decide if the page is backed or not, is not valid when the memory layout is
not continuous.
This happens when running as a QEMU/KVM guest, where RTAS is mapped higher
in the memory. In that case max_pfn points to the end of RTAS, and a hole
between the end of the kdump kernel and RTAS is not backed by PTEs. As a
consequence, the kdump kernel is crashing in copy_oldmem_page when accessing
in a direct way the pages in that hole.
This fix relies on the memblock's service memblock_is_region_memory to
check if the read page is part or not of the directly accessible memory.
Signed-off-by: Laurent Dufour <ldufour@linux.vnet.ibm.com>
Tested-by: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
CC: <stable@vger.kernel.org>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/kernel/crash_dump.c')
-rw-r--r-- | arch/powerpc/kernel/crash_dump.c | 8 |
1 files changed, 5 insertions, 3 deletions
diff --git a/arch/powerpc/kernel/crash_dump.c b/arch/powerpc/kernel/crash_dump.c index 11c1d069d920..7a13f378ca2c 100644 --- a/arch/powerpc/kernel/crash_dump.c +++ b/arch/powerpc/kernel/crash_dump.c | |||
@@ -98,17 +98,19 @@ ssize_t copy_oldmem_page(unsigned long pfn, char *buf, | |||
98 | size_t csize, unsigned long offset, int userbuf) | 98 | size_t csize, unsigned long offset, int userbuf) |
99 | { | 99 | { |
100 | void *vaddr; | 100 | void *vaddr; |
101 | phys_addr_t paddr; | ||
101 | 102 | ||
102 | if (!csize) | 103 | if (!csize) |
103 | return 0; | 104 | return 0; |
104 | 105 | ||
105 | csize = min_t(size_t, csize, PAGE_SIZE); | 106 | csize = min_t(size_t, csize, PAGE_SIZE); |
107 | paddr = pfn << PAGE_SHIFT; | ||
106 | 108 | ||
107 | if ((min_low_pfn < pfn) && (pfn < max_pfn)) { | 109 | if (memblock_is_region_memory(paddr, csize)) { |
108 | vaddr = __va(pfn << PAGE_SHIFT); | 110 | vaddr = __va(paddr); |
109 | csize = copy_oldmem_vaddr(vaddr, buf, csize, offset, userbuf); | 111 | csize = copy_oldmem_vaddr(vaddr, buf, csize, offset, userbuf); |
110 | } else { | 112 | } else { |
111 | vaddr = __ioremap(pfn << PAGE_SHIFT, PAGE_SIZE, 0); | 113 | vaddr = __ioremap(paddr, PAGE_SIZE, 0); |
112 | csize = copy_oldmem_vaddr(vaddr, buf, csize, offset, userbuf); | 114 | csize = copy_oldmem_vaddr(vaddr, buf, csize, offset, userbuf); |
113 | iounmap(vaddr); | 115 | iounmap(vaddr); |
114 | } | 116 | } |