s390/dump: streamline oldmem copy functions
authorMartin Schwidefsky <schwidefsky@de.ibm.com>
Mon, 12 Oct 2015 08:43:37 +0000 (10:43 +0200)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Fri, 27 Nov 2015 08:24:12 +0000 (09:24 +0100)
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>
arch/s390/include/asm/os_info.h
arch/s390/include/asm/sclp.h
arch/s390/kernel/crash_dump.c
arch/s390/kernel/os_info.c
arch/s390/kernel/smp.c
drivers/s390/char/zcore.c

index 295f2c4..9434753 100644 (file)
@@ -38,7 +38,7 @@ u32 os_info_csum(struct os_info *os_info);
 
 #ifdef CONFIG_CRASH_DUMP
 void *os_info_old_entry(int nr, unsigned long *size);
-int copy_from_oldmem(void *dest, void *src, size_t count);
+int copy_oldmem_kernel(void *dst, void *src, size_t count);
 #else
 static inline void *os_info_old_entry(int nr, unsigned long *size)
 {
index 821dde5..2ca9c7b 100644 (file)
@@ -77,7 +77,8 @@ int sclp_chp_read_info(struct sclp_chp_info *info);
 void sclp_get_ipl_info(struct sclp_ipl_info *info);
 int sclp_pci_configure(u32 fid);
 int sclp_pci_deconfigure(u32 fid);
-int memcpy_hsa(void *dest, unsigned long src, size_t count, int mode);
+int memcpy_hsa_kernel(void *dest, unsigned long src, size_t count);
+int memcpy_hsa_user(void __user *dest, unsigned long src, size_t count);
 void sclp_early_detect(void);
 int _sclp_print_early(const char *);
 
index 07d75b9..0d59c07 100644 (file)
@@ -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;
 }
 
 /*
@@ -203,33 +216,6 @@ int remap_oldmem_pfn_range(struct vm_area_struct *vma, unsigned long from,
                                                       prot);
 }
 
-/*
- * 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
  */
@@ -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(&note, addr, sizeof(note)))
+       if (copy_oldmem_kernel(&note, 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;
index d112fc6..87f05e4 100644 (file)
@@ -89,7 +89,7 @@ static void os_info_old_alloc(int nr, int align)
                goto fail;
        }
        buf_align = PTR_ALIGN(buf, align);
-       if (copy_from_oldmem(buf_align, (void *) addr, size)) {
+       if (copy_oldmem_kernel(buf_align, (void *) addr, size)) {
                msg = "copy failed";
                goto fail_free;
        }
@@ -122,14 +122,15 @@ static void os_info_old_init(void)
                return;
        if (!OLDMEM_BASE)
                goto fail;
-       if (copy_from_oldmem(&addr, &S390_lowcore.os_info, sizeof(addr)))
+       if (copy_oldmem_kernel(&addr, &S390_lowcore.os_info, sizeof(addr)))
                goto fail;
        if (addr == 0 || addr % PAGE_SIZE)
                goto fail;
        os_info_old = kzalloc(sizeof(*os_info_old), GFP_KERNEL);
        if (!os_info_old)
                goto fail;
-       if (copy_from_oldmem(os_info_old, (void *) addr, sizeof(*os_info_old)))
+       if (copy_oldmem_kernel(os_info_old, (void *) addr,
+                              sizeof(*os_info_old)))
                goto fail_free;
        if (os_info_old->magic != OS_INFO_MAGIC)
                goto fail_free;
index 7ad070e..5e04acd 100644 (file)
@@ -546,8 +546,8 @@ static void __init __smp_store_cpu_state(struct save_area_ext *sa_ext,
 
        if (is_boot_cpu) {
                /* Copy the registers of the boot CPU. */
-               copy_oldmem_page(1, (void *) &sa_ext->sa, sizeof(sa_ext->sa),
-                                SAVE_AREA_BASE - PAGE_SIZE, 0);
+               copy_oldmem_kernel(&sa_ext->sa, (void *) SAVE_AREA_BASE,
+                                  sizeof(sa_ext->sa));
                if (MACHINE_HAS_VX)
                        save_vx_regs_safe(sa_ext->vx_regs);
                return;
index 3ad3d53..4fa4557 100644 (file)
@@ -64,7 +64,7 @@ static struct ipl_parameter_block *ipl_block;
  * @count: Size of buffer, which should be copied
  * @mode:  Either TO_KERNEL or TO_USER
  */
-int memcpy_hsa(void *dest, unsigned long src, size_t count, int mode)
+static int memcpy_hsa(void *dest, unsigned long src, size_t count, int mode)
 {
        int offs, blk_num;
        static char buf[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
@@ -126,12 +126,26 @@ out:
        return 0;
 }
 
-static int memcpy_hsa_user(void __user *dest, unsigned long src, size_t count)
+/*
+ * Copy memory from HSA to user memory (not reentrant):
+ *
+ * @dest:  Kernel or user buffer where memory should be copied to
+ * @src:   Start address within HSA where data should be copied
+ * @count: Size of buffer, which should be copied
+ */
+int memcpy_hsa_user(void __user *dest, unsigned long src, size_t count)
 {
        return memcpy_hsa((void __force *) dest, src, count, TO_USER);
 }
 
-static int memcpy_hsa_kernel(void *dest, unsigned long src, size_t count)
+/*
+ * Copy memory from HSA to kernel memory (not reentrant):
+ *
+ * @dest:  Kernel or user buffer where memory should be copied to
+ * @src:   Start address within HSA where data should be copied
+ * @count: Size of buffer, which should be copied
+ */
+int memcpy_hsa_kernel(void *dest, unsigned long src, size_t count)
 {
        return memcpy_hsa(dest, src, count, TO_KERNEL);
 }