mirror of
https://github.com/torvalds/linux.git
synced 2026-03-08 01:24:47 +01:00
srcu: Permit Tiny SRCU srcu_read_unlock() with interrupts disabled
The current Tiny SRCU implementation of srcu_read_unlock() awakens the grace-period processing when exiting the outermost SRCU read-side critical section. However, not all Linux-kernel configurations and contexts permit swake_up_one() to be invoked while interrupts are disabled, and this can result in indefinitely extended SRCU grace periods. This commit therefore only invokes swake_up_one() when interrupts are enabled, and introduces polling to the grace-period workqueue handler. Reported-by: kernel test robot <oliver.sang@intel.com> Reported-by: Zqiang <qiang.zhang@linux.dev> Closes: https://lore.kernel.org/oe-lkp/202508261642.b15eefbb-lkp@intel.com Signed-off-by: Paul E. McKenney <paulmck@kernel.org> Signed-off-by: Frederic Weisbecker <frederic@kernel.org>
This commit is contained in:
parent
3a86608788
commit
58ac42f278
1 changed files with 9 additions and 4 deletions
|
|
@ -106,15 +106,15 @@ void __srcu_read_unlock(struct srcu_struct *ssp, int idx)
|
|||
newval = READ_ONCE(ssp->srcu_lock_nesting[idx]) - 1;
|
||||
WRITE_ONCE(ssp->srcu_lock_nesting[idx], newval);
|
||||
preempt_enable();
|
||||
if (!newval && READ_ONCE(ssp->srcu_gp_waiting) && in_task())
|
||||
if (!newval && READ_ONCE(ssp->srcu_gp_waiting) && in_task() && !irqs_disabled())
|
||||
swake_up_one(&ssp->srcu_wq);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__srcu_read_unlock);
|
||||
|
||||
/*
|
||||
* Workqueue handler to drive one grace period and invoke any callbacks
|
||||
* that become ready as a result. Single-CPU and !PREEMPTION operation
|
||||
* means that we get away with murder on synchronization. ;-)
|
||||
* that become ready as a result. Single-CPU operation and preemption
|
||||
* disabling mean that we get away with murder on synchronization. ;-)
|
||||
*/
|
||||
void srcu_drive_gp(struct work_struct *wp)
|
||||
{
|
||||
|
|
@ -141,7 +141,12 @@ void srcu_drive_gp(struct work_struct *wp)
|
|||
WRITE_ONCE(ssp->srcu_idx, ssp->srcu_idx + 1);
|
||||
WRITE_ONCE(ssp->srcu_gp_waiting, true); /* srcu_read_unlock() wakes! */
|
||||
preempt_enable();
|
||||
swait_event_exclusive(ssp->srcu_wq, !READ_ONCE(ssp->srcu_lock_nesting[idx]));
|
||||
do {
|
||||
// Deadlock issues prevent __srcu_read_unlock() from
|
||||
// doing an unconditional wakeup, so polling is required.
|
||||
swait_event_timeout_exclusive(ssp->srcu_wq,
|
||||
!READ_ONCE(ssp->srcu_lock_nesting[idx]), HZ / 10);
|
||||
} while (READ_ONCE(ssp->srcu_lock_nesting[idx]));
|
||||
preempt_disable(); // Needed for PREEMPT_LAZY
|
||||
WRITE_ONCE(ssp->srcu_gp_waiting, false); /* srcu_read_unlock() cheap. */
|
||||
WRITE_ONCE(ssp->srcu_idx, ssp->srcu_idx + 1);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue