Skip to content

Commit d6c4c11

Browse files
committed
Merge branch 'kcsan' of git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu into locking/core
Pull KCSAN updates for v5.10 from Paul E. McKenney: - Improve kernel messages. - Be more permissive with bitops races under KCSAN_ASSUME_PLAIN_WRITES_ATOMIC=y. - Optimize debugfs stat counters. - Introduce the instrument_*read_write() annotations, to provide a finer description of certain ops - using KCSAN's compound instrumentation. Use them for atomic RNW and bitops, where appropriate. Doing this might find new races. (Depends on the compiler having tsan-compound-read-before-write=1 support.) - Support atomic built-ins, which will help certain architectures, such as s390. - Misc enhancements and smaller fixes. Signed-off-by: Ingo Molnar <mingo@kernel.org>
2 parents e705d39 + cd290ec commit d6c4c11

16 files changed

Lines changed: 677 additions & 347 deletions

include/asm-generic/atomic-instrumented.h

Lines changed: 165 additions & 165 deletions
Large diffs are not rendered by default.

include/asm-generic/bitops/instrumented-atomic.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ static inline void change_bit(long nr, volatile unsigned long *addr)
6767
*/
6868
static inline bool test_and_set_bit(long nr, volatile unsigned long *addr)
6969
{
70-
instrument_atomic_write(addr + BIT_WORD(nr), sizeof(long));
70+
instrument_atomic_read_write(addr + BIT_WORD(nr), sizeof(long));
7171
return arch_test_and_set_bit(nr, addr);
7272
}
7373

@@ -80,7 +80,7 @@ static inline bool test_and_set_bit(long nr, volatile unsigned long *addr)
8080
*/
8181
static inline bool test_and_clear_bit(long nr, volatile unsigned long *addr)
8282
{
83-
instrument_atomic_write(addr + BIT_WORD(nr), sizeof(long));
83+
instrument_atomic_read_write(addr + BIT_WORD(nr), sizeof(long));
8484
return arch_test_and_clear_bit(nr, addr);
8585
}
8686

@@ -93,7 +93,7 @@ static inline bool test_and_clear_bit(long nr, volatile unsigned long *addr)
9393
*/
9494
static inline bool test_and_change_bit(long nr, volatile unsigned long *addr)
9595
{
96-
instrument_atomic_write(addr + BIT_WORD(nr), sizeof(long));
96+
instrument_atomic_read_write(addr + BIT_WORD(nr), sizeof(long));
9797
return arch_test_and_change_bit(nr, addr);
9898
}
9999

include/asm-generic/bitops/instrumented-lock.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ static inline void __clear_bit_unlock(long nr, volatile unsigned long *addr)
5252
*/
5353
static inline bool test_and_set_bit_lock(long nr, volatile unsigned long *addr)
5454
{
55-
instrument_atomic_write(addr + BIT_WORD(nr), sizeof(long));
55+
instrument_atomic_read_write(addr + BIT_WORD(nr), sizeof(long));
5656
return arch_test_and_set_bit_lock(nr, addr);
5757
}
5858

include/asm-generic/bitops/instrumented-non-atomic.h

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,30 @@ static inline void __change_bit(long nr, volatile unsigned long *addr)
5858
arch___change_bit(nr, addr);
5959
}
6060

61+
static inline void __instrument_read_write_bitop(long nr, volatile unsigned long *addr)
62+
{
63+
if (IS_ENABLED(CONFIG_KCSAN_ASSUME_PLAIN_WRITES_ATOMIC)) {
64+
/*
65+
* We treat non-atomic read-write bitops a little more special.
66+
* Given the operations here only modify a single bit, assuming
67+
* non-atomicity of the writer is sufficient may be reasonable
68+
* for certain usage (and follows the permissible nature of the
69+
* assume-plain-writes-atomic rule):
70+
* 1. report read-modify-write races -> check read;
71+
* 2. do not report races with marked readers, but do report
72+
* races with unmarked readers -> check "atomic" write.
73+
*/
74+
kcsan_check_read(addr + BIT_WORD(nr), sizeof(long));
75+
/*
76+
* Use generic write instrumentation, in case other sanitizers
77+
* or tools are enabled alongside KCSAN.
78+
*/
79+
instrument_write(addr + BIT_WORD(nr), sizeof(long));
80+
} else {
81+
instrument_read_write(addr + BIT_WORD(nr), sizeof(long));
82+
}
83+
}
84+
6185
/**
6286
* __test_and_set_bit - Set a bit and return its old value
6387
* @nr: Bit to set
@@ -68,7 +92,7 @@ static inline void __change_bit(long nr, volatile unsigned long *addr)
6892
*/
6993
static inline bool __test_and_set_bit(long nr, volatile unsigned long *addr)
7094
{
71-
instrument_write(addr + BIT_WORD(nr), sizeof(long));
95+
__instrument_read_write_bitop(nr, addr);
7296
return arch___test_and_set_bit(nr, addr);
7397
}
7498

@@ -82,7 +106,7 @@ static inline bool __test_and_set_bit(long nr, volatile unsigned long *addr)
82106
*/
83107
static inline bool __test_and_clear_bit(long nr, volatile unsigned long *addr)
84108
{
85-
instrument_write(addr + BIT_WORD(nr), sizeof(long));
109+
__instrument_read_write_bitop(nr, addr);
86110
return arch___test_and_clear_bit(nr, addr);
87111
}
88112

@@ -96,7 +120,7 @@ static inline bool __test_and_clear_bit(long nr, volatile unsigned long *addr)
96120
*/
97121
static inline bool __test_and_change_bit(long nr, volatile unsigned long *addr)
98122
{
99-
instrument_write(addr + BIT_WORD(nr), sizeof(long));
123+
__instrument_read_write_bitop(nr, addr);
100124
return arch___test_and_change_bit(nr, addr);
101125
}
102126

include/linux/instrumented.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,21 @@ static __always_inline void instrument_write(const volatile void *v, size_t size
4242
kcsan_check_write(v, size);
4343
}
4444

45+
/**
46+
* instrument_read_write - instrument regular read-write access
47+
*
48+
* Instrument a regular write access. The instrumentation should be inserted
49+
* before the actual write happens.
50+
*
51+
* @ptr address of access
52+
* @size size of access
53+
*/
54+
static __always_inline void instrument_read_write(const volatile void *v, size_t size)
55+
{
56+
kasan_check_write(v, size);
57+
kcsan_check_read_write(v, size);
58+
}
59+
4560
/**
4661
* instrument_atomic_read - instrument atomic read access
4762
*
@@ -72,6 +87,21 @@ static __always_inline void instrument_atomic_write(const volatile void *v, size
7287
kcsan_check_atomic_write(v, size);
7388
}
7489

90+
/**
91+
* instrument_atomic_read_write - instrument atomic read-write access
92+
*
93+
* Instrument an atomic read-write access. The instrumentation should be
94+
* inserted before the actual write happens.
95+
*
96+
* @ptr address of access
97+
* @size size of access
98+
*/
99+
static __always_inline void instrument_atomic_read_write(const volatile void *v, size_t size)
100+
{
101+
kasan_check_write(v, size);
102+
kcsan_check_atomic_read_write(v, size);
103+
}
104+
75105
/**
76106
* instrument_copy_to_user - instrument reads of copy_to_user
77107
*

include/linux/kcsan-checks.h

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,13 @@
77
#include <linux/compiler_attributes.h>
88
#include <linux/types.h>
99

10-
/*
11-
* ACCESS TYPE MODIFIERS
12-
*
13-
* <none>: normal read access;
14-
* WRITE : write access;
15-
* ATOMIC: access is atomic;
16-
* ASSERT: access is not a regular access, but an assertion;
17-
* SCOPED: access is a scoped access;
18-
*/
19-
#define KCSAN_ACCESS_WRITE 0x1
20-
#define KCSAN_ACCESS_ATOMIC 0x2
21-
#define KCSAN_ACCESS_ASSERT 0x4
22-
#define KCSAN_ACCESS_SCOPED 0x8
10+
/* Access types -- if KCSAN_ACCESS_WRITE is not set, the access is a read. */
11+
#define KCSAN_ACCESS_WRITE (1 << 0) /* Access is a write. */
12+
#define KCSAN_ACCESS_COMPOUND (1 << 1) /* Compounded read-write instrumentation. */
13+
#define KCSAN_ACCESS_ATOMIC (1 << 2) /* Access is atomic. */
14+
/* The following are special, and never due to compiler instrumentation. */
15+
#define KCSAN_ACCESS_ASSERT (1 << 3) /* Access is an assertion. */
16+
#define KCSAN_ACCESS_SCOPED (1 << 4) /* Access is a scoped access. */
2317

