Skip to content

Commit bde50d8

Browse files
Sebastian Andrzej Siewiorpaulmckrcu
authored andcommitted
srcu: Avoid local_irq_save() before acquiring spinlock_t
SRCU disables interrupts to get a stable per-CPU pointer and then acquires the spinlock which is in the per-CPU data structure. The release uses spin_unlock_irqrestore(). While this is correct on a non-RT kernel, this conflicts with the RT semantics because the spinlock is converted to a 'sleeping' spinlock. Sleeping locks can obviously not be acquired with interrupts disabled. Acquire the per-CPU pointer `ssp->sda' without disabling preemption and then acquire the spinlock_t of the per-CPU data structure. The lock will ensure that the data is consistent. The added call to check_init_srcu_struct() is now needed because a statically defined srcu_struct may remain uninitialized until this point and the newly introduced locking operation requires an initialized spinlock_t. This change was tested for four hours with 8*SRCU-N and 8*SRCU-P without causing any warnings. Cc: Lai Jiangshan <[email protected]> Cc: "Paul E. McKenney" <[email protected]> Cc: Josh Triplett <[email protected]> Cc: Steven Rostedt <[email protected]> Cc: Mathieu Desnoyers <[email protected]> Cc: [email protected] Signed-off-by: Sebastian Andrzej Siewior <[email protected]> Signed-off-by: Paul E. McKenney <[email protected]>
1 parent 7fef6cf commit bde50d8

File tree

1 file changed

+7
-7
lines changed

1 file changed

+7
-7
lines changed

kernel/rcu/srcutree.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -777,14 +777,15 @@ static bool srcu_might_be_idle(struct srcu_struct *ssp)
777777
unsigned long t;
778778
unsigned long tlast;
779779

780+
check_init_srcu_struct(ssp);
780781
/* If the local srcu_data structure has callbacks, not idle. */
781-
local_irq_save(flags);
782-
sdp = this_cpu_ptr(ssp->sda);
782+
sdp = raw_cpu_ptr(ssp->sda);
783+
spin_lock_irqsave_rcu_node(sdp, flags);
783784
if (rcu_segcblist_pend_cbs(&sdp->srcu_cblist)) {
784-
local_irq_restore(flags);
785+
spin_unlock_irqrestore_rcu_node(sdp, flags);
785786
return false; /* Callbacks already present, so not idle. */
786787
}
787-
local_irq_restore(flags);
788+
spin_unlock_irqrestore_rcu_node(sdp, flags);
788789

789790
/*
790791
* No local callbacks, so probabalistically probe global state.
@@ -864,9 +865,8 @@ static void __call_srcu(struct srcu_struct *ssp, struct rcu_head *rhp,
864865
}
865866
rhp->func = func;
866867
idx = srcu_read_lock(ssp);
867-
local_irq_save(flags);
868-
sdp = this_cpu_ptr(ssp->sda);
869-
spin_lock_rcu_node(sdp);
868+
sdp = raw_cpu_ptr(ssp->sda);
869+
spin_lock_irqsave_rcu_node(sdp, flags);
870870
rcu_segcblist_enqueue(&sdp->srcu_cblist, rhp);
871871
rcu_segcblist_advance(&sdp->srcu_cblist,
872872
rcu_seq_current(&ssp->srcu_gp_seq));

0 commit comments

Comments
 (0)