On Sat, May 30, 2020 at 01:41:32PM -0700, Matthew Wilcox wrote:
On Sat, May 30, 2020 at 10:35:47AM -0700, Eric Biggers wrote:
On Sat, May 30, 2020 at 10:18:14AM -0700, Matthew Wilcox wrote:
On Fri, May 29, 2020 at 11:02:16PM -0700, Eric Biggers wrote:
- if (len <= DNAME_INLINE_LEN - 1) {
unsigned int i;
for (i = 0; i < len; i++)
strbuf[i] = READ_ONCE(str[i]);
strbuf[len] = 0;
This READ_ONCE is going to force the compiler to use byte accesses. What's wrong with using a plain memcpy()?
It's undefined behavior when the source can be concurrently modified.
Compilers can assume that it's not, and remove the memcpy() (instead just using the source data directly) if they can prove that the destination array is never modified again before it goes out of scope.
Do you have any suggestions that don't involve undefined behavior?
void *memcpy_unsafe(void *dst, volatile void *src, __kernel_size_t);
It can just call memcpy() of course, but the compiler can't reason about this function because it's not a stdlib function.
The compiler can still reason about it if it's in the same file, if it's an inline function, or if link-time-optimization is enabled. (LTO isn't yet supported by the mainline kernel, but people have been working on it.)
Also, as I mentioned to Al, it's necessary to cast away 'volatile' to call memcpy(). So the 'volatile' serves no purpose.
How about using barrier(), which expands to asm("" : : : "memory") to tell the compiler that memory was clobbered?
if (len <= DNAME_INLINE_LEN - 1) { memcpy(strbuf, str, len); strbuf[len] = 0; /* prevent compiler from optimizing out the temporary buffer */ barrier(); }
I think it's still technically undefined to call memcpy() on concurrently modified memory at all, but I think the above would be okay in practice...
Using 'noinline' could be another option.
- Eric