x86/dax changes for v4.18
Subsystems (6)
Linus,
Please pull the latest x86-dax-for-linus git tree from:
git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86-dax-for-linus
# HEAD: 8780356ef630aa577fd4daa49e49b79674711fae x86/asm/memcpy_mcsafe: Define copy_to_iter_mcsafe()
This tree contains x86 memcpy_mcsafe() fault handling improvements the nvdimm tree would like to make more use of.
out-of-topic modifications in x86-dax-for-linus:
--------------------------------------------------
drivers/nvdimm/claim.c # 60622d68227d: x86/asm/memcpy_mcsafe: Retur drivers/nvdimm/pmem.c # 60622d68227d: x86/asm/memcpy_mcsafe: Retur include/linux/string.h # 60622d68227d: x86/asm/memcpy_mcsafe: Retur include/linux/uio.h # 8780356ef630: x86/asm/memcpy_mcsafe: Defin lib/iov_iter.c # 8780356ef630: x86/asm/memcpy_mcsafe: Defin
Thanks,
Ingo
------------------>
Dan Williams (5):
x86/asm/memcpy_mcsafe: Remove loop unrolling x86/asm/memcpy_mcsafe: Add labels for __memcpy_mcsafe() write fault handling x86/asm/memcpy_mcsafe: Return bytes remaining x86/asm/memcpy_mcsafe: Add write-protection-fault handling x86/asm/memcpy_mcsafe: Define copy_to_iter_mcsafe()
arch/x86/Kconfig | 1 + arch/x86/include/asm/string_64.h | 10 ++-- arch/x86/include/asm/uaccess_64.h | 14 ++++++ arch/x86/lib/memcpy_64.S | 102 ++++++++++++++++---------------------- arch/x86/lib/usercopy_64.c | 21 ++++++++ drivers/nvdimm/claim.c | 3 +- drivers/nvdimm/pmem.c | 6 +-- include/linux/string.h | 4 +- include/linux/uio.h | 15 ++++++ lib/iov_iter.c | 61 +++++++++++++++++++++++ 10 files changed, 169 insertions(+), 68 deletions(-)
arch/x86/Kconfig +1 -0
@@ -60,6 +60,7 @@ config X86 select ARCH_HAS_PMEM_API if X86_64 select ARCH_HAS_REFCOUNT select ARCH_HAS_UACCESS_FLUSHCACHE if X86_64 + select ARCH_HAS_UACCESS_MCSAFE if X86_64 select ARCH_HAS_SET_MEMORY select ARCH_HAS_SG_CHAIN select ARCH_HAS_STRICT_KERNEL_RWX
arch/x86/include/asm/string_64.h +6 -4
@@ -116,7 +116,8 @@ int strcmp(const char *cs, const char *ct);#endif #define __HAVE_ARCH_MEMCPY_MCSAFE 1 -__must_check int memcpy_mcsafe_unrolled (void *dst,const void *src,size_t cnt); +__must_check unsigned long __memcpy_mcsafe (void *dst,const void *src, +size_t cnt);DECLARE_STATIC_KEY_FALSE (mcsafe_key);/**
@@ -131,14 +132,15 @@ DECLARE_STATIC_KEY_FALSE(mcsafe_key);* actually do machine check recovery. Everyone else can just * use memcpy(). * -* Return 0 for success, -EFAULT for fail +* Return 0 for success, or number of bytes not copied if there was an +* exception. */ -static __always_inline __must_check int +static __always_inline __must_check unsigned long memcpy_mcsafe (void *dst,const void *src,size_t cnt) {#ifdef CONFIG_X86_MCE if (static_branch_unlikely (&mcsafe_key)) -return memcpy_mcsafe_unrolled (dst, src, cnt); +return __memcpy_mcsafe (dst, src, cnt); else#endif memcpy (dst, src, cnt);
arch/x86/include/asm/uaccess_64.h +14 -0
@@ -46,6 +46,17 @@ copy_user_generic(void *to, const void *from, unsigned len)return ret; } +static __always_inline __must_check unsigned long +copy_to_user_mcsafe (void *to,const void *from,unsigned len) +{ +unsigned long ret; + +__uaccess_begin (); + ret =memcpy_mcsafe (to, from, len); +__uaccess_end (); +return ret; +} +static __always_inline __must_check unsigned long raw_copy_from_user (void *dst,const void __user *src,unsigned long size) {
@@ -194,4 +205,7 @@ __copy_from_user_flushcache(void *dst, const void __user *src, unsigned size)unsigned long copy_user_handle_tail (char *to,char *from,unsigned len); +unsigned long +mcsafe_handle_tail (char *to,char *from,unsigned len); +#endif /* _ASM_X86_UACCESS_64_H */
arch/x86/lib/memcpy_64.S +44 -58
151 lines not on this page · raw message
arch/x86/lib/usercopy_64.c +21 -0
@@ -75,6 +75,27 @@ copy_user_handle_tail(char *to, char *from, unsigned len)return len; } +/* +* Similar to copy_user_handle_tail, probe for the write fault point, +* but reuse __memcpy_mcsafe in case a new read error is encountered. +* clac() is handled in _copy_to_iter_mcsafe(). +*/ +__visible unsigned long +mcsafe_handle_tail (char *to,char *from,unsigned len) +{ +for (; len; --len, to++, from++) { +/* +* Call the assembly routine back directly since +* memcpy_mcsafe() may silently fallback to memcpy. +*/ +unsigned long rem =__memcpy_mcsafe (to, from,1 ); + +if (rem) +break ; + } +return len; +} +#ifdef CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE /** * clean_cache_range - write back a cache range with CLWB
drivers/nvdimm/claim.c +2 -1
@@ -276,7 +276,8 @@ static int nsio_rw_bytes(struct nd_namespace_common *ndns,if (rw ==READ ) {if (unlikely (is_bad_pmem (&nsio->bb, sector, sz_align)))return -EIO ; -return memcpy_mcsafe (buf, nsio->addr + offset, size); +if (memcpy_mcsafe (buf, nsio->addr + offset, size) !=0 ) +return -EIO ; }if (unlikely (is_bad_pmem (&nsio->bb, sector, sz_align))) {
drivers/nvdimm/pmem.c +3 -3
@@ -101,15 +101,15 @@ static blk_status_t read_pmem(struct page *page, unsigned int off, void *pmem_addr, unsigned int len) {unsigned int chunk; -int rc; +unsigned long rem;void *mem;while (len) { mem =kmap_atomic (page); chunk = min_t(unsigned int, len, PAGE_SIZE); - rc =memcpy_mcsafe (mem + off, pmem_addr, chunk); + rem =memcpy_mcsafe (mem + off, pmem_addr, chunk);kunmap_atomic (mem); -if (rc) +if (rem)return BLK_STS_IOERR ; len -= chunk; off =0 ;
include/linux/string.h +2 -2
@@ -147,8 +147,8 @@ extern int memcmp(const void *,const void *,__kernel_size_t);extern void *memchr (const void *,int ,__kernel_size_t );#endif #ifndef __HAVE_ARCH_MEMCPY_MCSAFE -static inline __must_check int memcpy_mcsafe (void *dst,const void *src, -size_t cnt) +static inline __must_check unsigned long memcpy_mcsafe (void *dst, +const void *src,size_t cnt) {memcpy (dst, src, cnt);return 0 ;
include/linux/uio.h +15 -0
@@ -154,6 +154,12 @@ size_t _copy_from_iter_flushcache(void *addr, size_t bytes, struct iov_iter *i);#define _copy_from_iter_flushcache _copy_from_iter_nocache#endif +#ifdef CONFIG_ARCH_HAS_UACCESS_MCSAFE +size_t _copy_to_iter_mcsafe (void *addr,size_t bytes,struct iov_iter *i); +#else +#define _copy_to_iter_mcsafe _copy_to_iter +#endif +static __always_inline __must_check size_t copy_from_iter_flushcache(void *addr, size_t bytes, struct iov_iter *i) {
@@ -163,6 +169,15 @@ size_t copy_from_iter_flushcache(void *addr, size_t bytes, struct iov_iter *i)return _copy_from_iter_flushcache (addr, bytes, i); } +static __always_inline __must_check +size_t copy_to_iter_mcsafe(void *addr, size_t bytes, struct iov_iter *i) +{ +if (unlikely (!check_copy_size (addr, bytes, false))) +return 0 ; +else +return _copy_to_iter_mcsafe (addr, bytes, i); +} +size_t iov_iter_zero (size_t bytes,struct iov_iter *);unsigned long iov_iter_alignment (const struct iov_iter *i);unsigned long iov_iter_gap_alignment (const struct iov_iter *i);
lib/iov_iter.c +61 -0
67 lines not on this page · raw message