Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1245674 > unrolled thread

[PATCH v2 1/2] Provide READ_ONCE_NOCHECK()

Started byAndrey Ryabinin <aryabinin@virtuozzo.com>
First post2015-10-13 14:40 +0200
Last post2015-10-13 16:20 +0200
Articles 2 — 2 participants

Back to article view | Back to linux.kernel

This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by below is the oldest one visible, not the original post.


Contents

  [PATCH v2 1/2] Provide READ_ONCE_NOCHECK() Andrey Ryabinin <aryabinin@virtuozzo.com> - 2015-10-13 14:40 +0200
    Re: [PATCH v2 1/2] Provide READ_ONCE_NOCHECK() Ingo Molnar <mingo@kernel.org> - 2015-10-13 16:20 +0200

#1245674 — [PATCH v2 1/2] Provide READ_ONCE_NOCHECK()

FromAndrey Ryabinin <aryabinin@virtuozzo.com>
Date2015-10-13 14:40 +0200
Subject[PATCH v2 1/2] Provide READ_ONCE_NOCHECK()
Message-ID<qj722-6Fq-23@gated-at.bofh.it>
Some code may perform racy by design memory reads. This could be harmless,
yet such code may produce KASAN warnings.

To hide such accesses from KASAN this patch introduces READ_ONCE_NOCHECK()
macro. KASAN will not check the memory accessed by READ_ONCE_NOCHECK().

This patch creates __read_once_size_nocheck() a clone of
__read_once_size_check() (renamed __read_once_size()).
The only difference between them is 'no_sanitized_address' attribute
appended to '*_nocheck' function. This attribute tells compiler to not
instrumentation of memory accesses should not be applied to that function.
We declare it as static '__maybe_unsed' because GCC is not capable to
inline such function: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67368

With KASAN=n READ_ONCE_NOCHECK() is just a clone of READ_ONCE().

Signed-off-by: Andrey Ryabinin <aryabinin@virtuozzo.com>
---
 include/linux/compiler-gcc.h | 13 ++++++++++++
 include/linux/compiler.h     | 49 ++++++++++++++++++++++++++++++++------------
 2 files changed, 49 insertions(+), 13 deletions(-)

diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h
index dfaa7b3..7ab09de 100644
--- a/include/linux/compiler-gcc.h
+++ b/include/linux/compiler-gcc.h
@@ -237,12 +237,25 @@
 #define KASAN_ABI_VERSION 3
 #endif
 
+#if GCC_VERSION >= 40902
+/*
+ * Tell the compiler that address safety instrumentation (e.g. KASAN)
+ * should not be applied to that function.
+ * Confilcts with inlining: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67368
+ */
+#define __no_sanitize_address __attribute__((no_sanitize_address))
+#endif
+
 #endif	/* gcc version >= 40000 specific checks */
 
 #if !defined(__noclone)
 #define __noclone	/* not needed */
 #endif
 
+#if !defined(__no_sanitize_address)
+#define __no_sanitize_address
+#endif
+
 /*
  * A trick to suppress uninitialized variable warning without generating any
  * code
diff --git a/include/linux/compiler.h b/include/linux/compiler.h
index c836eb2..2153fd8 100644
--- a/include/linux/compiler.h
+++ b/include/linux/compiler.h
@@ -198,20 +198,37 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect);
 
 #include <uapi/linux/types.h>
 
-static __always_inline void __read_once_size(const volatile void *p, void *res, int size)
+#define __READ_ONCE_SIZE						\
+({									\
+	switch (size) {							\
+	case 1: *(__u8 *)res = *(volatile __u8 *)p; break;		\
+	case 2: *(__u16 *)res = *(volatile __u16 *)p; break;		\
+	case 4: *(__u32 *)res = *(volatile __u32 *)p; break;		\
+	case 8: *(__u64 *)res = *(volatile __u64 *)p; break;		\
+	default:							\
+		barrier();						\
+		__builtin_memcpy((void *)res, (const void *)p, size);	\
+		barrier();						\
+	}								\
+})
+
+static __always_inline
+void __read_once_size_check(const volatile void *p, void *res, int size)
 {
-	switch (size) {
-	case 1: *(__u8 *)res = *(volatile __u8 *)p; break;
-	case 2: *(__u16 *)res = *(volatile __u16 *)p; break;
-	case 4: *(__u32 *)res = *(volatile __u32 *)p; break;
-	case 8: *(__u64 *)res = *(volatile __u64 *)p; break;
-	default:
-		barrier();
-		__builtin_memcpy((void *)res, (const void *)p, size);
-		barrier();
-	}
+	__READ_ONCE_SIZE;
 }
 
+#ifdef CONFIG_KASAN
+static __no_sanitize_address __maybe_unused
+void __read_once_size_nocheck(const volatile void *p, void *res, int size)
+{
+	__READ_ONCE_SIZE;
+}
+#else
+static __always_inline __alias(__read_once_size_check)
+void __read_once_size_nocheck(const volatile void *p, void *res, int size);
+#endif
+
 static __always_inline void __write_once_size(volatile void *p, void *res, int size)
 {
 	switch (size) {
@@ -248,8 +265,14 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s
  * required ordering.
  */
 
-#define READ_ONCE(x) \
-	({ union { typeof(x) __val; char __c[1]; } __u; __read_once_size(&(x), __u.__c, sizeof(x)); __u.__val; })
+#define __READ_ONCE(x, check)					\
+({								\
+	union { typeof(x) __val; char __c[1]; } __u;		\
+	__read_once_size##check(&(x), __u.__c, sizeof(x));	\
+	__u.__val;						\
+})
+#define READ_ONCE(x) __READ_ONCE(x, _check)
+#define READ_ONCE_NOCHECK(x) __READ_ONCE(x, _nocheck)
 
 #define WRITE_ONCE(x, val) \
 ({							\
-- 
2.4.9

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [next] | [standalone]


#1245770

FromIngo Molnar <mingo@kernel.org>
Date2015-10-13 16:20 +0200
Message-ID<qj8AO-zI-21@gated-at.bofh.it>
In reply to#1245674
* Andrey Ryabinin <aryabinin@virtuozzo.com> wrote:

> +#define __READ_ONCE_SIZE						\
> +({									\
> +	switch (size) {							\
> +	case 1: *(__u8 *)res = *(volatile __u8 *)p; break;		\
> +	case 2: *(__u16 *)res = *(volatile __u16 *)p; break;		\
> +	case 4: *(__u32 *)res = *(volatile __u32 *)p; break;		\
> +	case 8: *(__u64 *)res = *(volatile __u64 *)p; break;		\
> +	default:							\
> +		barrier();						\
> +		__builtin_memcpy((void *)res, (const void *)p, size);	\
> +		barrier();						\
> +	}								\
> +})
> +
> +static __always_inline
> +void __read_once_size_check(const volatile void *p, void *res, int size)
>  {
> +	__READ_ONCE_SIZE;
>  }

> +#ifdef CONFIG_KASAN
> +static __no_sanitize_address __maybe_unused
> +void __read_once_size_nocheck(const volatile void *p, void *res, int size)
> +{
> +	__READ_ONCE_SIZE;
> +}
> +#else
> +static __always_inline __alias(__read_once_size_check)
> +void __read_once_size_nocheck(const volatile void *p, void *res, int size);
> +#endif

> +#define __READ_ONCE(x, check)				\
> +({								\
> +	union { typeof(x) __val; char __c[1]; } __u;		\
> +	__read_once_size##check(&(x), __u.__c, sizeof(x));	\
> +	__u.__val;						\
> +})
> +#define READ_ONCE(x) __READ_ONCE(x, _check)
> +#define READ_ONCE_NOCHECK(x) __READ_ONCE(x, _nocheck)

So all this code is quite convoluted, and as the changelog explains it's done to 
work around a GCC inlining + no-kasan bug.

But please explain this in the code as well, in a comment, so future generations 
are not kept wondering why these relatively simple wrappers are coded in such an 
ugly and roundabout fashion.

Thanks,

	Ingo
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web