| From f5295bd8ea8a65dc5eac608b151386314cb978f1 Mon Sep 17 00:00:00 2001 |
| From: Laurent Dufour <ldufour@linux.vnet.ibm.com> |
| Date: Mon, 24 Feb 2014 17:30:55 +0100 |
| Subject: powerpc/crashdump : Fix page frame number check in copy_oldmem_page |
| |
| From: Laurent Dufour <ldufour@linux.vnet.ibm.com> |
| |
| commit f5295bd8ea8a65dc5eac608b151386314cb978f1 upstream. |
| |
| 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> |
| Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| arch/powerpc/kernel/crash_dump.c | 8 +++++--- |
| 1 file changed, 5 insertions(+), 3 deletions(-) |
| |
| --- 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 p |
| size_t csize, unsigned long offset, int userbuf) |
| { |
| void *vaddr; |
| + phys_addr_t paddr; |
| |
| if (!csize) |
| return 0; |
| |
| csize = min_t(size_t, csize, PAGE_SIZE); |
| + paddr = pfn << PAGE_SHIFT; |
| |
| - if ((min_low_pfn < pfn) && (pfn < max_pfn)) { |
| - vaddr = __va(pfn << PAGE_SHIFT); |
| + if (memblock_is_region_memory(paddr, csize)) { |
| + vaddr = __va(paddr); |
| csize = copy_oldmem_vaddr(vaddr, buf, csize, offset, userbuf); |
| } else { |
| - vaddr = __ioremap(pfn << PAGE_SHIFT, PAGE_SIZE, 0); |
| + vaddr = __ioremap(paddr, PAGE_SIZE, 0); |
| csize = copy_oldmem_vaddr(vaddr, buf, csize, offset, userbuf); |
| iounmap(vaddr); |
| } |