diff options
author | Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com> | 2014-02-27 00:30:37 +0530 |
---|---|---|
committer | Eli Qiao <taget@linux.vnet.ibm.com> | 2014-03-04 11:46:02 +0800 |
commit | 63b4cc86c1a599279eba0cc7f7d19654097edb22 (patch) | |
tree | 72edbc4a36cb976514bdd460ae3f0e5591e80c57 | |
parent | c1254f03e260a94128c2765d2b52a9e639d0cb5e (diff) | |
download | powerkvm-63b4cc86c1a599279eba0cc7f7d19654097edb22.tar.gz |
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.
This is a backport of upstream patch
https://lists.ozlabs.org/pipermail/linuxppc-dev/2014-February/115569.html
This fixes LTC BUG #104729
Signed-off-by: Laurent Dufour <ldufour@linux.vnet.ibm.com>
Tested-by: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
-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 9ec3fe174cba7c..555ae67e4086c1 100644 --- a/arch/powerpc/kernel/crash_dump.c +++ b/arch/powerpc/kernel/crash_dump.c @@ -108,17 +108,19 @@ ssize_t copy_oldmem_page(unsigned long pfn, char *buf, 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); } |