Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+105 -102
+1 -1
arch/s390/include/asm/os_info.h
··· 38 38 39 39 #ifdef CONFIG_CRASH_DUMP 40 40 void *os_info_old_entry(int nr, unsigned long *size); 41 - int copy_from_oldmem(void *dest, void *src, size_t count); 41 + int copy_oldmem_kernel(void *dst, void *src, size_t count); 42 42 #else 43 43 static inline void *os_info_old_entry(int nr, unsigned long *size) 44 44 {
+2 -1
arch/s390/include/asm/sclp.h
··· 77 77 void sclp_get_ipl_info(struct sclp_ipl_info *info); 78 78 int sclp_pci_configure(u32 fid); 79 79 int sclp_pci_deconfigure(u32 fid); 80 - int memcpy_hsa(void *dest, unsigned long src, size_t count, int mode); 80 + int memcpy_hsa_kernel(void *dest, unsigned long src, size_t count); 81 + int memcpy_hsa_user(void __user *dest, unsigned long src, size_t count); 81 82 void sclp_early_detect(void); 82 83 int _sclp_print_early(const char *); 83 84
+79 -92
arch/s390/kernel/crash_dump.c
··· 51 51 } 52 52 53 53 /* 54 - * Copy real to virtual or real memory 54 + * Copy memory of the old, dumped system to a kernel space virtual address 55 55 */ 56 - static int copy_from_realmem(void *dest, void *src, size_t count) 56 + int copy_oldmem_kernel(void *dst, void *src, size_t count) 57 57 { 58 - unsigned long size; 58 + unsigned long from, len; 59 + void *ra; 60 + int rc; 59 61 60 - if (!count) 61 - return 0; 62 - if (!is_vmalloc_or_module_addr(dest)) 63 - return memcpy_real(dest, src, count); 64 - do { 65 - size = min(count, PAGE_SIZE - (__pa(dest) & ~PAGE_MASK)); 66 - if (memcpy_real(load_real_addr(dest), src, size)) 67 - return -EFAULT; 68 - count -= size; 69 - dest += size; 70 - src += size; 71 - } while (count); 62 + while (count) { 63 + from = __pa(src); 64 + if (!OLDMEM_BASE && from < sclp.hsa_size) { 65 + /* Copy from zfcpdump HSA area */ 66 + len = min(count, sclp.hsa_size - from); 67 + rc = memcpy_hsa_kernel(dst, from, len); 68 + if (rc) 69 + return rc; 70 + } else { 71 + /* Check for swapped kdump oldmem areas */ 72 + if (OLDMEM_BASE && from - OLDMEM_BASE < OLDMEM_SIZE) { 73 + from -= OLDMEM_BASE; 74 + len = min(count, OLDMEM_SIZE - from); 75 + } else if (OLDMEM_BASE && from < OLDMEM_SIZE) { 76 + len = min(count, OLDMEM_SIZE - from); 77 + from += OLDMEM_BASE; 78 + } else { 79 + len = count; 80 + } 81 + if (is_vmalloc_or_module_addr(dst)) { 82 + ra = load_real_addr(dst); 83 + len = min(PAGE_SIZE - offset_in_page(ra), len); 84 + } else { 85 + ra = dst; 86 + } 87 + if (memcpy_real(ra, (void *) from, len)) 88 + return -EFAULT; 89 + } 90 + dst += len; 91 + src += len; 92 + count -= len; 93 + } 72 94 return 0; 73 95 } 74 96 75 97 /* 76 - * Copy one page from zfcpdump "oldmem" 77 - * 78 - * For pages below HSA size memory from the HSA is copied. Otherwise 79 - * real memory copy is used. 98 + * Copy memory of the old, dumped system to a user space virtual address 80 99 */ 81 - static ssize_t copy_oldmem_page_zfcpdump(char *buf, size_t csize, 82 - unsigned long src, int userbuf) 100 + int copy_oldmem_user(void __user *dst, void *src, size_t count) 83 101 { 102 + unsigned long from, len; 84 103 int rc; 85 104 86 - if (src < sclp.hsa_size) { 87 - rc = memcpy_hsa(buf, src, csize, userbuf); 88 - } else { 89 - if (userbuf) 90 - rc = copy_to_user_real((void __force __user *) buf, 91 - (void *) src, csize); 92 - else 93 - rc = memcpy_real(buf, (void *) src, csize); 105 + while (count) { 106 + from = __pa(src); 107 + if (!OLDMEM_BASE && from < sclp.hsa_size) { 108 + /* Copy from zfcpdump HSA area */ 109 + len = min(count, sclp.hsa_size - from); 110 + rc = memcpy_hsa_user(dst, from, len); 111 + if (rc) 112 + return rc; 113 + } else { 114 + /* Check for swapped kdump oldmem areas */ 115 + if (OLDMEM_BASE && from - OLDMEM_BASE < OLDMEM_SIZE) { 116 + from -= OLDMEM_BASE; 117 + len = min(count, OLDMEM_SIZE - from); 118 + } else if (OLDMEM_BASE && from < OLDMEM_SIZE) { 119 + len = min(count, OLDMEM_SIZE - from); 120 + from += OLDMEM_BASE; 121 + } else { 122 + len = count; 123 + } 124 + rc = copy_to_user_real(dst, (void *) from, count); 125 + if (rc) 126 + return rc; 127 + } 128 + dst += len; 129 + src += len; 130 + count -= len; 94 131 } 95 - return rc ? rc : csize; 96 - } 97 - 98 - /* 99 - * Copy one page from kdump "oldmem" 100 - * 101 - * For the kdump reserved memory this functions performs a swap operation: 102 - * - [OLDMEM_BASE - OLDMEM_BASE + OLDMEM_SIZE] is mapped to [0 - OLDMEM_SIZE]. 103 - * - [0 - OLDMEM_SIZE] is mapped to [OLDMEM_BASE - OLDMEM_BASE + OLDMEM_SIZE] 104 - */ 105 - static ssize_t copy_oldmem_page_kdump(char *buf, size_t csize, 106 - unsigned long src, int userbuf) 107 - 108 - { 109 - int rc; 110 - 111 - if (src < OLDMEM_SIZE) 112 - src += OLDMEM_BASE; 113 - else if (src > OLDMEM_BASE && 114 - src < OLDMEM_BASE + OLDMEM_SIZE) 115 - src -= OLDMEM_BASE; 116 - if (userbuf) 117 - rc = copy_to_user_real((void __force __user *) buf, 118 - (void *) src, csize); 119 - else 120 - rc = copy_from_realmem(buf, (void *) src, csize); 121 - return (rc == 0) ? rc : csize; 132 + return 0; 122 133 } 123 134 124 135 /* ··· 138 127 ssize_t copy_oldmem_page(unsigned long pfn, char *buf, size_t csize, 139 128 unsigned long offset, int userbuf) 140 129 { 141 - unsigned long src; 130 + void *src; 131 + int rc; 142 132 143 133 if (!csize) 144 134 return 0; 145 - src = (pfn << PAGE_SHIFT) + offset; 146 - if (OLDMEM_BASE) 147 - return copy_oldmem_page_kdump(buf, csize, src, userbuf); 135 + src = (void *) (pfn << PAGE_SHIFT) + offset; 136 + if (userbuf) 137 + rc = copy_oldmem_user((void __force __user *) buf, src, csize); 148 138 else 149 - return copy_oldmem_page_zfcpdump(buf, csize, src, userbuf); 139 + rc = copy_oldmem_kernel((void *) buf, src, csize); 140 + return rc; 150 141 } 151 142 152 143 /* ··· 214 201 else 215 202 return remap_oldmem_pfn_range_zfcpdump(vma, from, pfn, size, 216 203 prot); 217 - } 218 - 219 - /* 220 - * Copy memory from old kernel 221 - */ 222 - int copy_from_oldmem(void *dest, void *src, size_t count) 223 - { 224 - unsigned long copied = 0; 225 - int rc; 226 - 227 - if (OLDMEM_BASE) { 228 - if ((unsigned long) src < OLDMEM_SIZE) { 229 - copied = min(count, OLDMEM_SIZE - (unsigned long) src); 230 - rc = copy_from_realmem(dest, src + OLDMEM_BASE, copied); 231 - if (rc) 232 - return rc; 233 - } 234 - } else { 235 - unsigned long hsa_end = sclp.hsa_size; 236 - if ((unsigned long) src < hsa_end) { 237 - copied = min(count, hsa_end - (unsigned long) src); 238 - rc = memcpy_hsa(dest, (unsigned long) src, copied, 0); 239 - if (rc) 240 - return rc; 241 - } 242 - } 243 - return copy_from_realmem(dest + copied, src + copied, count - copied); 244 204 } 245 205 246 206 /* ··· 411 425 Elf64_Nhdr note; 412 426 void *addr; 413 427 414 - if (copy_from_oldmem(&addr, &S390_lowcore.vmcore_info, sizeof(addr))) 428 + if (copy_oldmem_kernel(&addr, &S390_lowcore.vmcore_info, sizeof(addr))) 415 429 return NULL; 416 430 memset(nt_name, 0, sizeof(nt_name)); 417 - if (copy_from_oldmem(&note, addr, sizeof(note))) 431 + if (copy_oldmem_kernel(&note, addr, sizeof(note))) 418 432 return NULL; 419 - if (copy_from_oldmem(nt_name, addr + sizeof(note), sizeof(nt_name) - 1)) 433 + if (copy_oldmem_kernel(nt_name, addr + sizeof(note), 434 + sizeof(nt_name) - 1)) 420 435 return NULL; 421 436 if (strcmp(nt_name, "VMCOREINFO") != 0) 422 437 return NULL; 423 438 vmcoreinfo = kzalloc_panic(note.n_descsz); 424 - if (copy_from_oldmem(vmcoreinfo, addr + 24, note.n_descsz)) 439 + if (copy_oldmem_kernel(vmcoreinfo, addr + 24, note.n_descsz)) 425 440 return NULL; 426 441 *size = note.n_descsz; 427 442 return vmcoreinfo;
+4 -3
arch/s390/kernel/os_info.c
··· 89 89 goto fail; 90 90 } 91 91 buf_align = PTR_ALIGN(buf, align); 92 - if (copy_from_oldmem(buf_align, (void *) addr, size)) { 92 + if (copy_oldmem_kernel(buf_align, (void *) addr, size)) { 93 93 msg = "copy failed"; 94 94 goto fail_free; 95 95 } ··· 122 122 return; 123 123 if (!OLDMEM_BASE) 124 124 goto fail; 125 - if (copy_from_oldmem(&addr, &S390_lowcore.os_info, sizeof(addr))) 125 + if (copy_oldmem_kernel(&addr, &S390_lowcore.os_info, sizeof(addr))) 126 126 goto fail; 127 127 if (addr == 0 || addr % PAGE_SIZE) 128 128 goto fail; 129 129 os_info_old = kzalloc(sizeof(*os_info_old), GFP_KERNEL); 130 130 if (!os_info_old) 131 131 goto fail; 132 - if (copy_from_oldmem(os_info_old, (void *) addr, sizeof(*os_info_old))) 132 + if (copy_oldmem_kernel(os_info_old, (void *) addr, 133 + sizeof(*os_info_old))) 133 134 goto fail_free; 134 135 if (os_info_old->magic != OS_INFO_MAGIC) 135 136 goto fail_free;
+2 -2
arch/s390/kernel/smp.c
··· 546 546 547 547 if (is_boot_cpu) { 548 548 /* Copy the registers of the boot CPU. */ 549 - copy_oldmem_page(1, (void *) &sa_ext->sa, sizeof(sa_ext->sa), 550 - SAVE_AREA_BASE - PAGE_SIZE, 0); 549 + copy_oldmem_kernel(&sa_ext->sa, (void *) SAVE_AREA_BASE, 550 + sizeof(sa_ext->sa)); 551 551 if (MACHINE_HAS_VX) 552 552 save_vx_regs_safe(sa_ext->vx_regs); 553 553 return;
+17 -3
drivers/s390/char/zcore.c
··· 64 64 * @count: Size of buffer, which should be copied 65 65 * @mode: Either TO_KERNEL or TO_USER 66 66 */ 67 - int memcpy_hsa(void *dest, unsigned long src, size_t count, int mode) 67 + static int memcpy_hsa(void *dest, unsigned long src, size_t count, int mode) 68 68 { 69 69 int offs, blk_num; 70 70 static char buf[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); ··· 126 126 return 0; 127 127 } 128 128 129 - static int memcpy_hsa_user(void __user *dest, unsigned long src, size_t count) 129 + /* 130 + * Copy memory from HSA to user memory (not reentrant): 131 + * 132 + * @dest: Kernel or user buffer where memory should be copied to 133 + * @src: Start address within HSA where data should be copied 134 + * @count: Size of buffer, which should be copied 135 + */ 136 + int memcpy_hsa_user(void __user *dest, unsigned long src, size_t count) 130 137 { 131 138 return memcpy_hsa((void __force *) dest, src, count, TO_USER); 132 139 } 133 140 134 - static int memcpy_hsa_kernel(void *dest, unsigned long src, size_t count) 141 + /* 142 + * Copy memory from HSA to kernel memory (not reentrant): 143 + * 144 + * @dest: Kernel or user buffer where memory should be copied to 145 + * @src: Start address within HSA where data should be copied 146 + * @count: Size of buffer, which should be copied 147 + */ 148 + int memcpy_hsa_kernel(void *dest, unsigned long src, size_t count) 135 149 { 136 150 return memcpy_hsa(dest, src, count, TO_KERNEL); 137 151 }