diff options
author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2015-10-12 10:43:37 +0200 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2015-11-27 09:24:12 +0100 |
commit | df9694c7975ff9976368eb381388c61f65352aef (patch) | |
tree | 3f6fd34b593582248a293a9eaa4f89ae347ef169 /arch/s390/kernel/crash_dump.c | |
parent | 8a07dd02d7615d91d65d6235f7232e3f9b5d347f (diff) | |
download | linux-df9694c7975ff9976368eb381388c61f65352aef.tar.bz2 |
s390/dump: streamline oldmem copy functions
Introduce two copy functions for the memory of the dumped system,
copy_oldmem_kernel() to copy to the virtual kernel address space
and copy_oldmem_user() to copy to user space.
Acked-by: Michael Holzheu <holzheu@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390/kernel/crash_dump.c')
-rw-r--r-- | arch/s390/kernel/crash_dump.c | 171 |
1 files changed, 79 insertions, 92 deletions
diff --git a/arch/s390/kernel/crash_dump.c b/arch/s390/kernel/crash_dump.c index 07d75b969f59..0d59c0705c4f 100644 --- a/arch/s390/kernel/crash_dump.c +++ b/arch/s390/kernel/crash_dump.c @@ -51,74 +51,85 @@ static inline void *load_real_addr(void *addr) } /* - * Copy real to virtual or real memory + * Copy memory of the old, dumped system to a kernel space virtual address */ -static int copy_from_realmem(void *dest, void *src, size_t count) -{ - unsigned long size; - - if (!count) - return 0; - if (!is_vmalloc_or_module_addr(dest)) - return memcpy_real(dest, src, count); - do { - size = min(count, PAGE_SIZE - (__pa(dest) & ~PAGE_MASK)); - if (memcpy_real(load_real_addr(dest), src, size)) - return -EFAULT; - count -= size; - dest += size; - src += size; - } while (count); - return 0; -} - -/* - * Copy one page from zfcpdump "oldmem" - * - * For pages below HSA size memory from the HSA is copied. Otherwise - * real memory copy is used. - */ -static ssize_t copy_oldmem_page_zfcpdump(char *buf, size_t csize, - unsigned long src, int userbuf) +int copy_oldmem_kernel(void *dst, void *src, size_t count) { + unsigned long from, len; + void *ra; int rc; - if (src < sclp.hsa_size) { - rc = memcpy_hsa(buf, src, csize, userbuf); - } else { - if (userbuf) - rc = copy_to_user_real((void __force __user *) buf, - (void *) src, csize); - else - rc = memcpy_real(buf, (void *) src, csize); + while (count) { + from = __pa(src); + if (!OLDMEM_BASE && from < sclp.hsa_size) { + /* Copy from zfcpdump HSA area */ + len = min(count, sclp.hsa_size - from); + rc = memcpy_hsa_kernel(dst, from, len); + if (rc) + return rc; + } else { + /* Check for swapped kdump oldmem areas */ + if (OLDMEM_BASE && from - OLDMEM_BASE < OLDMEM_SIZE) { + from -= OLDMEM_BASE; + len = min(count, OLDMEM_SIZE - from); + } else if (OLDMEM_BASE && from < OLDMEM_SIZE) { + len = min(count, OLDMEM_SIZE - from); + from += OLDMEM_BASE; + } else { + len = count; + } + if (is_vmalloc_or_module_addr(dst)) { + ra = load_real_addr(dst); + len = min(PAGE_SIZE - offset_in_page(ra), len); + } else { + ra = dst; + } + if (memcpy_real(ra, (void *) from, len)) + return -EFAULT; + } + dst += len; + src += len; + count -= len; } - return rc ? rc : csize; + return 0; } /* - * Copy one page from kdump "oldmem" - * - * For the kdump reserved memory this functions performs a swap operation: - * - [OLDMEM_BASE - OLDMEM_BASE + OLDMEM_SIZE] is mapped to [0 - OLDMEM_SIZE]. - * - [0 - OLDMEM_SIZE] is mapped to [OLDMEM_BASE - OLDMEM_BASE + OLDMEM_SIZE] + * Copy memory of the old, dumped system to a user space virtual address */ -static ssize_t copy_oldmem_page_kdump(char *buf, size_t csize, - unsigned long src, int userbuf) - +int copy_oldmem_user(void __user *dst, void *src, size_t count) { + unsigned long from, len; int rc; - if (src < OLDMEM_SIZE) - src += OLDMEM_BASE; - else if (src > OLDMEM_BASE && - src < OLDMEM_BASE + OLDMEM_SIZE) - src -= OLDMEM_BASE; - if (userbuf) - rc = copy_to_user_real((void __force __user *) buf, - (void *) src, csize); - else - rc = copy_from_realmem(buf, (void *) src, csize); - return (rc == 0) ? rc : csize; + while (count) { + from = __pa(src); + if (!OLDMEM_BASE && from < sclp.hsa_size) { + /* Copy from zfcpdump HSA area */ + len = min(count, sclp.hsa_size - from); + rc = memcpy_hsa_user(dst, from, len); + if (rc) + return rc; + } else { + /* Check for swapped kdump oldmem areas */ + if (OLDMEM_BASE && from - OLDMEM_BASE < OLDMEM_SIZE) { + from -= OLDMEM_BASE; + len = min(count, OLDMEM_SIZE - from); + } else if (OLDMEM_BASE && from < OLDMEM_SIZE) { + len = min(count, OLDMEM_SIZE - from); + from += OLDMEM_BASE; + } else { + len = count; + } + rc = copy_to_user_real(dst, (void *) from, count); + if (rc) + return rc; + } + dst += len; + src += len; + count -= len; + } + return 0; } /* @@ -127,15 +138,17 @@ static ssize_t copy_oldmem_page_kdump(char *buf, size_t csize, ssize_t copy_oldmem_page(unsigned long pfn, char *buf, size_t csize, unsigned long offset, int userbuf) { - unsigned long src; + void *src; + int rc; if (!csize) return 0; - src = (pfn << PAGE_SHIFT) + offset; - if (OLDMEM_BASE) - return copy_oldmem_page_kdump(buf, csize, src, userbuf); + src = (void *) (pfn << PAGE_SHIFT) + offset; + if (userbuf) + rc = copy_oldmem_user((void __force __user *) buf, src, csize); else - return copy_oldmem_page_zfcpdump(buf, csize, src, userbuf); + rc = copy_oldmem_kernel((void *) buf, src, csize); + return rc; } /* @@ -204,33 +217,6 @@ int remap_oldmem_pfn_range(struct vm_area_struct *vma, unsigned long from, } /* - * Copy memory from old kernel - */ -int copy_from_oldmem(void *dest, void *src, size_t count) -{ - unsigned long copied = 0; - int rc; - - if (OLDMEM_BASE) { - if ((unsigned long) src < OLDMEM_SIZE) { - copied = min(count, OLDMEM_SIZE - (unsigned long) src); - rc = copy_from_realmem(dest, src + OLDMEM_BASE, copied); - if (rc) - return rc; - } - } else { - unsigned long hsa_end = sclp.hsa_size; - if ((unsigned long) src < hsa_end) { - copied = min(count, hsa_end - (unsigned long) src); - rc = memcpy_hsa(dest, (unsigned long) src, copied, 0); - if (rc) - return rc; - } - } - return copy_from_realmem(dest + copied, src + copied, count - copied); -} - -/* * Alloc memory and panic in case of ENOMEM */ static void *kzalloc_panic(int len) @@ -425,17 +411,18 @@ static void *get_vmcoreinfo_old(unsigned long *size) Elf64_Nhdr note; void *addr; - if (copy_from_oldmem(&addr, &S390_lowcore.vmcore_info, sizeof(addr))) + if (copy_oldmem_kernel(&addr, &S390_lowcore.vmcore_info, sizeof(addr))) return NULL; memset(nt_name, 0, sizeof(nt_name)); - if (copy_from_oldmem(¬e, addr, sizeof(note))) + if (copy_oldmem_kernel(¬e, addr, sizeof(note))) return NULL; - if (copy_from_oldmem(nt_name, addr + sizeof(note), sizeof(nt_name) - 1)) + if (copy_oldmem_kernel(nt_name, addr + sizeof(note), + sizeof(nt_name) - 1)) return NULL; if (strcmp(nt_name, "VMCOREINFO") != 0) return NULL; vmcoreinfo = kzalloc_panic(note.n_descsz); - if (copy_from_oldmem(vmcoreinfo, addr + 24, note.n_descsz)) + if (copy_oldmem_kernel(vmcoreinfo, addr + 24, note.n_descsz)) return NULL; *size = note.n_descsz; return vmcoreinfo; |