Merge branch 'rwonce/rework' of git://git.kernel.org/pub/scm/linux/kernel/git/will/linux

Pull READ/WRITE_ONCE rework from Will Deacon:
 "This the READ_ONCE rework I've been working on for a while, which
  bumps the minimum GCC version and improves code-gen on arm64 when
  stack protector is enabled"

[ Side note: I'm _really_ tempted to raise the minimum gcc version to
  4.9, so that we can just say that we require _Generic() support.

  That would allow us to more cleanly handle a lot of the cases where we
  depend on very complex macros with 'sizeof' or __builtin_choose_expr()
  with __builtin_types_compatible_p() etc.

  This branch has a workaround for sparse not handling _Generic(),
  either, but that was already fixed in the sparse development branch,
  so it's really just gcc-4.9 that we'd require.   - Linus ]

* 'rwonce/rework' of git://git.kernel.org/pub/scm/linux/kernel/git/will/linux:
  compiler_types.h: Use unoptimized __unqual_scalar_typeof for sparse
  compiler_types.h: Optimize __unqual_scalar_typeof compilation time
  compiler.h: Enforce that READ_ONCE_NOCHECK() access size is sizeof(long)
  compiler-types.h: Include naked type in __pick_integer_type() match
  READ_ONCE: Fix comment describing 2x32-bit atomicity
  gcov: Remove old GCC 3.4 support
  arm64: barrier: Use '__unqual_scalar_typeof' for acquire/release macros
  locking/barriers: Use '__unqual_scalar_typeof' for load-acquire macros
  READ_ONCE: Drop pointer qualifiers when reading from scalar types
  READ_ONCE: Enforce atomicity for {READ,WRITE}_ONCE() memory accesses
  READ_ONCE: Simplify implementations of {READ,WRITE}_ONCE()
  arm64: csum: Disable KASAN for do_csum()
  fault_inject: Don't rely on "return value" from WRITE_ONCE()
  net: tls: Avoid assigning 'const' pointer to non-const pointer
  netfilter: Avoid assigning 'const' pointer to non-const pointer
  compiler/gcc: Raise minimum GCC version for kernel builds to 4.8
This commit is contained in:
Linus Torvalds 2020-06-10 14:46:54 -07:00
Родитель 78c24f7bee b398ace5d2
Коммит 4152d146ee
18 изменённых файлов: 161 добавлений и 719 удалений

Просмотреть файл

@ -29,7 +29,7 @@ you probably needn't concern yourself with pcmciautils.
====================== =============== ========================================
Program Minimal version Command to check the version
====================== =============== ========================================
GNU C 4.6 gcc --version
GNU C 4.8 gcc --version
GNU make 3.81 make --version
binutils 2.23 ld -v
flex 2.5.35 flex --version

Просмотреть файл

@ -30,7 +30,7 @@ config CRYPTO_SHA1_ARM_NEON
config CRYPTO_SHA1_ARM_CE
tristate "SHA1 digest algorithm (ARM v8 Crypto Extensions)"
depends on KERNEL_MODE_NEON && (CC_IS_CLANG || GCC_VERSION >= 40800)
depends on KERNEL_MODE_NEON
select CRYPTO_SHA1_ARM
select CRYPTO_HASH
help
@ -39,7 +39,7 @@ config CRYPTO_SHA1_ARM_CE
config CRYPTO_SHA2_ARM_CE
tristate "SHA-224/256 digest algorithm (ARM v8 Crypto Extensions)"
depends on KERNEL_MODE_NEON && (CC_IS_CLANG || GCC_VERSION >= 40800)
depends on KERNEL_MODE_NEON
select CRYPTO_SHA256_ARM
select CRYPTO_HASH
help
@ -96,7 +96,7 @@ config CRYPTO_AES_ARM_BS
config CRYPTO_AES_ARM_CE
tristate "Accelerated AES using ARMv8 Crypto Extensions"
depends on KERNEL_MODE_NEON && (CC_IS_CLANG || GCC_VERSION >= 40800)
depends on KERNEL_MODE_NEON
select CRYPTO_SKCIPHER
select CRYPTO_LIB_AES
select CRYPTO_SIMD
@ -106,7 +106,7 @@ config CRYPTO_AES_ARM_CE
config CRYPTO_GHASH_ARM_CE
tristate "PMULL-accelerated GHASH using NEON/ARMv8 Crypto Extensions"
depends on KERNEL_MODE_NEON && (CC_IS_CLANG || GCC_VERSION >= 40800)
depends on KERNEL_MODE_NEON
select CRYPTO_HASH
select CRYPTO_CRYPTD
select CRYPTO_GF128MUL
@ -118,13 +118,13 @@ config CRYPTO_GHASH_ARM_CE
config CRYPTO_CRCT10DIF_ARM_CE
tristate "CRCT10DIF digest algorithm using PMULL instructions"
depends on KERNEL_MODE_NEON && (CC_IS_CLANG || GCC_VERSION >= 40800)
depends on KERNEL_MODE_NEON
depends on CRC_T10DIF
select CRYPTO_HASH
config CRYPTO_CRC32_ARM_CE
tristate "CRC32(C) digest algorithm using CRC and/or PMULL instructions"
depends on KERNEL_MODE_NEON && (CC_IS_CLANG || GCC_VERSION >= 40800)
depends on KERNEL_MODE_NEON
depends on CRC32
select CRYPTO_HASH