2418
/*
2519
* __kcsan_*: Always calls into the runtime when KCSAN is enabled. This may be used
@@ -204,6 +198,15 @@ static inline void __kcsan_disable_current(void) { }
204198
#define __kcsan_check_write(ptr, size) \
205199
__kcsan_check_access(ptr, size, KCSAN_ACCESS_WRITE)
206200

201+
/**
202+
* __kcsan_check_read_write - check regular read-write access for races
203+
*
204+
* @ptr: address of access
205+
* @size: size of access
206+
*/
207+
#define __kcsan_check_read_write(ptr, size) \
208+
__kcsan_check_access(ptr, size, KCSAN_ACCESS_COMPOUND | KCSAN_ACCESS_WRITE)
209+
207210
/**
208211
* kcsan_check_read - check regular read access for races
209212
*
@@ -221,18 +224,30 @@ static inline void __kcsan_disable_current(void) { }
221224
#define kcsan_check_write(ptr, size) \
222225
kcsan_check_access(ptr, size, KCSAN_ACCESS_WRITE)
223226

227+
/**
228+
* kcsan_check_read_write - check regular read-write access for races
229+
*
230+
* @ptr: address of access
231+
* @size: size of access
232+
*/
233+
#define kcsan_check_read_write(ptr, size) \
234+
kcsan_check_access(ptr, size, KCSAN_ACCESS_COMPOUND | KCSAN_ACCESS_WRITE)
235+
224236
/*
225237
* Check for atomic accesses: if atomic accesses are not ignored, this simply
226238
* aliases to kcsan_check_access(), otherwise becomes a no-op.
227239
*/
228240
#ifdef CONFIG_KCSAN_IGNORE_ATOMICS
229-
#define kcsan_check_atomic_read(...) do { } while (0)
230-
#define kcsan_check_atomic_write(...) do { } while (0)
241+
#define kcsan_check_atomic_read(...) do { } while (0)
242+
#define kcsan_check_atomic_write(...) do { } while (0)
243+
#define kcsan_check_atomic_read_write(...) do { } while (0)
231244
#else
232245
#define kcsan_check_atomic_read(ptr, size) \
233246
kcsan_check_access(ptr, size, KCSAN_ACCESS_ATOMIC)
234247
#define kcsan_check_atomic_write(ptr, size) \
235248
kcsan_check_access(ptr, size, KCSAN_ACCESS_ATOMIC | KCSAN_ACCESS_WRITE)
249+
#define kcsan_check_atomic_read_write(ptr, size) \
250+
kcsan_check_access(ptr, size, KCSAN_ACCESS_ATOMIC | KCSAN_ACCESS_WRITE | KCSAN_ACCESS_COMPOUND)
236251
#endif
237252

238253
/**

0 commit comments

Comments
 (0)