Resolves: bz1097904 https://bugzilla.redhat.com/show_bug.cgi?id=1097904
This is back ported from upstream. It need be edited manually since several irrelevant commits are not back ported. commit 191a2fa0a8d2bbb64c98f9b1976fcb37ee5eae6b Author: Michael Holzheu <holz...@linux.vnet.ibm.com> Date: Thu Jul 18 12:18:27 2013 +0200 s390/kdump: Allow copy_oldmem_page() copy to virtual memory The kdump mmap patch series (git commit 83086978c63afd7c73e1c) changed the requirements for copy_oldmem_page(). Now this function is used for copying to virtual memory. So implement vmalloc support for the s390 version of copy_oldmem_page(). Signed-off-by: Michael Holzheu <holz...@linux.vnet.ibm.com> Signed-off-by: Martin Schwidefsky <schwidef...@de.ibm.com> Signed-off-by: Baoquan He <b...@redhat.com> --- arch/s390/kernel/crash_dump.c | 49 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/arch/s390/kernel/crash_dump.c b/arch/s390/kernel/crash_dump.c index b66edb9..0f70217 100644 --- a/arch/s390/kernel/crash_dump.c +++ b/arch/s390/kernel/crash_dump.c @@ -56,6 +56,47 @@ static int __init setup_elfcorehdr(char *arg) early_param("elfcorehdr", setup_elfcorehdr); /* + * Return physical address for virtual address + */ +static inline void *load_real_addr(void *addr) +{ + unsigned long real_addr; + + asm volatile( + " lra %0,0(%1)\n" + " jz 0f\n" + " la %0,0\n" + "0:" + : "=a" (real_addr) : "a" (addr) : "cc"); + return (void *)real_addr; +} + +/* + * Copy up to one page to vmalloc or real memory + */ +static ssize_t copy_page_real(void *buf, void *src, size_t csize) +{ + size_t size; + + if (is_vmalloc_addr(buf)) { + BUG_ON(csize >= PAGE_SIZE); + /* If buf is not page aligned, copy first part */ + size = min(roundup(__pa(buf), PAGE_SIZE) - __pa(buf), csize); + if (size) { + if (memcpy_real(load_real_addr(buf), src, size)) + return -EFAULT; + buf += size; + src += size; + } + /* Copy second part */ + size = csize - size; + return (size) ? memcpy_real(load_real_addr(buf), src, size) : 0; + } else { + return memcpy_real(buf, src, csize); + } +} + +/* * Copy one page from "oldmem" * * For the kdump reserved memory this functions performs a swap operation: @@ -66,6 +107,7 @@ ssize_t copy_oldmem_page(unsigned long pfn, char *buf, size_t csize, unsigned long offset, int userbuf) { unsigned long src; + int rc; if (!csize) return 0; @@ -77,10 +119,11 @@ ssize_t copy_oldmem_page(unsigned long pfn, char *buf, src < OLDMEM_BASE + OLDMEM_SIZE) src -= OLDMEM_BASE; if (userbuf) - copy_to_user_real((void __user *) buf, (void *) src, csize); + rc = copy_to_user_real((void __force __user *) buf, + (void *) src, csize); else - memcpy_real(buf, (void *) src, csize); - return csize; + rc = copy_page_real(buf, (void *) src, csize); + return (rc == 0) ? csize : rc; } /* -- 2.1.0 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/