On Tue, Sep 06, 2022 at 05:17:57PM +0200, Frederic Weisbecker wrote: > On Tue, Sep 06, 2022 at 03:05:46AM +0000, Joel Fernandes wrote: > > diff --git a/kernel/rcu/tree_nocb.h b/kernel/rcu/tree_nocb.h > > index 4dc86274b3e8..b201606f7c4f 100644 > > --- a/kernel/rcu/tree_nocb.h > > +++ b/kernel/rcu/tree_nocb.h > > @@ -256,6 +256,31 @@ static bool wake_nocb_gp(struct rcu_data *rdp, bool force) > > return __wake_nocb_gp(rdp_gp, rdp, force, flags); > > } > > > > +/* > > + * LAZY_FLUSH_JIFFIES decides the maximum amount of time that > > + * can elapse before lazy callbacks are flushed. Lazy callbacks > > + * could be flushed much earlier for a number of other reasons > > + * however, LAZY_FLUSH_JIFFIES will ensure no lazy callbacks are > > + * left unsubmitted to RCU after those many jiffies. > > + */ > > +#define LAZY_FLUSH_JIFFIES (10 * HZ) > > +unsigned long jiffies_till_flush = LAZY_FLUSH_JIFFIES; > > Still not static. > > > @@ -293,12 +322,16 @@ static void wake_nocb_gp_defer(struct rcu_data *rdp, int waketype, > > * proves to be initially empty, just return false because the no-CB GP > > * kthread may need to be awakened in this case. > > * > > + * Return true if there was something to be flushed and it succeeded, otherwise > > + * false. > > + * > > This kind of contradict the comment that follows. Not sure you need to add > that line because the existing comment seem to cover it. > > > * Note that this function always returns true if rhp is NULL. > > > */ > > static bool rcu_nocb_do_flush_bypass(struct rcu_data *rdp, struct rcu_head *rhp, > > - unsigned long j) > > + unsigned long j, unsigned long flush_flags) > > { > > struct rcu_cblist rcl; > > + bool lazy = flush_flags & FLUSH_BP_LAZY; > > > > WARN_ON_ONCE(!rcu_rdp_is_offloaded(rdp)); > > rcu_lockdep_assert_cblist_protected(rdp); > > @@ -326,13 +372,20 @@ static bool rcu_nocb_do_flush_bypass(struct rcu_data *rdp, struct rcu_head *rhp, > > * Note that this function always returns true if rhp is NULL. > > */ > > static bool rcu_nocb_flush_bypass(struct rcu_data *rdp, struct rcu_head *rhp, > > - unsigned long j) > > + unsigned long j, unsigned long flush_flags) > > { > > + bool ret; > > + > > if (!rcu_rdp_is_offloaded(rdp)) > > return true; > > rcu_lockdep_assert_cblist_protected(rdp); > > rcu_nocb_bypass_lock(rdp); > > - return rcu_nocb_do_flush_bypass(rdp, rhp, j); > > + ret = rcu_nocb_do_flush_bypass(rdp, rhp, j, flush_flags); > > + > > + if (flush_flags & FLUSH_BP_WAKE) > > + wake_nocb_gp(rdp, true); > > Why the true above? > > Also should we check if the wake up is really necessary (otherwise it means we > force a wake up for all rdp's from rcu_barrier())? > > was_alldone = rcu_segcblist_pend_cbs(&rdp->cblist); > ret = rcu_nocb_do_flush_bypass(rdp, rhp, j, flush_flags); > if (was_alldone && rcu_segcblist_pend_cbs(&rdp->cblist)) > wake_nocb_gp(rdp, false); You mean something like the following right? Though I'm thinking if its better to call wake_nocb_gp() from tree.c in entrain() and let that handle the wake. That way, we can get rid of the extra FLUSH_BP flags as well and let the flush callers deal with the wakeups.. Anyway, for testing this should be good... ---8<----------------------- diff --git a/kernel/rcu/tree_nocb.h b/kernel/rcu/tree_nocb.h index bd8f39ee2cd0..e3344c262672 100644 --- a/kernel/rcu/tree_nocb.h +++ b/kernel/rcu/tree_nocb.h @@ -382,15 +382,19 @@ static bool rcu_nocb_flush_bypass(struct rcu_data *rdp, struct rcu_head *rhp, unsigned long j, unsigned long flush_flags) { bool ret; + bool was_alldone; if (!rcu_rdp_is_offloaded(rdp)) return true; rcu_lockdep_assert_cblist_protected(rdp); rcu_nocb_bypass_lock(rdp); + if (flush_flags & FLUSH_BP_WAKE) + was_alldone = !rcu_segcblist_pend_cbs(&rdp->cblist); + ret = rcu_nocb_do_flush_bypass(rdp, rhp, j, flush_flags); - if (flush_flags & FLUSH_BP_WAKE) - wake_nocb_gp(rdp, true); + if (flush_flags & FLUSH_BP_WAKE && was_alldone) + wake_nocb_gp(rdp, false); return ret; } -- 2.37.2.789.g6183377224-goog