Message ID | 20200214235607.13749-22-paulmck@kernel.org |
---|---|
State | In Next |
Commit | cb8277c5f689cdc1951262e48c1c96b4eefc073a |
Headers | show |
Series |
|
Related | show |
On Fri, 14 Feb 2020 15:55:59 -0800 paulmck@kernel.org wrote: > @@ -1252,10 +1252,10 @@ static bool rcu_future_gp_cleanup(struct rcu_node *rnp) > */ > static void rcu_gp_kthread_wake(void) > { > - if ((current == rcu_state.gp_kthread && > + if ((current == READ_ONCE(rcu_state.gp_kthread) && > !in_irq() && !in_serving_softirq()) || > !READ_ONCE(rcu_state.gp_flags) || > - !rcu_state.gp_kthread) > + !READ_ONCE(rcu_state.gp_kthread)) > return; This looks buggy. You have two instances of READ_ONCE(rcu_state.gp_thread), which means they can be different. Is that intentional? -- Steve
On Fri, Feb 14, 2020 at 10:53:05PM -0500, Steven Rostedt wrote: > On Fri, 14 Feb 2020 15:55:59 -0800 > paulmck@kernel.org wrote: > > > @@ -1252,10 +1252,10 @@ static bool rcu_future_gp_cleanup(struct rcu_node *rnp) > > */ > > static void rcu_gp_kthread_wake(void) > > { > > - if ((current == rcu_state.gp_kthread && > > + if ((current == READ_ONCE(rcu_state.gp_kthread) && > > !in_irq() && !in_serving_softirq()) || > > !READ_ONCE(rcu_state.gp_flags) || > > - !rcu_state.gp_kthread) > > + !READ_ONCE(rcu_state.gp_kthread)) > > return; > > This looks buggy. You have two instances of > READ_ONCE(rcu_state.gp_thread), which means they can be different. Is > that intentional? It might well be a bug, but let's see... The rcu_state.gp_kthread field is initially NULL and transitions only once to the non-NULL pointer to the RCU grace-period kthread's task_struct structure. So yes, this does work, courtesy of the compiler not being allowed to change the order of READ_ONCE() instances and conherence-order rules for READ_ONCE() and WRITE_ONCE(). But it would clearly be way better to do just one READ_ONCE() into a local variable and test that local variable twice. I will make this change, and thank you for calling my attention to it! Thanx, Paul
On Sat, Feb 15, 2020 at 03:01:11AM -0800, Paul E. McKenney wrote: > On Fri, Feb 14, 2020 at 10:53:05PM -0500, Steven Rostedt wrote: > > On Fri, 14 Feb 2020 15:55:59 -0800 > > paulmck@kernel.org wrote: > > > > > @@ -1252,10 +1252,10 @@ static bool rcu_future_gp_cleanup(struct rcu_node *rnp) > > > */ > > > static void rcu_gp_kthread_wake(void) > > > { > > > - if ((current == rcu_state.gp_kthread && > > > + if ((current == READ_ONCE(rcu_state.gp_kthread) && > > > !in_irq() && !in_serving_softirq()) || > > > !READ_ONCE(rcu_state.gp_flags) || > > > - !rcu_state.gp_kthread) > > > + !READ_ONCE(rcu_state.gp_kthread)) > > > return; > > > > This looks buggy. You have two instances of > > READ_ONCE(rcu_state.gp_thread), which means they can be different. Is > > that intentional? > > It might well be a bug, but let's see... > > The rcu_state.gp_kthread field is initially NULL and transitions only once > to the non-NULL pointer to the RCU grace-period kthread's task_struct > structure. So yes, this does work, courtesy of the compiler not being > allowed to change the order of READ_ONCE() instances and conherence-order > rules for READ_ONCE() and WRITE_ONCE(). > > But it would clearly be way better to do just one READ_ONCE() into a > local variable and test that local variable twice. > > I will make this change, and thank you for calling my attention to it! And does the following V2 look better? Thanx, Paul ------------------------------------------------------------------------ commit 35f7c539d30d5b595718302d07334146f8eb7304 Author: Paul E. McKenney <paulmck@kernel.org> Date: Tue Jan 21 12:30:22 2020 -0800 rcu: Don't flag non-starting GPs before GP kthread is running Currently rcu_check_gp_start_stall() complains if a grace period takes too long to start, where "too long" is roughly one RCU CPU stall-warning interval. This has worked well, but there are some debugging Kconfig options (such as CONFIG_EFI_PGT_DUMP=y) that can make booting take a very long time, so much so that the stall-warning interval has expired before RCU's grace-period kthread has even been spawned. This commit therefore resets the rcu_state.gp_req_activity and rcu_state.gp_activity timestamps just before the grace-period kthread is spawned, and modifies the checks and adds ordering to ensure that if rcu_check_gp_start_stall() sees that the grace-period kthread has been spawned, that it will also see the resets applied to the rcu_state.gp_req_activity and rcu_state.gp_activity timestamps. Reported-by: Qian Cai <cai@lca.pw> Signed-off-by: Paul E. McKenney <paulmck@kernel.org> [ paulmck: Fix whitespace issues reported by Qian Cai. ] Tested-by: Qian Cai <cai@lca.pw> [ paulmck: Simplify grace-period wakeup check per Steve Rostedt feedback. ] diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 62383ce..4a4a975 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -1202,7 +1202,7 @@ static bool rcu_start_this_gp(struct rcu_node *rnp_start, struct rcu_data *rdp, trace_rcu_this_gp(rnp, rdp, gp_seq_req, TPS("Startedroot")); WRITE_ONCE(rcu_state.gp_flags, rcu_state.gp_flags | RCU_GP_FLAG_INIT); WRITE_ONCE(rcu_state.gp_req_activity, jiffies); - if (!rcu_state.gp_kthread) { + if (!READ_ONCE(rcu_state.gp_kthread)) { trace_rcu_this_gp(rnp, rdp, gp_seq_req, TPS("NoGPkthread")); goto unlock_out; } @@ -1237,12 +1237,13 @@ static bool rcu_future_gp_cleanup(struct rcu_node *rnp) } /* - * Awaken the grace-period kthread. Don't do a self-awaken (unless in - * an interrupt or softirq handler), and don't bother awakening when there - * is nothing for the grace-period kthread to do (as in several CPUs raced - * to awaken, and we lost), and finally don't try to awaken a kthread that - * has not yet been created. If all those checks are passed, track some - * debug information and awaken. + * Awaken the grace-period kthread. Don't do a self-awaken (unless in an + * interrupt or softirq handler, in which case we just might immediately + * sleep upon return, resulting in a grace-period hang), and don't bother + * awakening when there is nothing for the grace-period kthread to do + * (as in several CPUs raced to awaken, we lost), and finally don't try + * to awaken a kthread that has not yet been created. If all those checks + * are passed, track some debug information and awaken. * * So why do the self-wakeup when in an interrupt or softirq handler * in the grace-period kthread's context? Because the kthread might have @@ -1252,10 +1253,10 @@ static bool rcu_future_gp_cleanup(struct rcu_node *rnp) */ static void rcu_gp_kthread_wake(void) { - if ((current == rcu_state.gp_kthread && - !in_irq() && !in_serving_softirq()) || - !READ_ONCE(rcu_state.gp_flags) || - !rcu_state.gp_kthread) + struct task_struct *t = READ_ONCE(rcu_state.gp_kthread); + + if ((current == t && !in_irq() && !in_serving_softirq()) || + !READ_ONCE(rcu_state.gp_flags) || !t) return; WRITE_ONCE(rcu_state.gp_wake_time, jiffies); WRITE_ONCE(rcu_state.gp_wake_seq, READ_ONCE(rcu_state.gp_seq)); @@ -3554,7 +3555,10 @@ static int __init rcu_spawn_gp_kthread(void) } rnp = rcu_get_root(); raw_spin_lock_irqsave_rcu_node(rnp, flags); - rcu_state.gp_kthread = t; + WRITE_ONCE(rcu_state.gp_activity, jiffies); + WRITE_ONCE(rcu_state.gp_req_activity, jiffies); + // Reset .gp_activity and .gp_req_activity before setting .gp_kthread. + smp_store_release(&rcu_state.gp_kthread, t); /* ^^^ */ raw_spin_unlock_irqrestore_rcu_node(rnp, flags); wake_up_process(t); rcu_spawn_nocb_kthreads(); diff --git a/kernel/rcu/tree_stall.h b/kernel/rcu/tree_stall.h index 488b71d..16ad7ad 100644 --- a/kernel/rcu/tree_stall.h +++ b/kernel/rcu/tree_stall.h @@ -578,6 +578,7 @@ void show_rcu_gp_kthreads(void) unsigned long jw; struct rcu_data *rdp; struct rcu_node *rnp; + struct task_struct *t = READ_ONCE(rcu_state.gp_kthread); j = jiffies; ja = j - READ_ONCE(rcu_state.gp_activity); @@ -585,8 +586,7 @@ void show_rcu_gp_kthreads(void) jw = j - READ_ONCE(rcu_state.gp_wake_time); pr_info("%s: wait state: %s(%d) ->state: %#lx delta ->gp_activity %lu ->gp_req_activity %lu ->gp_wake_time %lu ->gp_wake_seq %ld ->gp_seq %ld ->gp_seq_needed %ld ->gp_flags %#x\n", rcu_state.name, gp_state_getname(rcu_state.gp_state), - rcu_state.gp_state, - rcu_state.gp_kthread ? rcu_state.gp_kthread->state : 0x1ffffL, + rcu_state.gp_state, t ? t->state : 0x1ffffL, ja, jr, jw, (long)READ_ONCE(rcu_state.gp_wake_seq), (long)READ_ONCE(rcu_state.gp_seq), (long)READ_ONCE(rcu_get_root()->gp_seq_needed), @@ -633,7 +633,8 @@ static void rcu_check_gp_start_stall(struct rcu_node *rnp, struct rcu_data *rdp, if (!IS_ENABLED(CONFIG_PROVE_RCU) || rcu_gp_in_progress() || ULONG_CMP_GE(READ_ONCE(rnp_root->gp_seq), - READ_ONCE(rnp_root->gp_seq_needed))) + READ_ONCE(rnp_root->gp_seq_needed)) || + !smp_load_acquire(&rcu_state.gp_kthread)) // Get stable kthread. return; j = jiffies; /* Expensive access, and in common case don't get here. */ if (time_before(j, READ_ONCE(rcu_state.gp_req_activity) + gpssdelay) ||
On Sat, 15 Feb 2020 05:42:08 -0800 "Paul E. McKenney" <paulmck@kernel.org> wrote: > > And does the following V2 look better? > For the issue I brought up, yes. But now I have to ask... > @@ -1252,10 +1253,10 @@ static bool rcu_future_gp_cleanup(struct rcu_node *rnp) > */ > static void rcu_gp_kthread_wake(void) > { > - if ((current == rcu_state.gp_kthread && > - !in_irq() && !in_serving_softirq()) || > - !READ_ONCE(rcu_state.gp_flags) || > - !rcu_state.gp_kthread) > + struct task_struct *t = READ_ONCE(rcu_state.gp_kthread); > + > + if ((current == t && !in_irq() && !in_serving_softirq()) || > + !READ_ONCE(rcu_state.gp_flags) || !t) Why not test !t first? As that is the fastest operation in the if statement, and will shortcut all the other operations if it is true. As I like to micro-optimize ;-), for or (||) statements, I like to add the fastest operations first. To me, that would be: if (!t || READ_ONCE(rcu_state.gp_flags) || (current == t && !in_irq() && !in_serving_softirq())) return; Note, in_irq() reads preempt_count which is not always a fast operation. -- Steve > return; > WRITE_ONCE(rcu_state.gp_wake_time, jiffies); > WRITE_ONCE(rcu_state.gp_wake_seq, READ_ONCE(rcu_state.gp_seq)); > @@ -3554,7 +3555,10 @@ static int __init rcu_spawn_gp_kthread(void) > } > rnp = rcu_get_root(); > raw_spin_lock_irqsave_rcu_node(rnp, flags); > - rcu_state.gp_kthread = t; > + WRITE_ONCE(rcu_state.gp_activity, jiffies); > + WRITE_ONCE(rcu_state.gp_req_activity, jiffies); > + // Reset .gp_activity and .gp_req_activity before setting .gp_kthread. > + smp_store_release(&rcu_state.gp_kthread, t); /* ^^^ */ > raw_spin_unlock_irqrestore_rcu_node(rnp, flags); > wake_up_process(t); > rcu_spawn_nocb_kthreads(); > diff --git a/kernel/rcu/tree_stall.h b/kernel/rcu/tree_stall.h > index 488b71d..16ad7ad 100644 \
On Mon, Feb 17, 2020 at 03:25:17PM -0500, Steven Rostedt wrote: > On Sat, 15 Feb 2020 05:42:08 -0800 > "Paul E. McKenney" <paulmck@kernel.org> wrote: > > > > > And does the following V2 look better? > > > > For the issue I brought up, yes. But now I have to ask... > > > @@ -1252,10 +1253,10 @@ static bool rcu_future_gp_cleanup(struct rcu_node *rnp) > > */ > > static void rcu_gp_kthread_wake(void) > > { > > - if ((current == rcu_state.gp_kthread && > > - !in_irq() && !in_serving_softirq()) || > > - !READ_ONCE(rcu_state.gp_flags) || > > - !rcu_state.gp_kthread) > > + struct task_struct *t = READ_ONCE(rcu_state.gp_kthread); > > + > > + if ((current == t && !in_irq() && !in_serving_softirq()) || > > + !READ_ONCE(rcu_state.gp_flags) || !t) > > Why not test !t first? As that is the fastest operation in the if > statement, and will shortcut all the other operations if it is true. > > As I like to micro-optimize ;-), for or (||) statements, I like to add > the fastest operations first. To me, that would be: > > if (!t || READ_ONCE(rcu_state.gp_flags) || > (current == t && !in_irq() && !in_serving_softirq())) > return; > > Note, in_irq() reads preempt_count which is not always a fast operation. And what is a day without micro-optimization of a slowpath? :-) OK, let's see... Grace-period kthread wakeups are normally mediated by rcu_start_this_gp(), which uses a funnel lock to consolidate concurrent requests to start a grace period. If a grace period is already in progress, it refrains from doing a wakeup because that means that the grace-period kthread will check for another grace period being needed at the end of the current grace period. Exceptions include: o The wakeup reporting the last quiescent state of the current grace period. o Emergency situations such as callback overloads and RCU CPU stalls. So on a busy system that is not overloaded, the common case is that rcu_gp_kthread_wake() is invoked only once per grace period because there is no emergency and there is a grace period in progress. If this system has short idle periods and a fair number of quiescent states, a reasonable amount of idle time, then the last quiescent state will not normally be detected by the grace-period kthread. But workloads can of course vary. The "!t" holds only during early boot. So we could put a likely() around the "t". But more to the point, at runtime, "!t" would always be false, so it really should be last in the list of "||" clauses. This isn't enough of a fastpath for a static branch to make sense. The "!READ_ONCE(rcu_state.gp_flags)" will normally hold, though it is false often enough to pay for itself. Or has been in the past, anyway. I suspect that access to the global variable rcu_state.gp_flags is not always fast either. So I am having difficulty talking myself into modifying this one given the frequency of operations. Thanx, Paul
On Mon, 17 Feb 2020 14:03:56 -0800 "Paul E. McKenney" <paulmck@kernel.org> wrote: > And what is a day without micro-optimization of a slowpath? :-) A day you have off, but still find yourself working ;-) > > OK, let's see... > > Grace-period kthread wakeups are normally mediated by rcu_start_this_gp(), > which uses a funnel lock to consolidate concurrent requests to start > a grace period. If a grace period is already in progress, it refrains > from doing a wakeup because that means that the grace-period kthread > will check for another grace period being needed at the end of the > current grace period. > > Exceptions include: > > o The wakeup reporting the last quiescent state of the current > grace period. > > o Emergency situations such as callback overloads and RCU CPU stalls. > > So on a busy system that is not overloaded, the common case is that > rcu_gp_kthread_wake() is invoked only once per grace period because there > is no emergency and there is a grace period in progress. If this system > has short idle periods and a fair number of quiescent states, a reasonable > amount of idle time, then the last quiescent state will not normally be > detected by the grace-period kthread. But workloads can of course vary. > > The "!t" holds only during early boot. So we could put a likely() around > the "t". But more to the point, at runtime, "!t" would always be false, > so it really should be last in the list of "||" clauses. This isn't > enough of a fastpath for a static branch to make sense. Hey! Does that mean we can add a static branch for that check? struct static_key rcu_booting = STATIC_KEY_INIT_TRUE; [...] if (READ_ONCE(rcu_state.gp_flags) || (current == t && !in_irq() && !in_serving_softirq()) return; if (static_branch_unlikely(&rcu_booting) && !t) return; At end of boot: static_key_disable(&rcu_booting); That way we can really micro-optimize the slow path, and it basically becomes a nop! -- Steve > > The "!READ_ONCE(rcu_state.gp_flags)" will normally hold, though it is > false often enough to pay for itself. Or has been in the past, anyway. > I suspect that access to the global variable rcu_state.gp_flags is not > always fast either. > > So I am having difficulty talking myself into modifying this one given > the frequency of operations. > > Thanx, Paul
On Mon, Feb 17, 2020 at 05:21:31PM -0500, Steven Rostedt wrote: > On Mon, 17 Feb 2020 14:03:56 -0800 > "Paul E. McKenney" <paulmck@kernel.org> wrote: > > > And what is a day without micro-optimization of a slowpath? :-) > > A day you have off, but still find yourself working ;-) > > > > > OK, let's see... > > > > Grace-period kthread wakeups are normally mediated by rcu_start_this_gp(), > > which uses a funnel lock to consolidate concurrent requests to start > > a grace period. If a grace period is already in progress, it refrains > > from doing a wakeup because that means that the grace-period kthread > > will check for another grace period being needed at the end of the > > current grace period. > > > > Exceptions include: > > > > o The wakeup reporting the last quiescent state of the current > > grace period. > > > > o Emergency situations such as callback overloads and RCU CPU stalls. > > > > So on a busy system that is not overloaded, the common case is that > > rcu_gp_kthread_wake() is invoked only once per grace period because there > > is no emergency and there is a grace period in progress. If this system > > has short idle periods and a fair number of quiescent states, a reasonable > > amount of idle time, then the last quiescent state will not normally be > > detected by the grace-period kthread. But workloads can of course vary. > > > > The "!t" holds only during early boot. So we could put a likely() around > > the "t". But more to the point, at runtime, "!t" would always be false, > > so it really should be last in the list of "||" clauses. This isn't > > enough of a fastpath for a static branch to make sense. > > Hey! Does that mean we can add a static branch for that check? > > > struct static_key rcu_booting = STATIC_KEY_INIT_TRUE; > > [...] > > if (READ_ONCE(rcu_state.gp_flags) || > (current == t && !in_irq() && !in_serving_softirq()) > return; > > if (static_branch_unlikely(&rcu_booting) && !t) > return; > > At end of boot: > > static_key_disable(&rcu_booting); > > That way we can really micro-optimize the slow path, and it basically > becomes a nop! ;-) ;-) ;-) There might be some place where static branches would be of use in RCU, but unfortunately none that I can think of on the read side. Though I am once again making progress on Lai Jiangshan's patchset, which might one day result in inlining of __rcu_read_lock() and __rcu_read_unlock() in PREEMPT=y kernels. Thanx, Paul > -- Steve > > > > > The "!READ_ONCE(rcu_state.gp_flags)" will normally hold, though it is > > false often enough to pay for itself. Or has been in the past, anyway. > > I suspect that access to the global variable rcu_state.gp_flags is not > > always fast either. > > > > So I am having difficulty talking myself into modifying this one given > > the frequency of operations. > > > > Thanx, Paul >
diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 62383ce..5ee5657 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -1202,7 +1202,7 @@ static bool rcu_start_this_gp(struct rcu_node *rnp_start, struct rcu_data *rdp, trace_rcu_this_gp(rnp, rdp, gp_seq_req, TPS("Startedroot")); WRITE_ONCE(rcu_state.gp_flags, rcu_state.gp_flags | RCU_GP_FLAG_INIT); WRITE_ONCE(rcu_state.gp_req_activity, jiffies); - if (!rcu_state.gp_kthread) { + if (!READ_ONCE(rcu_state.gp_kthread)) { trace_rcu_this_gp(rnp, rdp, gp_seq_req, TPS("NoGPkthread")); goto unlock_out; } @@ -1252,10 +1252,10 @@ static bool rcu_future_gp_cleanup(struct rcu_node *rnp) */ static void rcu_gp_kthread_wake(void) { - if ((current == rcu_state.gp_kthread && + if ((current == READ_ONCE(rcu_state.gp_kthread) && !in_irq() && !in_serving_softirq()) || !READ_ONCE(rcu_state.gp_flags) || - !rcu_state.gp_kthread) + !READ_ONCE(rcu_state.gp_kthread)) return; WRITE_ONCE(rcu_state.gp_wake_time, jiffies); WRITE_ONCE(rcu_state.gp_wake_seq, READ_ONCE(rcu_state.gp_seq)); @@ -3554,7 +3554,10 @@ static int __init rcu_spawn_gp_kthread(void) } rnp = rcu_get_root(); raw_spin_lock_irqsave_rcu_node(rnp, flags); - rcu_state.gp_kthread = t; + WRITE_ONCE(rcu_state.gp_activity, jiffies); + WRITE_ONCE(rcu_state.gp_req_activity, jiffies); + // Reset .gp_activity and .gp_req_activity before setting .gp_kthread. + smp_store_release(&rcu_state.gp_kthread, t); /* ^^^ */ raw_spin_unlock_irqrestore_rcu_node(rnp, flags); wake_up_process(t); rcu_spawn_nocb_kthreads(); diff --git a/kernel/rcu/tree_stall.h b/kernel/rcu/tree_stall.h index 56df88e..4c216f7 100644 --- a/kernel/rcu/tree_stall.h +++ b/kernel/rcu/tree_stall.h @@ -578,6 +578,7 @@ void show_rcu_gp_kthreads(void) unsigned long jw; struct rcu_data *rdp; struct rcu_node *rnp; + struct task_struct *t = READ_ONCE(rcu_state.gp_kthread); j = jiffies; ja = j - READ_ONCE(rcu_state.gp_activity); @@ -585,8 +586,7 @@ void show_rcu_gp_kthreads(void) jw = j - READ_ONCE(rcu_state.gp_wake_time); pr_info("%s: wait state: %s(%d) ->state: %#lx delta ->gp_activity %lu ->gp_req_activity %lu ->gp_wake_time %lu ->gp_wake_seq %ld ->gp_seq %ld ->gp_seq_needed %ld ->gp_flags %#x\n", rcu_state.name, gp_state_getname(rcu_state.gp_state), - rcu_state.gp_state, - rcu_state.gp_kthread ? rcu_state.gp_kthread->state : 0x1ffffL, + rcu_state.gp_state, t ? t->state : 0x1ffffL, ja, jr, jw, (long)READ_ONCE(rcu_state.gp_wake_seq), (long)READ_ONCE(rcu_state.gp_seq), (long)READ_ONCE(rcu_get_root()->gp_seq_needed), @@ -633,7 +633,8 @@ static void rcu_check_gp_start_stall(struct rcu_node *rnp, struct rcu_data *rdp, if (!IS_ENABLED(CONFIG_PROVE_RCU) || rcu_gp_in_progress() || ULONG_CMP_GE(READ_ONCE(rnp_root->gp_seq), - READ_ONCE(rnp_root->gp_seq_needed))) + READ_ONCE(rnp_root->gp_seq_needed)) || + !smp_load_acquire(&rcu_state.gp_kthread)) return; j = jiffies; /* Expensive access, and in common case don't get here. */ if (time_before(j, READ_ONCE(rcu_state.gp_req_activity) + gpssdelay) || @@ -645,7 +646,7 @@ static void rcu_check_gp_start_stall(struct rcu_node *rnp, struct rcu_data *rdp, j = jiffies; if (rcu_gp_in_progress() || ULONG_CMP_GE(READ_ONCE(rnp_root->gp_seq), - READ_ONCE(rnp_root->gp_seq_needed)) || + READ_ONCE(rnp_root->gp_seq_needed)) || time_before(j, READ_ONCE(rcu_state.gp_req_activity) + gpssdelay) || time_before(j, READ_ONCE(rcu_state.gp_activity) + gpssdelay) || atomic_read(&warned)) { @@ -659,7 +660,7 @@ static void rcu_check_gp_start_stall(struct rcu_node *rnp, struct rcu_data *rdp, j = jiffies; if (rcu_gp_in_progress() || ULONG_CMP_GE(READ_ONCE(rnp_root->gp_seq), - READ_ONCE(rnp_root->gp_seq_needed)) || + READ_ONCE(rnp_root->gp_seq_needed)) || time_before(j, READ_ONCE(rcu_state.gp_req_activity) + gpssdelay) || time_before(j, READ_ONCE(rcu_state.gp_activity) + gpssdelay) || atomic_xchg(&warned, 1)) {