Просмотреть файл

@ -76,8 +76,8 @@ static inline unsigned long array_index_mask_nospec(unsigned long idx,
#define __smp_store_release(p, v) \
do { \
typeof(p) __p = (p); \
union { typeof(*p) __val; char __c[1]; } __u = \
{ .__val = (__force typeof(*p)) (v) }; \
union { __unqual_scalar_typeof(*p) __val; char __c[1]; } __u = \
{ .__val = (__force __unqual_scalar_typeof(*p)) (v) }; \
compiletime_assert_atomic_type(*p); \
kasan_check_write(__p, sizeof(*p)); \
switch (sizeof(*p)) { \
@ -110,7 +110,7 @@ do { \
#define __smp_load_acquire(p) \
({ \
union { typeof(*p) __val; char __c[1]; } __u; \
union { __unqual_scalar_typeof(*p) __val; char __c[1]; } __u; \
typeof(p) __p = (p); \
compiletime_assert_atomic_type(*p); \
kasan_check_read(__p, sizeof(*p)); \
@ -136,33 +136,33 @@ do { \
: "Q" (*__p) : "memory"); \
break; \
} \
__u.__val; \
(typeof(*p))__u.__val; \
})
#define smp_cond_load_relaxed(ptr, cond_expr) \
({ \
typeof(ptr) __PTR = (ptr); \
typeof(*ptr) VAL; \
__unqual_scalar_typeof(*ptr) VAL; \
for (;;) { \
VAL = READ_ONCE(*__PTR); \
if (cond_expr) \
break; \
__cmpwait_relaxed(__PTR, VAL); \
} \
VAL; \
(typeof(*ptr))VAL; \
})
#define smp_cond_load_acquire(ptr, cond_expr) \
({ \
typeof(ptr) __PTR = (ptr); \
typeof(*ptr) VAL; \
__unqual_scalar_typeof(*ptr) VAL; \
for (;;) { \
VAL = smp_load_acquire(__PTR); \
if (cond_expr) \
break; \
__cmpwait_relaxed(__PTR, VAL); \
} \
VAL; \
(typeof(*ptr))VAL; \
})
#include <asm-generic/barrier.h>

Просмотреть файл

@ -14,7 +14,11 @@ static u64 accumulate(u64 sum, u64 data)
return tmp + (tmp >> 64);
}
unsigned int do_csum(const unsigned char *buff, int len)
/*
* We over-read the buffer and this makes KASAN unhappy. Instead, disable
* instrumentation and call kasan explicitly.
*/
unsigned int __no_sanitize_address do_csum(const unsigned char *buff, int len)
{
unsigned int offset, shift, sum;
const u64 *ptr;
@ -42,7 +46,7 @@ unsigned int do_csum(const unsigned char *buff, int len)
* odd/even alignment, and means we can ignore it until the very end.
*/
shift = offset * 8;
data = READ_ONCE_NOCHECK(*ptr++);
data = *ptr++;
#ifdef __LITTLE_ENDIAN
data = (data >> shift) << shift;
#else
@ -58,10 +62,10 @@ unsigned int do_csum(const unsigned char *buff, int len)
while (unlikely(len > 64)) {
__uint128_t tmp1, tmp2, tmp3, tmp4;
tmp1 = READ_ONCE_NOCHECK(*(__uint128_t *)ptr);
tmp2 = READ_ONCE_NOCHECK(*(__uint128_t *)(ptr + 2));
tmp3 = READ_ONCE_NOCHECK(*(__uint128_t *)(ptr + 4));
tmp4 = READ_ONCE_NOCHECK(*(__uint128_t *)(ptr + 6));
tmp1 = *(__uint128_t *)ptr;
tmp2 = *(__uint128_t *)(ptr + 2);
tmp3 = *(__uint128_t *)(ptr + 4);
tmp4 = *(__uint128_t *)(ptr + 6);
len -= 64;
ptr += 8;
@ -85,7 +89,7 @@ unsigned int do_csum(const unsigned char *buff, int len)
__uint128_t tmp;
sum64 = accumulate(sum64, data);
tmp = READ_ONCE_NOCHECK(*(__uint128_t *)ptr);
tmp = *(__uint128_t *)ptr;
len -= 16;
ptr += 2;
@ -100,7 +104,7 @@ unsigned int do_csum(const unsigned char *buff, int len)
}
if (len > 0) {
sum64 = accumulate(sum64, data);
data = READ_ONCE_NOCHECK(*ptr);
data = *ptr;
len -= 8;
}
/*

Просмотреть файл

@ -316,7 +316,6 @@ config CRYPTO_AEGIS128
config CRYPTO_AEGIS128_SIMD
bool "Support SIMD acceleration for AEGIS-128"
depends on CRYPTO_AEGIS128 && ((ARM || ARM64) && KERNEL_MODE_NEON)
depends on !ARM || CC_IS_CLANG || GCC_VERSION >= 40800
default y
config CRYPTO_AEGIS128_AESNI_SSE2

Просмотреть файл

@ -64,7 +64,7 @@ static void xen_get_runstate_snapshot_cpu_delta(
do {
state_time = get64(&state->state_entry_time);
rmb(); /* Hypervisor might update data. */
*res = READ_ONCE(*state);
*res = __READ_ONCE(*state);
rmb(); /* Hypervisor might update data. */
} while (get64(&state->state_entry_time) != state_time ||
(state_time & XEN_RUNSTATE_UPDATE));

Просмотреть файл

@ -128,10 +128,10 @@ do { \
#ifndef __smp_load_acquire
#define __smp_load_acquire(p) \
({ \
typeof(*p) ___p1 = READ_ONCE(*p); \
__unqual_scalar_typeof(*p) ___p1 = READ_ONCE(*p); \
compiletime_assert_atomic_type(*p); \
__smp_mb(); \
___p1; \
(typeof(*p))___p1; \
})
#endif
@ -183,10 +183,10 @@ do { \
#ifndef smp_load_acquire
#define smp_load_acquire(p) \
({ \
typeof(*p) ___p1 = READ_ONCE(*p); \
__unqual_scalar_typeof(*p) ___p1 = READ_ONCE(*p); \
compiletime_assert_atomic_type(*p); \
barrier(); \
___p1; \
(typeof(*p))___p1; \
})
#endif
@ -229,14 +229,14 @@ do { \
#ifndef smp_cond_load_relaxed
#define smp_cond_load_relaxed(ptr, cond_expr) ({ \
typeof(ptr) __PTR = (ptr); \
typeof(*ptr) VAL; \
__unqual_scalar_typeof(*ptr) VAL; \
for (;;) { \
VAL = READ_ONCE(*__PTR); \
if (cond_expr) \
break; \
cpu_relax(); \
} \
VAL; \
(typeof(*ptr))VAL; \
})
#endif
@ -250,10 +250,10 @@ do { \
*/
#ifndef smp_cond_load_acquire
#define smp_cond_load_acquire(ptr, cond_expr) ({ \
typeof(*ptr) _val; \
__unqual_scalar_typeof(*ptr) _val; \
_val = smp_cond_load_relaxed(ptr, cond_expr); \
smp_acquire__after_ctrl_dep(); \
_val; \
(typeof(*ptr))_val; \
})
#endif

Просмотреть файл

@ -10,7 +10,8 @@
+ __GNUC_MINOR__ * 100 \
+ __GNUC_PATCHLEVEL__)
#if GCC_VERSION < 40600
/* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58145 */
#if GCC_VERSION < 40800
# error Sorry, your compiler is too old - please upgrade it.
#endif
@ -126,9 +127,7 @@
#if defined(CONFIG_ARCH_USE_BUILTIN_BSWAP) && !defined(__CHECKER__)
#define __HAVE_BUILTIN_BSWAP32__
#define __HAVE_BUILTIN_BSWAP64__
#if GCC_VERSION >= 40800
#define __HAVE_BUILTIN_BSWAP16__
#endif
#endif /* CONFIG_ARCH_USE_BUILTIN_BSWAP && !__CHECKER__ */
#if GCC_VERSION >= 70000

Просмотреть файл

@ -230,60 +230,6 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val,
# define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __LINE__)
#endif
#include <uapi/linux/types.h>
#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)
{
__READ_ONCE_SIZE;
}
#ifdef CONFIG_KASAN
/*
* We can't declare function '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.
*/
# define __no_kasan_or_inline __no_sanitize_address notrace __maybe_unused
#else
# define __no_kasan_or_inline __always_inline
#endif
static __no_kasan_or_inline
void __read_once_size_nocheck(const volatile void *p, void *res, int size)
{
__READ_ONCE_SIZE;
}
static __always_inline void __write_once_size(volatile void *p, void *res, int size)
{
switch (size) {
case 1: *(volatile __u8 *)p = *(__u8 *)res; break;
case 2: *(volatile __u16 *)p = *(__u16 *)res; break;
case 4: *(volatile __u32 *)p = *(__u32 *)res; break;
case 8: *(volatile __u64 *)p = *(__u64 *)res; break;
default:
barrier();
__builtin_memcpy((void *)p, (const void *)res, size);
barrier();
}
}
/*
* Prevent the compiler from merging or refetching reads or writes. The
* compiler is also forbidden from reordering successive instances of
@ -293,11 +239,7 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s
* statements.
*
* These two macros will also work on aggregate data types like structs or
* unions. If the size of the accessed data type exceeds the word size of
* the machine (e.g., 32 bits or 64 bits) READ_ONCE() and WRITE_ONCE() will
* fall back to memcpy(). There's at least two memcpy()s: one for the
* __builtin_memcpy() and then one for the macro doing the copy of variable
* - '__u' allocated on the stack.
* unions.
*
* Their two major use cases are: (1) Mediating communication between
* process-level code and irq/NMI handlers, all running on the same CPU,
@ -309,23 +251,69 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s
#include <asm/barrier.h>
#include <linux/kasan-checks.h>
#define __READ_ONCE(x, check) \
/*
* Use __READ_ONCE() instead of READ_ONCE() if you do not require any
* atomicity or dependency ordering guarantees. Note that this may result
* in tears!
*/
#define __READ_ONCE(x) (*(const volatile __unqual_scalar_typeof(x) *)&(x))
#define __READ_ONCE_SCALAR(x) \
({ \
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)); \
smp_read_barrier_depends(); /* Enforce dependency ordering from x */ \
__u.__val; \
__unqual_scalar_typeof(x) __x = __READ_ONCE(x); \
smp_read_barrier_depends(); \
(typeof(x))__x; \
})
#define READ_ONCE(x) __READ_ONCE(x, 1)
#define READ_ONCE(x) \
({ \
compiletime_assert_rwonce_type(x); \
__READ_ONCE_SCALAR(x); \
})
#define __WRITE_ONCE(x, val) \
do { \
*(volatile typeof(x) *)&(x) = (val); \
} while (0)
#define WRITE_ONCE(x, val) \
do { \
compiletime_assert_rwonce_type(x); \
__WRITE_ONCE(x, val); \
} while (0)
#ifdef CONFIG_KASAN
/*
* We can't declare function 'inline' because __no_sanitize_address conflicts
* 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.
*/
# define __no_kasan_or_inline __no_sanitize_address notrace __maybe_unused
#else
# define __no_kasan_or_inline __always_inline
#endif
static __no_kasan_or_inline
unsigned long __read_once_word_nocheck(const void *addr)
{
return __READ_ONCE(*(unsigned long *)addr);
}
/*
* Use READ_ONCE_NOCHECK() instead of READ_ONCE() if you need
* to hide memory access from KASAN.
* Use READ_ONCE_NOCHECK() instead of READ_ONCE() if you need to load a
* word from memory atomically but without telling KASAN. This is usually
* used by unwinding code when walking the stack of a running process.
*/
#define READ_ONCE_NOCHECK(x) __READ_ONCE(x, 0)
#define READ_ONCE_NOCHECK(x) \
({ \
unsigned long __x; \
compiletime_assert(sizeof(x) == sizeof(__x), \
"Unsupported access size for READ_ONCE_NOCHECK()."); \
__x = __read_once_word_nocheck(&(x)); \
smp_read_barrier_depends(); \
(typeof(x))__x; \
})
static __no_kasan_or_inline
unsigned long read_word_at_a_time(const void *addr)
@ -334,14 +322,6 @@ unsigned long read_word_at_a_time(const void *addr)
return *(unsigned long *)addr;
}
#define WRITE_ONCE(x, val) \
({ \
union { typeof(x) __val; char __c[1]; } __u = \
{ .__val = (__force typeof(x)) (val) }; \
__write_once_size(&(x), __u.__c, sizeof(x)); \
__u.__val; \
})
#endif /* __KERNEL__ */
/*
@ -406,6 +386,16 @@ static inline void *offset_to_ptr(const int *off)
compiletime_assert(__native_word(t), \
"Need native word sized stores/loads for atomicity.")
/*
* Yes, this permits 64-bit accesses on 32-bit architectures. These will
* actually be atomic in some cases (namely Armv7 + LPAE), but for others we
* rely on the access being split into 2x32-bit accesses for a 32-bit quantity
* (e.g. a virtual address) and a strong prevailing wind.
*/
#define compiletime_assert_rwonce_type(t) \
compiletime_assert(__native_word(t) || sizeof(t) == sizeof(long long), \
"Unsupported access size for {READ,WRITE}_ONCE().")
/* &a[0] degrades to a pointer: a different type from an array */
#define __must_be_array(a) BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0]))

Просмотреть файл

@ -218,6 +218,53 @@ struct ftrace_likely_data {
/* Are two types/vars the same type (ignoring qualifiers)? */
#define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
/*
* __unqual_scalar_typeof(x) - Declare an unqualified scalar type, leaving
* non-scalar types unchanged.
*/
#if (defined(CONFIG_CC_IS_GCC) && CONFIG_GCC_VERSION < 40900) || defined(__CHECKER__)
/*
* We build this out of a couple of helper macros in a vain attempt to
* help you keep your lunch down while reading it.
*/
#define __pick_scalar_type(x, type, otherwise) \
__builtin_choose_expr(__same_type(x, type), (type)0, otherwise)
/*
* 'char' is not type-compatible with either 'signed char' or 'unsigned char',
* so we include the naked type here as well as the signed/unsigned variants.
*/
#define __pick_integer_type(x, type, otherwise) \
__pick_scalar_type(x, type, \
__pick_scalar_type(x, unsigned type, \
__pick_scalar_type(x, signed type, otherwise)))
#define __unqual_scalar_typeof(x) typeof( \
__pick_integer_type(x, char, \
__pick_integer_type(x, short, \
__pick_integer_type(x, int, \
__pick_integer_type(x, long, \
__pick_integer_type(x, long long, x))))))
#else
/*
* If supported, prefer C11 _Generic for better compile-times. As above, 'char'
* is not type-compatible with 'signed char', and we define a separate case.
*/
#define __scalar_type_to_expr_cases(type) \
unsigned type: (unsigned type)0, \
signed type: (signed type)0
#define __unqual_scalar_typeof(x) typeof( \
_Generic((x), \
char: (char)0, \
__scalar_type_to_expr_cases(char), \
__scalar_type_to_expr_cases(short), \
__scalar_type_to_expr_cases(int), \
__scalar_type_to_expr_cases(long), \
__scalar_type_to_expr_cases(long long), \
default: (x)))
#endif
/* Is this type a native word size -- useful for atomic operations */
#define __native_word(t) \
(sizeof(t) == sizeof(char) || sizeof(t) == sizeof(short) || \

Просмотреть файл

@ -1293,7 +1293,6 @@ config LD_DEAD_CODE_DATA_ELIMINATION
bool "Dead code and data elimination (EXPERIMENTAL)"
depends on HAVE_LD_DEAD_CODE_DATA_ELIMINATION
depends on EXPERT
depends on !(FUNCTION_TRACER && CC_IS_GCC && GCC_VERSION < 40800)
depends on $(cc-option,-ffunction-sections -fdata-sections)
depends on $(ld-option,--gc-sections)
help

Просмотреть файл

@ -51,28 +51,4 @@ config GCOV_PROFILE_ALL
larger and run slower. Also be sure to exclude files from profiling
which are not linked to the kernel image to prevent linker errors.
choice
prompt "Specify GCOV format"
depends on GCOV_KERNEL
depends on CC_IS_GCC
---help---
The gcov format is usually determined by the GCC version, and the
default is chosen according to your GCC version. However, there are
exceptions where format changes are integrated in lower-version GCCs.
In such a case, change this option to adjust the format used in the
kernel accordingly.
config GCOV_FORMAT_3_4
bool "GCC 3.4 format"
depends on GCC_VERSION < 40700
---help---
Select this option to use the format defined by GCC 3.4.
config GCOV_FORMAT_4_7
bool "GCC 4.7 format"
---help---
Select this option to use the format defined by GCC 4.7.
endchoice
endmenu

Просмотреть файл

@ -2,6 +2,5 @@
ccflags-y := -DSRCTREE='"$(srctree)"' -DOBJTREE='"$(objtree)"'
obj-y := base.o fs.o
obj-$(CONFIG_GCOV_FORMAT_3_4) += gcc_base.o gcc_3_4.o
obj-$(CONFIG_GCOV_FORMAT_4_7) += gcc_base.o gcc_4_7.o
obj-$(CONFIG_CC_IS_GCC) += gcc_base.o gcc_4_7.o
obj-$(CONFIG_CC_IS_CLANG) += clang.o

Просмотреть файл

@ -1,573 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
/*
* This code provides functions to handle gcc's profiling data format
* introduced with gcc 3.4. Future versions of gcc may change the gcov
* format (as happened before), so all format-specific information needs
* to be kept modular and easily exchangeable.
*
* This file is based on gcc-internal definitions. Functions and data
* structures are defined to be compatible with gcc counterparts.
* For a better understanding, refer to gcc source: gcc/gcov-io.h.
*
* Copyright IBM Corp. 2009
* Author(s): Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
*
* Uses gcc-internal data definitions.
*/
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/seq_file.h>
#include <linux/vmalloc.h>
#include "gcov.h"
#define GCOV_COUNTERS 5
static struct gcov_info *gcov_info_head;
/**
* struct gcov_fn_info - profiling meta data per function
* @ident: object file-unique function identifier
* @checksum: function checksum
* @n_ctrs: number of values per counter type belonging to this function
*
* This data is generated by gcc during compilation and doesn't change
* at run-time.
*/
struct gcov_fn_info {
unsigned int ident;
unsigned int checksum;
unsigned int n_ctrs[];
};
/**
* struct gcov_ctr_info - profiling data per counter type
* @num: number of counter values for this type
* @values: array of counter values for this type
* @merge: merge function for counter values of this type (unused)
*
* This data is generated by gcc during compilation and doesn't change
* at run-time with the exception of the values array.
*/
struct gcov_ctr_info {
unsigned int num;
gcov_type *values;
void (*merge)(gcov_type *, unsigned int);
};
/**
* struct gcov_info - profiling data per object file
* @version: gcov version magic indicating the gcc version used for compilation
* @next: list head for a singly-linked list
* @stamp: time stamp
* @filename: name of the associated gcov data file
* @n_functions: number of instrumented functions
* @functions: function data
* @ctr_mask: mask specifying which counter types are active
* @counts: counter data per counter type
*
* This data is generated by gcc during compilation and doesn't change
* at run-time with the exception of the next pointer.
*/
struct gcov_info {
unsigned int version;
struct gcov_info *next;
unsigned int stamp;
const char *filename;
unsigned int n_functions;
const struct gcov_fn_info *functions;
unsigned int ctr_mask;
struct gcov_ctr_info counts[];
};
/**
* gcov_info_filename - return info filename
* @info: profiling data set
*/
const char *gcov_info_filename(struct gcov_info *info)
{
return info->filename;
}
/**
* gcov_info_version - return info version
* @info: profiling data set
*/
unsigned int gcov_info_version(struct gcov_info *info)
{
return info->version;
}
/**
* gcov_info_next - return next profiling data set
* @info: profiling data set
*
* Returns next gcov_info following @info or first gcov_info in the chain if
* @info is %NULL.
*/
struct gcov_info *gcov_info_next(struct gcov_info *info)
{
if (!info)
return gcov_info_head;
return info->next;
}
/**
* gcov_info_link - link/add profiling data set to the list
* @info: profiling data set
*/
void gcov_info_link(struct gcov_info *info)
{
info->next = gcov_info_head;
gcov_info_head = info;
}
/**
* gcov_info_unlink - unlink/remove profiling data set from the list
* @prev: previous profiling data set
* @info: profiling data set
*/
void gcov_info_unlink(struct gcov_info *prev, struct gcov_info *info)
{
if (prev)
prev->next = info->next;
else
gcov_info_head = info->next;
}
/**
* gcov_info_within_module - check if a profiling data set belongs to a module
* @info: profiling data set
* @mod: module
*
* Returns true if profiling data belongs module, false otherwise.
*/
bool gcov_info_within_module(struct gcov_info *info, struct module *mod)
{
return within_module((unsigned long)info, mod);
}
/* Symbolic links to be created for each profiling data file. */
const struct gcov_link gcov_link[] = {
{ OBJ_TREE, "gcno" }, /* Link to .gcno file in $(objtree). */
{ 0, NULL},
};
/*
* Determine whether a counter is active. Based on gcc magic. Doesn't change
* at run-time.
*/
static int counter_active(struct gcov_info *info, unsigned int type)
{
return (1 << type) & info->ctr_mask;
}
/* Determine number of active counters. Based on gcc magic. */
static unsigned int num_counter_active(struct gcov_info *info)
{
unsigned int i;
unsigned int result = 0;
for (i = 0; i < GCOV_COUNTERS; i++) {
if (counter_active(info, i))
result++;
}
return result;
}
/**
* gcov_info_reset - reset profiling data to zero
* @info: profiling data set
*/
void gcov_info_reset(struct gcov_info *info)
{
unsigned int active = num_counter_active(info);
unsigned int i;
for (i = 0; i < active; i++) {
memset(info->counts[i].values, 0,
info->counts[i].num * sizeof(gcov_type));
}
}
/**
* gcov_info_is_compatible - check if profiling data can be added
* @info1: first profiling data set
* @info2: second profiling data set
*
* Returns non-zero if profiling data can be added, zero otherwise.
*/
int gcov_info_is_compatible(struct gcov_info *info1, struct gcov_info *info2)
{
return (info1->stamp == info2->stamp);
}
/**
* gcov_info_add - add up profiling data
* @dest: profiling data set to which data is added
* @source: profiling data set which is added
*
* Adds profiling counts of @source to @dest.
*/
void gcov_info_add(struct gcov_info *dest, struct gcov_info *source)
{
unsigned int i;
unsigned int j;
for (i = 0; i < num_counter_active(dest); i++) {
for (j = 0; j < dest->counts[i].num; j++) {
dest->counts[i].values[j] +=
source->counts[i].values[j];
}
}
}
/* Get size of function info entry. Based on gcc magic. */
static size_t get_fn_size(struct gcov_info *info)
{
size_t size;
size = sizeof(struct gcov_fn_info) + num_counter_active(info) *
sizeof(unsigned int);
if (__alignof__(struct gcov_fn_info) > sizeof(unsigned int))
size = ALIGN(size, __alignof__(struct gcov_fn_info));
return size;
}
/* Get address of function info entry. Based on gcc magic. */
static struct gcov_fn_info *get_fn_info(struct gcov_info *info, unsigned int fn)
{
return (struct gcov_fn_info *)
((char *) info->functions + fn * get_fn_size(info));
}
/**
* gcov_info_dup - duplicate profiling data set
* @info: profiling data set to duplicate
*
* Return newly allocated duplicate on success, %NULL on error.
*/
struct gcov_info *gcov_info_dup(struct gcov_info *info)
{
struct gcov_info *dup;
unsigned int i;
unsigned int active;
/* Duplicate gcov_info. */
active = num_counter_active(info);
dup = kzalloc(struct_size(dup, counts, active), GFP_KERNEL);
if (!dup)
return NULL;
dup->version = info->version;
dup->stamp = info->stamp;
dup->n_functions = info->n_functions;
dup->ctr_mask = info->ctr_mask;
/* Duplicate filename. */
dup->filename = kstrdup(info->filename, GFP_KERNEL);
if (!dup->filename)
goto err_free;
/* Duplicate table of functions. */
dup->functions = kmemdup(info->functions, info->n_functions *
get_fn_size(info), GFP_KERNEL);
if (!dup->functions)
goto err_free;
/* Duplicate counter arrays. */
for (i = 0; i < active ; i++) {
struct gcov_ctr_info *ctr = &info->counts[i];
size_t size = ctr->num * sizeof(gcov_type);
dup->counts[i].num = ctr->num;
dup->counts[i].merge = ctr->merge;
dup->counts[i].values = vmalloc(size);
if (!dup->counts[i].values)
goto err_free;
memcpy(dup->counts[i].values, ctr->values, size);
}
return dup;
err_free:
gcov_info_free(dup);
return NULL;
}
/**
* gcov_info_free - release memory for profiling data set duplicate
* @info: profiling data set duplicate to free
*/
void gcov_info_free(struct gcov_info *info)
{
unsigned int active = num_counter_active(info);
unsigned int i;
for (i = 0; i < active ; i++)
vfree(info->counts[i].values);
kfree(info->functions);
kfree(info->filename);
kfree(info);
}
/**
* struct type_info - iterator helper array
* @ctr_type: counter type
* @offset: index of the first value of the current function for this type
*
* This array is needed to convert the in-memory data format into the in-file
* data format:
*
* In-memory:
* for each counter type
* for each function
* values
*
* In-file:
* for each function
* for each counter type
* values
*
* See gcc source gcc/gcov-io.h for more information on data organization.
*/
struct type_info {
int ctr_type;
unsigned int offset;
};
/**
* struct gcov_iterator - specifies current file position in logical records
* @info: associated profiling data
* @record: record type
* @function: function number
* @type: counter type
* @count: index into values array
* @num_types: number of counter types
* @type_info: helper array to get values-array offset for current function
*/
struct gcov_iterator {
struct gcov_info *info;
int record;
unsigned int function;
unsigned int type;
unsigned int count;
int num_types;
struct type_info type_info[];
};
static struct gcov_fn_info *get_func(struct gcov_iterator *iter)
{
return get_fn_info(iter->info, iter->function);
}
static struct type_info *get_type(struct gcov_iterator *iter)
{
return &iter->type_info[iter->type];
}
/**
* gcov_iter_new - allocate and initialize profiling data iterator
* @info: profiling data set to be iterated
*
* Return file iterator on success, %NULL otherwise.
*/
struct gcov_iterator *gcov_iter_new(struct gcov_info *info)
{
struct gcov_iterator *iter;
iter = kzalloc(struct_size(iter, type_info, num_counter_active(info)),
GFP_KERNEL);
if (iter)
iter->info = info;
return iter;
}
/**
* gcov_iter_free - release memory for iterator
* @iter: file iterator to free
*/
void gcov_iter_free(struct gcov_iterator *iter)
{
kfree(iter);
}
/**
* gcov_iter_get_info - return profiling data set for given file iterator
* @iter: file iterator
*/
struct gcov_info *gcov_iter_get_info(struct gcov_iterator *iter)
{
return iter->info;
}
/**
* gcov_iter_start - reset file iterator to starting position
* @iter: file iterator
*/
void gcov_iter_start(struct gcov_iterator *iter)
{
int i;
iter->record = 0;
iter->function = 0;
iter->type = 0;
iter->count = 0;
iter->num_types = 0;
for (i = 0; i < GCOV_COUNTERS; i++) {
if (counter_active(iter->info, i)) {
iter->type_info[iter->num_types].ctr_type = i;
iter->type_info[iter->num_types++].offset = 0;
}
}
}
/* Mapping of logical record number to actual file content. */
#define RECORD_FILE_MAGIC 0
#define RECORD_GCOV_VERSION 1
#define RECORD_TIME_STAMP 2
#define RECORD_FUNCTION_TAG 3
#define RECORD_FUNCTON_TAG_LEN 4
#define RECORD_FUNCTION_IDENT 5
#define RECORD_FUNCTION_CHECK 6
#define RECORD_COUNT_TAG 7
#define RECORD_COUNT_LEN 8
#define RECORD_COUNT 9
/**
* gcov_iter_next - advance file iterator to next logical record
* @iter: file iterator
*
* Return zero if new position is valid, non-zero if iterator has reached end.
*/
int gcov_iter_next(struct gcov_iterator *iter)
{
switch (iter->record) {
case RECORD_FILE_MAGIC:
case RECORD_GCOV_VERSION:
case RECORD_FUNCTION_TAG:
case RECORD_FUNCTON_TAG_LEN:
case RECORD_FUNCTION_IDENT:
case RECORD_COUNT_TAG:
/* Advance to next record */
iter->record++;
break;
case RECORD_COUNT:
/* Advance to next count */
iter->count++;
/* fall through */
case RECORD_COUNT_LEN:
if (iter->count < get_func(iter)->n_ctrs[iter->type]) {
iter->record = 9;
break;
}
/* Advance to next counter type */
get_type(iter)->offset += iter->count;
iter->count = 0;
iter->type++;
/* fall through */
case RECORD_FUNCTION_CHECK:
if (iter->type < iter->num_types) {
iter->record = 7;
break;
}
/* Advance to next function */
iter->type = 0;
iter->function++;
/* fall through */
case RECORD_TIME_STAMP:
if (iter->function < iter->info->n_functions)
iter->record = 3;
else
iter->record = -1;
break;
}
/* Check for EOF. */
if (iter->record == -1)
return -EINVAL;
else
return 0;
}
/**
* seq_write_gcov_u32 - write 32 bit number in gcov format to seq_file
* @seq: seq_file handle
* @v: value to be stored
*
* Number format defined by gcc: numbers are recorded in the 32 bit
* unsigned binary form of the endianness of the machine generating the
* file.
*/
static int seq_write_gcov_u32(struct seq_file *seq, u32 v)
{
return seq_write(seq, &v, sizeof(v));
}
/**
* seq_write_gcov_u64 - write 64 bit number in gcov format to seq_file
* @seq: seq_file handle
* @v: value to be stored
*
* Number format defined by gcc: numbers are recorded in the 32 bit
* unsigned binary form of the endianness of the machine generating the
* file. 64 bit numbers are stored as two 32 bit numbers, the low part
* first.
*/
static int seq_write_gcov_u64(struct seq_file *seq, u64 v)
{
u32 data[2];
data[0] = (v & 0xffffffffUL);
data[1] = (v >> 32);
return seq_write(seq, data, sizeof(data));
}
/**
* gcov_iter_write - write data for current pos to seq_file
* @iter: file iterator
* @seq: seq_file handle
*
* Return zero on success, non-zero otherwise.
*/
int gcov_iter_write(struct gcov_iterator *iter, struct seq_file *seq)
{
int rc = -EINVAL;
switch (iter->record) {
case RECORD_FILE_MAGIC:
rc = seq_write_gcov_u32(seq, GCOV_DATA_MAGIC);
break;
case RECORD_GCOV_VERSION:
rc = seq_write_gcov_u32(seq, iter->info->version);
break;
case RECORD_TIME_STAMP:
rc = seq_write_gcov_u32(seq, iter->info->stamp);
break;
case RECORD_FUNCTION_TAG:
rc = seq_write_gcov_u32(seq, GCOV_TAG_FUNCTION);
break;
case RECORD_FUNCTON_TAG_LEN:
rc = seq_write_gcov_u32(seq, 2);
break;
case RECORD_FUNCTION_IDENT:
rc = seq_write_gcov_u32(seq, get_func(iter)->ident);
break;
case RECORD_FUNCTION_CHECK:
rc = seq_write_gcov_u32(seq, get_func(iter)->checksum);
break;
case RECORD_COUNT_TAG:
rc = seq_write_gcov_u32(seq,
GCOV_TAG_FOR_COUNTER(get_type(iter)->ctr_type));
break;
case RECORD_COUNT_LEN:
rc = seq_write_gcov_u32(seq,
get_func(iter)->n_ctrs[iter->type] * 2);
break;
case RECORD_COUNT:
rc = seq_write_gcov_u64(seq,
iter->info->counts[iter->type].
values[iter->count + get_type(iter)->offset]);
break;
}
return rc;
}

Просмотреть файл

@ -106,7 +106,9 @@ bool should_fail(struct fault_attr *attr, ssize_t size)
unsigned int fail_nth = READ_ONCE(current->fail_nth);
if (fail_nth) {
if (!WRITE_ONCE(current->fail_nth, fail_nth - 1))
fail_nth--;
WRITE_ONCE(current->fail_nth, fail_nth);
if (!fail_nth)
goto fail;
return false;

Просмотреть файл

@ -376,7 +376,7 @@ static bool nf_remove_net_hook(struct nf_hook_entries *old,
if (orig_ops[i] != unreg)
continue;
WRITE_ONCE(old->hooks[i].hook, accept_all);
WRITE_ONCE(orig_ops[i], &dummy_ops);
WRITE_ONCE(orig_ops[i], (void *)&dummy_ops);
return true;
}

Просмотреть файл

@ -629,7 +629,7 @@ struct tls_context *tls_ctx_create(struct sock *sk)
static void tls_build_proto(struct sock *sk)
{
int ip_ver = sk->sk_family == AF_INET6 ? TLSV6 : TLSV4;
const struct proto *prot = READ_ONCE(sk->sk_prot);
struct proto *prot = READ_ONCE(sk->sk_prot);
/* Build IPv6 TLS whenever the address of tcpv6 _prot changes */
if (ip_ver == TLSV6 &&

Просмотреть файл

@ -8,7 +8,7 @@ config HAVE_GCC_PLUGINS
menuconfig GCC_PLUGINS
bool "GCC plugins"
depends on HAVE_GCC_PLUGINS
depends on CC_IS_GCC && GCC_VERSION >= 40800
depends on CC_IS_GCC
depends on $(success,$(srctree)/scripts/gcc-plugin.sh $(CC))
default y
help