Commit 2f089a38 authored by Alexander Gordeev's avatar Alexander Gordeev

Merge branch 'vmcore-iov_iter' into features

Pull changes that finalize switching of copy_oldmem_page() callback
to iov_iter interface. These changes were pulled in work.iov_iter of
git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs.gitSigned-off-by: default avatarAlexander Gordeev <agordeev@linux.ibm.com>
parents 9aa938dd ebbc9570
...@@ -42,18 +42,4 @@ typedef struct { ...@@ -42,18 +42,4 @@ typedef struct {
.context.pgtable_list = LIST_HEAD_INIT(name.context.pgtable_list), \ .context.pgtable_list = LIST_HEAD_INIT(name.context.pgtable_list), \
.context.gmap_list = LIST_HEAD_INIT(name.context.gmap_list), .context.gmap_list = LIST_HEAD_INIT(name.context.gmap_list),
static inline int tprot(unsigned long addr)
{
int rc = -EFAULT;
asm volatile(
" tprot 0(%1),0\n"
"0: ipm %0\n"
" srl %0,28\n"
"1:\n"
EX_TABLE(0b,1b)
: "+d" (rc) : "a" (addr) : "cc");
return rc;
}
#endif #endif
...@@ -8,6 +8,8 @@ ...@@ -8,6 +8,8 @@
#ifndef _ASM_S390_OS_INFO_H #ifndef _ASM_S390_OS_INFO_H
#define _ASM_S390_OS_INFO_H #define _ASM_S390_OS_INFO_H
#include <linux/uio.h>
#define OS_INFO_VERSION_MAJOR 1 #define OS_INFO_VERSION_MAJOR 1
#define OS_INFO_VERSION_MINOR 1 #define OS_INFO_VERSION_MINOR 1
#define OS_INFO_MAGIC 0x4f53494e464f535aULL /* OSINFOSZ */ #define OS_INFO_MAGIC 0x4f53494e464f535aULL /* OSINFOSZ */
...@@ -39,7 +41,20 @@ u32 os_info_csum(struct os_info *os_info); ...@@ -39,7 +41,20 @@ u32 os_info_csum(struct os_info *os_info);
#ifdef CONFIG_CRASH_DUMP #ifdef CONFIG_CRASH_DUMP
void *os_info_old_entry(int nr, unsigned long *size); void *os_info_old_entry(int nr, unsigned long *size);
int copy_oldmem_kernel(void *dst, unsigned long src, size_t count); size_t copy_oldmem_iter(struct iov_iter *iter, unsigned long src, size_t count);
static inline int copy_oldmem_kernel(void *dst, unsigned long src, size_t count)
{
struct iov_iter iter;
struct kvec kvec;
kvec.iov_base = dst;
kvec.iov_len = count;
iov_iter_kvec(&iter, WRITE, &kvec, 1, count);
if (copy_oldmem_iter(&iter, src, count) < count)
return -EFAULT;
return 0;
}
#else #else
static inline void *os_info_old_entry(int nr, unsigned long *size) static inline void *os_info_old_entry(int nr, unsigned long *size)
{ {
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#define EXT_SCCB_READ_CPU (3 * PAGE_SIZE) #define EXT_SCCB_READ_CPU (3 * PAGE_SIZE)
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
#include <linux/uio.h>
#include <asm/chpid.h> #include <asm/chpid.h>
#include <asm/cpu.h> #include <asm/cpu.h>
...@@ -142,8 +143,7 @@ int sclp_pci_deconfigure(u32 fid); ...@@ -142,8 +143,7 @@ int sclp_pci_deconfigure(u32 fid);
int sclp_ap_configure(u32 apid); int sclp_ap_configure(u32 apid);
int sclp_ap_deconfigure(u32 apid); int sclp_ap_deconfigure(u32 apid);
int sclp_pci_report(struct zpci_report_error_header *report, u32 fh, u32 fid); int sclp_pci_report(struct zpci_report_error_header *report, u32 fh, u32 fid);
int memcpy_hsa_kernel(void *dest, unsigned long src, size_t count); size_t memcpy_hsa_iter(struct iov_iter *iter, unsigned long src, size_t count);
int memcpy_hsa_user(void __user *dest, unsigned long src, size_t count);
void sclp_ocf_cpc_name_copy(char *dst); void sclp_ocf_cpc_name_copy(char *dst);
static inline int sclp_get_core_info(struct sclp_core_info *info, int early) static inline int sclp_get_core_info(struct sclp_core_info *info, int early)
......
...@@ -285,7 +285,6 @@ static inline unsigned long __must_check clear_user(void __user *to, unsigned lo ...@@ -285,7 +285,6 @@ static inline unsigned long __must_check clear_user(void __user *to, unsigned lo
return __clear_user(to, n); return __clear_user(to, n);
} }
int copy_to_user_real(void __user *dest, unsigned long src, unsigned long count);
void *s390_kernel_write(void *dst, const void *src, size_t size); void *s390_kernel_write(void *dst, const void *src, size_t size);
int __noreturn __put_kernel_bad(void); int __noreturn __put_kernel_bad(void);
......
...@@ -53,6 +53,8 @@ struct save_area { ...@@ -53,6 +53,8 @@ struct save_area {
}; };
static LIST_HEAD(dump_save_areas); static LIST_HEAD(dump_save_areas);
static DEFINE_MUTEX(memcpy_real_mutex);
static char memcpy_real_buf[PAGE_SIZE];
/* /*
* Allocate a save area * Allocate a save area
...@@ -63,7 +65,7 @@ struct save_area * __init save_area_alloc(bool is_boot_cpu) ...@@ -63,7 +65,7 @@ struct save_area * __init save_area_alloc(bool is_boot_cpu)
sa = memblock_alloc(sizeof(*sa), 8); sa = memblock_alloc(sizeof(*sa), 8);
if (!sa) if (!sa)
panic("Failed to allocate save area\n"); return NULL;
if (is_boot_cpu) if (is_boot_cpu)
list_add(&sa->list, &dump_save_areas); list_add(&sa->list, &dump_save_areas);
...@@ -114,80 +116,35 @@ void __init save_area_add_vxrs(struct save_area *sa, __vector128 *vxrs) ...@@ -114,80 +116,35 @@ void __init save_area_add_vxrs(struct save_area *sa, __vector128 *vxrs)
memcpy(sa->vxrs_high, vxrs + 16, 16 * sizeof(__vector128)); memcpy(sa->vxrs_high, vxrs + 16, 16 * sizeof(__vector128));
} }
/* static size_t copy_to_iter_real(struct iov_iter *iter, unsigned long src, size_t count)
* 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 memory of the old, dumped system to a kernel space virtual address
*/
int copy_oldmem_kernel(void *dst, unsigned long src, size_t count)
{ {
unsigned long len; size_t len, copied, res = 0;
void *ra;
int rc;
mutex_lock(&memcpy_real_mutex);
while (count) { while (count) {
if (!oldmem_data.start && src < sclp.hsa_size) { len = min(PAGE_SIZE, count);
/* Copy from zfcp/nvme dump HSA area */ if (memcpy_real(memcpy_real_buf, src, len))
len = min(count, sclp.hsa_size - src); break;
rc = memcpy_hsa_kernel(dst, src, len); copied = copy_to_iter(memcpy_real_buf, len, iter);
if (rc) count -= copied;
return rc; src += copied;
} else { res += copied;
/* Check for swapped kdump oldmem areas */ if (copied < len)
if (oldmem_data.start && src - oldmem_data.start < oldmem_data.size) { break;
src -= oldmem_data.start;
len = min(count, oldmem_data.size - src);
} else if (oldmem_data.start && src < oldmem_data.size) {
len = min(count, oldmem_data.size - src);
src += oldmem_data.start;
} 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, src, len))
return -EFAULT;
}
dst += len;
src += len;
count -= len;
} }
return 0; mutex_unlock(&memcpy_real_mutex);
return res;
} }
/* size_t copy_oldmem_iter(struct iov_iter *iter, unsigned long src, size_t count)
* Copy memory of the old, dumped system to a user space virtual address
*/
static int copy_oldmem_user(void __user *dst, unsigned long src, size_t count)
{ {
unsigned long len; size_t len, copied, res = 0;
int rc;
while (count) { while (count) {
if (!oldmem_data.start && src < sclp.hsa_size) { if (!oldmem_data.start && src < sclp.hsa_size) {
/* Copy from zfcp/nvme dump HSA area */ /* Copy from zfcp/nvme dump HSA area */
len = min(count, sclp.hsa_size - src); len = min(count, sclp.hsa_size - src);
rc = memcpy_hsa_user(dst, src, len); copied = memcpy_hsa_iter(iter, src, len);
if (rc)
return rc;
} else { } else {
/* Check for swapped kdump oldmem areas */ /* Check for swapped kdump oldmem areas */
if (oldmem_data.start && src - oldmem_data.start < oldmem_data.size) { if (oldmem_data.start && src - oldmem_data.start < oldmem_data.size) {
...@@ -199,15 +156,15 @@ static int copy_oldmem_user(void __user *dst, unsigned long src, size_t count) ...@@ -199,15 +156,15 @@ static int copy_oldmem_user(void __user *dst, unsigned long src, size_t count)
} else { } else {
len = count; len = count;
} }
rc = copy_to_user_real(dst, src, count); copied = copy_to_iter_real(iter, src, len);
if (rc)
return rc;
} }
dst += len; count -= copied;
src += len; src += copied;
count -= len; res += copied;
if (copied < len)
break;
} }
return 0; return res;
} }
/* /*
...@@ -217,18 +174,9 @@ ssize_t copy_oldmem_page(struct iov_iter *iter, unsigned long pfn, size_t csize, ...@@ -217,18 +174,9 @@ ssize_t copy_oldmem_page(struct iov_iter *iter, unsigned long pfn, size_t csize,
unsigned long offset) unsigned long offset)
{ {
unsigned long src; unsigned long src;
int rc;
if (!csize)
return 0;
src = pfn_to_phys(pfn) + offset; src = pfn_to_phys(pfn) + offset;
return copy_oldmem_iter(iter, src, csize);
/* XXX: pass the iov_iter down to a common function */
if (iter_is_iovec(iter))
rc = copy_oldmem_user(iter->iov->iov_base, src, csize);
else
rc = copy_oldmem_kernel(iter->kvec->iov_base, src, csize);
return rc;
} }
/* /*
......
...@@ -171,32 +171,6 @@ void memcpy_absolute(void *dest, void *src, size_t count) ...@@ -171,32 +171,6 @@ void memcpy_absolute(void *dest, void *src, size_t count)
arch_local_irq_restore(flags); arch_local_irq_restore(flags);
} }
/*
* Copy memory from kernel (real) to user (virtual)
*/
int copy_to_user_real(void __user *dest, unsigned long src, unsigned long count)
{
int offs = 0, size, rc;
char *buf;
buf = (char *) __get_free_page(GFP_KERNEL);
if (!buf)
return -ENOMEM;
rc = -EFAULT;
while (offs < count) {
size = min(PAGE_SIZE, count - offs);
if (memcpy_real(buf, src + offs, size))
goto out;
if (copy_to_user(dest + offs, buf, size))
goto out;
offs += size;
}
rc = 0;
out:
free_page((unsigned long) buf);
return rc;
}
/* /*
* Check if physical address is within prefix or zero page * Check if physical address is within prefix or zero page
*/ */
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/panic_notifier.h> #include <linux/panic_notifier.h>
#include <linux/reboot.h> #include <linux/reboot.h>
#include <linux/uio.h>
#include <asm/asm-offsets.h> #include <asm/asm-offsets.h>
#include <asm/ipl.h> #include <asm/ipl.h>
...@@ -50,36 +51,41 @@ static struct dentry *zcore_reipl_file; ...@@ -50,36 +51,41 @@ static struct dentry *zcore_reipl_file;
static struct dentry *zcore_hsa_file; static struct dentry *zcore_hsa_file;
static struct ipl_parameter_block *zcore_ipl_block; static struct ipl_parameter_block *zcore_ipl_block;
static DEFINE_MUTEX(hsa_buf_mutex);
static char hsa_buf[PAGE_SIZE] __aligned(PAGE_SIZE); static char hsa_buf[PAGE_SIZE] __aligned(PAGE_SIZE);
/* /*
* Copy memory from HSA to user memory (not reentrant): * Copy memory from HSA to iterator (not reentrant):
* *
* @dest: User buffer where memory should be copied to * @iter: Iterator where memory should be copied to
* @src: Start address within HSA where data should be copied * @src: Start address within HSA where data should be copied
* @count: Size of buffer, which should be copied * @count: Size of buffer, which should be copied
*/ */
int memcpy_hsa_user(void __user *dest, unsigned long src, size_t count) size_t memcpy_hsa_iter(struct iov_iter *iter, unsigned long src, size_t count)
{ {
unsigned long offset, bytes; size_t bytes, copied, res = 0;
unsigned long offset;
if (!hsa_available) if (!hsa_available)
return -ENODATA; return 0;
mutex_lock(&hsa_buf_mutex);
while (count) { while (count) {
if (sclp_sdias_copy(hsa_buf, src / PAGE_SIZE + 2, 1)) { if (sclp_sdias_copy(hsa_buf, src / PAGE_SIZE + 2, 1)) {
TRACE("sclp_sdias_copy() failed\n"); TRACE("sclp_sdias_copy() failed\n");
return -EIO; break;
} }
offset = src % PAGE_SIZE; offset = src % PAGE_SIZE;
bytes = min(PAGE_SIZE - offset, count); bytes = min(PAGE_SIZE - offset, count);
if (copy_to_user(dest, hsa_buf + offset, bytes)) copied = copy_to_iter(hsa_buf + offset, bytes, iter);
return -EFAULT; count -= copied;
src += bytes; src += copied;
dest += bytes; res += copied;
count -= bytes; if (copied < bytes)
break;
} }
return 0; mutex_unlock(&hsa_buf_mutex);
return res;
} }
/* /*
...@@ -89,25 +95,16 @@ int memcpy_hsa_user(void __user *dest, unsigned long src, size_t count) ...@@ -89,25 +95,16 @@ int memcpy_hsa_user(void __user *dest, unsigned long src, size_t count)
* @src: Start address within HSA where data should be copied * @src: Start address within HSA where data should be copied
* @count: Size of buffer, which should be copied * @count: Size of buffer, which should be copied
*/ */
int memcpy_hsa_kernel(void *dest, unsigned long src, size_t count) static inline int memcpy_hsa_kernel(void *dst, unsigned long src, size_t count)
{ {
unsigned long offset, bytes; struct iov_iter iter;
struct kvec kvec;
if (!hsa_available) kvec.iov_base = dst;
return -ENODATA; kvec.iov_len = count;
iov_iter_kvec(&iter, WRITE, &kvec, 1, count);
while (count) { if (memcpy_hsa_iter(&iter, src, count) < count)
if (sclp_sdias_copy(hsa_buf, src / PAGE_SIZE + 2, 1)) { return -EIO;
TRACE("sclp_sdias_copy() failed\n");
return -EIO;
}
offset = src % PAGE_SIZE;
bytes = min(PAGE_SIZE - offset, count);
memcpy(dest, hsa_buf + offset, bytes);
src += bytes;
dest += bytes;
count -= bytes;
}
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment