Skip to content

Commit b8f7aca

Browse files
Frederic Weisbeckerpaulmckrcu
authored andcommitted
rcu: Fix missing nocb gp wake on rcu_barrier()
In preparation for RCU lazy changes, wake up the RCU nocb gp thread if needed after an entrain. This change prevents the RCU barrier callback from waiting in the queue for several seconds before the lazy callbacks in front of it are serviced. Reported-by: Joel Fernandes (Google) <joel@joelfernandes.org> Signed-off-by: Frederic Weisbecker <frederic@kernel.org> Signed-off-by: Joel Fernandes (Google) <joel@joelfernandes.org> Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
1 parent b50606f commit b8f7aca

3 files changed

Lines changed: 17 additions & 0 deletions

File tree

kernel/rcu/tree.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3894,6 +3894,8 @@ static void rcu_barrier_entrain(struct rcu_data *rdp)
38943894
{
38953895
unsigned long gseq = READ_ONCE(rcu_state.barrier_sequence);
38963896
unsigned long lseq = READ_ONCE(rdp->barrier_seq_snap);
3897+
bool wake_nocb = false;
3898+
bool was_alldone = false;
38973899

38983900
lockdep_assert_held(&rcu_state.barrier_lock);
38993901
if (rcu_seq_state(lseq) || !rcu_seq_state(gseq) || rcu_seq_ctr(lseq) != rcu_seq_ctr(gseq))
@@ -3902,14 +3904,23 @@ static void rcu_barrier_entrain(struct rcu_data *rdp)
39023904
rdp->barrier_head.func = rcu_barrier_callback;
39033905
debug_rcu_head_queue(&rdp->barrier_head);
39043906
rcu_nocb_lock(rdp);
3907+
/*
3908+
* Flush bypass and wakeup rcuog if we add callbacks to an empty regular
3909+
* queue. This way we don't wait for bypass timer that can reach seconds
3910+
* if it's fully lazy.
3911+
*/
3912+
was_alldone = rcu_rdp_is_offloaded(rdp) && !rcu_segcblist_pend_cbs(&rdp->cblist);
39053913
WARN_ON_ONCE(!rcu_nocb_flush_bypass(rdp, NULL, jiffies));
3914+
wake_nocb = was_alldone && rcu_segcblist_pend_cbs(&rdp->cblist);
39063915
if (rcu_segcblist_entrain(&rdp->cblist, &rdp->barrier_head)) {
39073916
atomic_inc(&rcu_state.barrier_cpu_count);
39083917
} else {
39093918
debug_rcu_head_unqueue(&rdp->barrier_head);
39103919
rcu_barrier_trace(TPS("IRQNQ"), -1, rcu_state.barrier_sequence);
39113920
}
39123921
rcu_nocb_unlock(rdp);
3922+
if (wake_nocb)
3923+
wake_nocb_gp(rdp, false);
39133924
smp_store_release(&rdp->barrier_seq_snap, gseq);
39143925
}
39153926

kernel/rcu/tree.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,7 @@ static void zero_cpu_stall_ticks(struct rcu_data *rdp);
439439
static struct swait_queue_head *rcu_nocb_gp_get(struct rcu_node *rnp);
440440
static void rcu_nocb_gp_cleanup(struct swait_queue_head *sq);
441441
static void rcu_init_one_nocb(struct rcu_node *rnp);
442+
static bool wake_nocb_gp(struct rcu_data *rdp, bool force);
442443
static bool rcu_nocb_flush_bypass(struct rcu_data *rdp, struct rcu_head *rhp,
443444
unsigned long j);
444445
static bool rcu_nocb_try_bypass(struct rcu_data *rdp, struct rcu_head *rhp,

kernel/rcu/tree_nocb.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1558,6 +1558,11 @@ static void rcu_init_one_nocb(struct rcu_node *rnp)
15581558
{
15591559
}
15601560

1561+
static bool wake_nocb_gp(struct rcu_data *rdp, bool force)
1562+
{
1563+
return false;
1564+
}
1565+
15611566
static bool rcu_nocb_flush_bypass(struct rcu_data *rdp, struct rcu_head *rhp,
15621567
unsigned long j)
15631568
{

0 commit comments

Comments
 (0)