Skip to content

Commit d1cc3cd

Browse files
djbwgregkh
authored andcommitted
x86, pmem: fix broken __copy_user_nocache cache-bypass assumptions
commit 11e63f6d920d6f2dfd3cd421e939a4aec9a58dcd upstream. Before we rework the "pmem api" to stop abusing __copy_user_nocache() for memcpy_to_pmem() we need to fix cases where we may strand dirty data in the cpu cache. The problem occurs when copy_from_iter_pmem() is used for arbitrary data transfers from userspace. There is no guarantee that these transfers, performed by dax_iomap_actor(), will have aligned destinations or aligned transfer lengths. Backstop the usage __copy_user_nocache() with explicit cache management in these unaligned cases. Yes, copy_from_iter_pmem() is now too big for an inline, but addressing that is saved for a later patch that moves the entirety of the "pmem api" into the pmem driver directly. Fixes: 5de490d ("pmem: add copy_from_iter_pmem() and clear_pmem()") Cc: <x86@kernel.org> Cc: Jan Kara <jack@suse.cz> Cc: Jeff Moyer <jmoyer@redhat.com> Cc: Ingo Molnar <mingo@redhat.com> Cc: Christoph Hellwig <hch@lst.de> Cc: "H. Peter Anvin" <hpa@zytor.com> Cc: Al Viro <viro@zeniv.linux.org.uk> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Matthew Wilcox <mawilcox@microsoft.com> Reviewed-by: Ross Zwisler <ross.zwisler@linux.intel.com> Signed-off-by: Toshi Kani <toshi.kani@hpe.com> Signed-off-by: Dan Williams <dan.j.williams@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 5693f3f commit d1cc3cd

1 file changed

Lines changed: 32 additions & 13 deletions

File tree

arch/x86/include/asm/pmem.h

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,8 @@ static inline void arch_wmb_pmem(void)
7272
* @size: number of bytes to write back
7373
*
7474
* Write back a cache range using the CLWB (cache line write back)
75-
* instruction. This function requires explicit ordering with an
76-
* arch_wmb_pmem() call. This API is internal to the x86 PMEM implementation.
75+
* instruction. Note that @size is internally rounded up to be cache
76+
* line size aligned.
7777
*/
7878
static inline void __arch_wb_cache_pmem(void *vaddr, size_t size)
7979
{
@@ -87,15 +87,6 @@ static inline void __arch_wb_cache_pmem(void *vaddr, size_t size)
8787
clwb(p);
8888
}
8989

90-
/*
91-
* copy_from_iter_nocache() on x86 only uses non-temporal stores for iovec
92-
* iterators, so for other types (bvec & kvec) we must do a cache write-back.
93-
*/
94-
static inline bool __iter_needs_pmem_wb(struct iov_iter *i)
95-
{
96-
return iter_is_iovec(i) == false;
97-
}
98-
9990
/**
10091
* arch_copy_from_iter_pmem - copy data from an iterator to PMEM
10192
* @addr: PMEM destination address
@@ -114,8 +105,36 @@ static inline size_t arch_copy_from_iter_pmem(void __pmem *addr, size_t bytes,
114105
/* TODO: skip the write-back by always using non-temporal stores */
115106
len = copy_from_iter_nocache(vaddr, bytes, i);
116107

117-
if (__iter_needs_pmem_wb(i))
118-
__arch_wb_cache_pmem(vaddr, bytes);
108+
/*
109+
* In the iovec case on x86_64 copy_from_iter_nocache() uses
110+
* non-temporal stores for the bulk of the transfer, but we need
111+
* to manually flush if the transfer is unaligned. A cached
112+
* memory copy is used when destination or size is not naturally
113+
* aligned. That is:
114+
* - Require 8-byte alignment when size is 8 bytes or larger.
115+
* - Require 4-byte alignment when size is 4 bytes.
116+
*
117+
* In the non-iovec case the entire destination needs to be
118+
* flushed.
119+
*/
120+
if (iter_is_iovec(i)) {
121+
unsigned long flushed, dest = (unsigned long) addr;
122+
123+
if (bytes < 8) {
124+
if (!IS_ALIGNED(dest, 4) || (bytes != 4))
125+
__arch_wb_cache_pmem(addr, 1);
126+
} else {
127+
if (!IS_ALIGNED(dest, 8)) {
128+
dest = ALIGN(dest, boot_cpu_data.x86_clflush_size);
129+
__arch_wb_cache_pmem(addr, 1);
130+
}
131+
132+
flushed = dest - (unsigned long) addr;
133+
if (bytes > flushed && !IS_ALIGNED(bytes - flushed, 8))
134+
__arch_wb_cache_pmem(addr + bytes - 1, 1);
135+
}
136+
} else
137+
__arch_wb_cache_pmem(addr, bytes);
119138

120139
return len;
121140
}

0 commit comments

Comments
 (0)