summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2018-05-03 20:06:21 -0400
committerIngo Molnar <mingo@kernel.org>2018-05-15 02:32:42 -0400
commit60622d68227d6d71fdfba5fb39f7f3d44cdd8815 (patch)
tree345ff9c60d43d8d3720053a25f855289cd9570ff
parentbd131544aa7e318a5735cbcbad46c4a5ee6b9d42 (diff)
x86/asm/memcpy_mcsafe: Return bytes remaining
Machine check safe memory copies are currently deployed in the pmem driver whenever reading from persistent memory media, so that -EIO is returned rather than triggering a kernel panic. While this protects most pmem accesses, it is not complete in the filesystem-dax case. When filesystem-dax is enabled reads may bypass the block layer and the driver via dax_iomap_actor() and its usage of copy_to_iter(). In preparation for creating a copy_to_iter() variant that can handle machine checks, teach memcpy_mcsafe() to return the number of bytes remaining rather than -EFAULT when an exception occurs. Co-developed-by: Tony Luck <tony.luck@intel.com> Signed-off-by: Dan Williams <dan.j.williams@intel.com> Cc: Al Viro <viro@zeniv.linux.org.uk> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Andy Lutomirski <luto@amacapital.net> Cc: Borislav Petkov <bp@alien8.de> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Tony Luck <tony.luck@intel.com> Cc: hch@lst.de Cc: linux-fsdevel@vger.kernel.org Cc: linux-nvdimm@lists.01.org Link: http://lkml.kernel.org/r/152539238119.31796.14318473522414462886.stgit@dwillia2-desk3.amr.corp.intel.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--arch/x86/include/asm/string_64.h8
-rw-r--r--arch/x86/lib/memcpy_64.S20
-rw-r--r--drivers/nvdimm/claim.c3
-rw-r--r--drivers/nvdimm/pmem.c6
-rw-r--r--include/linux/string.h4
5 files changed, 26 insertions, 15 deletions
diff --git a/arch/x86/include/asm/string_64.h b/arch/x86/include/asm/string_64.h
index 4752f8984923..d33f92b9fa22 100644
--- a/arch/x86/include/asm/string_64.h
+++ b/arch/x86/include/asm/string_64.h
@@ -116,7 +116,8 @@ int strcmp(const char *cs, const char *ct);
116#endif 116#endif
117 117
118#define __HAVE_ARCH_MEMCPY_MCSAFE 1 118#define __HAVE_ARCH_MEMCPY_MCSAFE 1
119__must_check int __memcpy_mcsafe(void *dst, const void *src, size_t cnt); 119__must_check unsigned long __memcpy_mcsafe(void *dst, const void *src,
120 size_t cnt);
120DECLARE_STATIC_KEY_FALSE(mcsafe_key); 121DECLARE_STATIC_KEY_FALSE(mcsafe_key);
121 122
122/** 123/**
@@ -131,9 +132,10 @@ DECLARE_STATIC_KEY_FALSE(mcsafe_key);
131 * actually do machine check recovery. Everyone else can just 132 * actually do machine check recovery. Everyone else can just
132 * use memcpy(). 133 * use memcpy().
133 * 134 *
134 * Return 0 for success, -EFAULT for fail 135 * Return 0 for success, or number of bytes not copied if there was an
136 * exception.
135 */ 137 */
136static __always_inline __must_check int 138static __always_inline __must_check unsigned long
137memcpy_mcsafe(void *dst, const void *src, size_t cnt) 139memcpy_mcsafe(void *dst, const void *src, size_t cnt)
138{ 140{
139#ifdef CONFIG_X86_MCE 141#ifdef CONFIG_X86_MCE
diff --git a/arch/x86/lib/memcpy_64.S b/arch/x86/lib/memcpy_64.S
index 5709f3ec22a4..f01a88391c98 100644
--- a/arch/x86/lib/memcpy_64.S
+++ b/arch/x86/lib/memcpy_64.S
@@ -252,14 +252,22 @@ ENDPROC(__memcpy_mcsafe)
252EXPORT_SYMBOL_GPL(__memcpy_mcsafe) 252EXPORT_SYMBOL_GPL(__memcpy_mcsafe)
253 253
254 .section .fixup, "ax" 254 .section .fixup, "ax"
255 /* Return -EFAULT for any failure */ 255 /*
256.L_memcpy_mcsafe_fail: 256 * Return number of bytes not copied for any failure. Note that
257 mov $-EFAULT, %rax 257 * there is no "tail" handling since the source buffer is 8-byte
258 * aligned and poison is cacheline aligned.
259 */
260.E_read_words:
261 shll $3, %ecx
262.E_leading_bytes:
263 addl %edx, %ecx
264.E_trailing_bytes:
265 mov %ecx, %eax
258 ret 266 ret
259 267
260 .previous 268 .previous
261 269
262 _ASM_EXTABLE_FAULT(.L_read_leading_bytes, .L_memcpy_mcsafe_fail) 270 _ASM_EXTABLE_FAULT(.L_read_leading_bytes, .E_leading_bytes)
263 _ASM_EXTABLE_FAULT(.L_read_words, .L_memcpy_mcsafe_fail) 271 _ASM_EXTABLE_FAULT(.L_read_words, .E_read_words)
264 _ASM_EXTABLE_FAULT(.L_read_trailing_bytes, .L_memcpy_mcsafe_fail) 272 _ASM_EXTABLE_FAULT(.L_read_trailing_bytes, .E_trailing_bytes)
265#endif 273#endif
diff --git a/drivers/nvdimm/claim.c b/drivers/nvdimm/claim.c
index 30852270484f..2e96b34bc936 100644
--- a/drivers/nvdimm/claim.c
+++ b/drivers/nvdimm/claim.c
@@ -276,7 +276,8 @@ static int nsio_rw_bytes(struct nd_namespace_common *ndns,
276 if (rw == READ) { 276 if (rw == READ) {
277 if (unlikely(is_bad_pmem(&nsio->bb, sector, sz_align))) 277 if (unlikely(is_bad_pmem(&nsio->bb, sector, sz_align)))
278 return -EIO; 278 return -EIO;
279 return memcpy_mcsafe(buf, nsio->addr + offset, size); 279 if (memcpy_mcsafe(buf, nsio->addr + offset, size) != 0)
280 return -EIO;
280 } 281 }
281 282
282 if (unlikely(is_bad_pmem(&nsio->bb, sector, sz_align))) { 283 if (unlikely(is_bad_pmem(&nsio->bb, sector, sz_align))) {
diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c
index 9d714926ecf5..e023d6aa22b5 100644
--- a/drivers/nvdimm/pmem.c
+++ b/drivers/nvdimm/pmem.c
@@ -101,15 +101,15 @@ static blk_status_t read_pmem(struct page *page, unsigned int off,
101 void *pmem_addr, unsigned int len) 101 void *pmem_addr, unsigned int len)
102{ 102{
103 unsigned int chunk; 103 unsigned int chunk;
104 int rc; 104 unsigned long rem;
105 void *mem; 105 void *mem;
106 106
107 while (len) { 107 while (len) {
108 mem = kmap_atomic(page); 108 mem = kmap_atomic(page);
109 chunk = min_t(unsigned int, len, PAGE_SIZE); 109 chunk = min_t(unsigned int, len, PAGE_SIZE);
110 rc = memcpy_mcsafe(mem + off, pmem_addr, chunk); 110 rem = memcpy_mcsafe(mem + off, pmem_addr, chunk);
111 kunmap_atomic(mem); 111 kunmap_atomic(mem);
112 if (rc) 112 if (rem)
113 return BLK_STS_IOERR; 113 return BLK_STS_IOERR;
114 len -= chunk; 114 len -= chunk;
115 off = 0; 115 off = 0;
diff --git a/include/linux/string.h b/include/linux/string.h
index dd39a690c841..4a5a0eb7df51 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -147,8 +147,8 @@ extern int memcmp(const void *,const void *,__kernel_size_t);
147extern void * memchr(const void *,int,__kernel_size_t); 147extern void * memchr(const void *,int,__kernel_size_t);
148#endif 148#endif
149#ifndef __HAVE_ARCH_MEMCPY_MCSAFE 149#ifndef __HAVE_ARCH_MEMCPY_MCSAFE
150static inline __must_check int memcpy_mcsafe(void *dst, const void *src, 150static inline __must_check unsigned long memcpy_mcsafe(void *dst,
151 size_t cnt) 151 const void *src, size_t cnt)
152{ 152{
153 memcpy(dst, src, cnt); 153 memcpy(dst, src, cnt);
154 return 0; 154 return 0;