mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 20:54:03 +02:00
rcu-tasks: Fix IRQ read lock/unlock data race
As noted by Marco Elver: rcu_read_lock_trace() .... t->trc_reader_scp = __srcu_read_lock_fast(&rcu_tasks_trace_srcu_struct); <interrupt> rcu_read_unlock_trace() < ... var decls only ... > scp = t->trc_reader_scp; This constitutes a data race between these two accesses to t->trc_reader_scp. If rcu_read_lock_trace() were to tear its store, this value would be corrupted. This commit therefore defers the rcu_read_lock_untrace() function's load from t->trc_reader_scp until after it has verified that this is the outermost rcu_read_unlock_trace(). With this change, the interrupt handler increments and decrements t->trc_reader_nesting and does not access t->trc_reader_scp, thus avoiding the data race. KCSAN located this issue. Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
This commit is contained in:
parent
7a455d3cae
commit
f99dc9e288
|
|
@ -126,11 +126,13 @@ static inline void rcu_read_unlock_trace(void)
|
|||
struct srcu_ctr __percpu *scp;
|
||||
struct task_struct *t = current;
|
||||
|
||||
scp = t->trc_reader_scp;
|
||||
barrier(); // scp before nesting to protect against interrupt handler.
|
||||
n = READ_ONCE(t->trc_reader_nesting) - 1;
|
||||
WRITE_ONCE(t->trc_reader_nesting, n);
|
||||
if (!n) {
|
||||
if (n) {
|
||||
WRITE_ONCE(t->trc_reader_nesting, n);
|
||||
} else {
|
||||
scp = t->trc_reader_scp; // Compiler cannot hoist load due to data raciness.
|
||||
barrier(); // scp before nesting to protect against interrupt handler.
|
||||
WRITE_ONCE(t->trc_reader_nesting, n);
|
||||
if (!IS_ENABLED(CONFIG_TASKS_TRACE_RCU_NO_MB))
|
||||
smp_mb(); // Placeholder for more selective ordering
|
||||
__srcu_read_unlock_fast(&rcu_tasks_trace_srcu_struct, scp);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user