Skip to content

Commit dbcf642

Browse files
Frederic Weisbeckerchantra
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) <[email protected]> Signed-off-by: Frederic Weisbecker <[email protected]> Signed-off-by: Joel Fernandes (Google) <[email protected]> Signed-off-by: Paul E. McKenney <[email protected]>
1 parent da314e0 commit dbcf642

File tree

3 files changed

+17
-0
lines changed

3 files changed

+17
-0
lines changed

kernel/rcu/tree.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3914,6 +3914,8 @@ static void rcu_barrier_entrain(struct rcu_data *rdp)
39143914
{
39153915
unsigned long gseq = READ_ONCE(rcu_state.barrier_sequence);
39163916
unsigned long lseq = READ_ONCE(rdp->barrier_seq_snap);
3917+
bool wake_nocb = false;
3918+
bool was_alldone = false;
39173919

39183920
lockdep_assert_held(&rcu_state.barrier_lock);
39193921
if (rcu_seq_state(lseq) || !rcu_seq_state(gseq) || rcu_seq_ctr(lseq) != rcu_seq_ctr(gseq))
@@ -3922,14 +3924,23 @@ static void rcu_barrier_entrain(struct rcu_data *rdp)
39223924
rdp->barrier_head.func = rcu_barrier_callback;
39233925
debug_rcu_head_queue(&rdp->barrier_head);
39243926
rcu_nocb_lock(rdp);
3927+
/*
3928+
* Flush bypass and wakeup rcuog if we add callbacks to an empty regular
3929+
* queue. This way we don't wait for bypass timer that can reach seconds
3930+
* if it's fully lazy.
3931+
*/
3932+
was_alldone = rcu_rdp_is_offloaded(rdp) && !rcu_segcblist_pend_cbs(&rdp->cblist);
39253933
WARN_ON_ONCE(!rcu_nocb_flush_bypass(rdp, NULL, jiffies));
3934+
wake_nocb = was_alldone && rcu_segcblist_pend_cbs(&rdp->cblist);
39263935
if (rcu_segcblist_entrain(&rdp->cblist, &rdp->barrier_head)) {
39273936
atomic_inc(&rcu_state.barrier_cpu_count);
39283937
} else {
39293938
debug_rcu_head_unqueue(&rdp->barrier_head);
39303939
rcu_barrier_trace(TPS("IRQNQ"), -1, rcu_state.barrier_sequence);
39313940
}
39323941
rcu_nocb_unlock(rdp);
3942+
if (wake_nocb)
3943+
wake_nocb_gp(rdp, false);
39333944
smp_store_release(&rdp->barrier_seq_snap, gseq);
39343945
}
39353946

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)