diff options
Diffstat (limited to 'include/linux/compiler.h')
| -rw-r--r-- | include/linux/compiler.h | 66 | 
1 files changed, 53 insertions, 13 deletions
diff --git a/include/linux/compiler.h b/include/linux/compiler.h index c836eb2dc44d..3d7810341b57 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -198,19 +198,45 @@ 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(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 +/* + * This function is not 'inline' because __no_sanitize_address confilcts + * with inlining. Attempt to inline it may cause a build failure. + * 	https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67368 + * '__maybe_unused' allows us to avoid defined-but-not-used warnings. + */ +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 +void __read_once_size_nocheck(const volatile void *p, void *res, int size) +{ +	__READ_ONCE_SIZE;  } +#endif  static __always_inline void __write_once_size(volatile void *p, void *res, int size)  { @@ -248,8 +274,22 @@ 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;			\ +	if (check)							\ +		__read_once_size(&(x), __u.__c, sizeof(x));		\ +	else								\ +		__read_once_size_nocheck(&(x), __u.__c, sizeof(x));	\ +	__u.__val;							\ +}) +#define READ_ONCE(x) __READ_ONCE(x, 1) + +/* + * Use READ_ONCE_NOCHECK() instead of READ_ONCE() if you need + * to hide memory access from KASAN. + */ +#define READ_ONCE_NOCHECK(x) __READ_ONCE(x, 0)  #define WRITE_ONCE(x, val) \  ({							\  | 
