3   atomic_t dynticks;
   4   bool rcu_need_heavy_qs;
   5   unsigned long rcu_qs_ctr;
+  6   bool rcu_urgent_qs;
 </pre>
 
 <p>The <tt>->dynticks_nesting</tt> field counts the
 This flag is checked by RCU's context-switch and <tt>cond_resched()</tt>
 code, which provide a momentary idle sojourn in response.
 
-</p><p>Finally the <tt>->rcu_qs_ctr</tt> field is used to record
+</p><p>The <tt>->rcu_qs_ctr</tt> field is used to record
 quiescent states from <tt>cond_resched()</tt>.
 Because <tt>cond_resched()</tt> can execute quite frequently, this
 must be quite lightweight, as in a non-atomic increment of this
 per-CPU field.
 
+</p><p>Finally, the <tt>->rcu_urgent_qs</tt> field is used to record
+the fact that the RCU core code would really like to see a quiescent
+state from the corresponding CPU, with the various other fields indicating
+just how badly RCU wants this quiescent state.
+This flag is checked by RCU's context-switch and <tt>cond_resched()</tt>
+code, which, if nothing else, non-atomically increment <tt>->rcu_qs_ctr</tt>
+in response.
+
 <table>
 <tr><th> </th></tr>
 <tr><th align="left">Quick Quiz:</th></tr>
 
        trace_rcu_utilization(TPS("Start context switch"));
        rcu_sched_qs();
        rcu_preempt_note_context_switch();
+       /* Load rcu_urgent_qs before other flags. */
+       if (!smp_load_acquire(this_cpu_ptr(&rcu_dynticks.rcu_urgent_qs)))
+               goto out;
+       this_cpu_write(rcu_dynticks.rcu_urgent_qs, false);
        if (unlikely(raw_cpu_read(rcu_dynticks.rcu_need_heavy_qs)))
                rcu_momentary_dyntick_idle();
+       this_cpu_inc(rcu_dynticks.rcu_qs_ctr);
+out:
        trace_rcu_utilization(TPS("End context switch"));
        barrier(); /* Avoid RCU read-side critical sections leaking up. */
 }
 {
        unsigned long flags;
 
+       if (!raw_cpu_read(rcu_dynticks.rcu_urgent_qs))
+               return;
+       preempt_disable();
+       /* Load rcu_urgent_qs before other flags. */
+       if (!smp_load_acquire(this_cpu_ptr(&rcu_dynticks.rcu_urgent_qs))) {
+               preempt_enable();
+               return;
+       }
+       this_cpu_write(rcu_dynticks.rcu_urgent_qs, false);
        barrier(); /* Avoid RCU read-side critical sections leaking down. */
        if (unlikely(raw_cpu_read(rcu_dynticks.rcu_need_heavy_qs))) {
                local_irq_save(flags);
                rcu_momentary_dyntick_idle();
                local_irq_restore(flags);
        }
-       if (unlikely(raw_cpu_read(rcu_sched_data.cpu_no_qs.b.exp))) {
-               /*
-                * Yes, we just checked a per-CPU variable with preemption
-                * enabled, so we might be migrated to some other CPU at
-                * this point.  That is OK because in that case, the
-                * migration will supply the needed quiescent state.
-                * We might end up needlessly disabling preemption and
-                * invoking rcu_sched_qs() on the destination CPU, but
-                * the probability and cost are both quite low, so this
-                * should not be a problem in practice.
-                */
-               preempt_disable();
+       if (unlikely(raw_cpu_read(rcu_sched_data.cpu_no_qs.b.exp)))
                rcu_sched_qs();
-               preempt_enable();
-       }
        this_cpu_inc(rcu_dynticks.rcu_qs_ctr);
        barrier(); /* Avoid RCU read-side critical sections leaking up. */
+       preempt_enable();
 }
 EXPORT_SYMBOL_GPL(rcu_all_qs);
 
 {
        unsigned long jtsq;
        bool *rnhqp;
+       bool *ruqp;
        unsigned long rjtsc;
        struct rcu_node *rnp;
 
         * might not be the case for nohz_full CPUs looping in the kernel.
         */
        rnp = rdp->mynode;
+       ruqp = per_cpu_ptr(&rcu_dynticks.rcu_urgent_qs, rdp->cpu);
        if (time_after(jiffies, rdp->rsp->gp_start + jtsq) &&
            READ_ONCE(rdp->rcu_qs_ctr_snap) != per_cpu(rcu_dynticks.rcu_qs_ctr, rdp->cpu) &&
            READ_ONCE(rdp->gpnum) == rnp->gpnum && !rdp->gpwrap) {
                trace_rcu_fqs(rdp->rsp->name, rdp->gpnum, rdp->cpu, TPS("rqc"));
                return 1;
+       } else {
+               /* Load rcu_qs_ctr before store to rcu_urgent_qs. */
+               smp_store_release(ruqp, true);
        }
 
        /* Check for the CPU being offline. */
            (time_after(jiffies, rdp->rsp->gp_start + jtsq) ||
             time_after(jiffies, rdp->rsp->jiffies_resched))) {
                WRITE_ONCE(*rnhqp, true);
+               /* Store rcu_need_heavy_qs before rcu_urgent_qs. */
+               smp_store_release(ruqp, true);
                rdp->rsp->jiffies_resched += 5; /* Re-enable beating. */
        }
 
 
                                    /* Process level is worth LLONG_MAX/2. */
        int dynticks_nmi_nesting;   /* Track NMI nesting level. */
        atomic_t dynticks;          /* Even value for idle, else odd. */
-       bool rcu_need_heavy_qs;      /* GP old, need heavy quiescent state. */
+       bool rcu_need_heavy_qs;     /* GP old, need heavy quiescent state. */
        unsigned long rcu_qs_ctr;   /* Light universal quiescent state ctr. */
+       bool rcu_urgent_qs;         /* GP old need light quiescent state. */
 #ifdef CONFIG_NO_HZ_FULL_SYSIDLE
        long long dynticks_idle_nesting;
                                    /* irq/process nesting level from idle. */
 
                        trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu,
                                            TPS("WakeEmpty"));
                } else {
-                       rdp->nocb_defer_wakeup = RCU_NOGP_WAKE;
+                       WRITE_ONCE(rdp->nocb_defer_wakeup, RCU_NOGP_WAKE);
+                       /* Store ->nocb_defer_wakeup before ->rcu_urgent_qs. */
+                       smp_store_release(this_cpu_ptr(&rcu_dynticks.rcu_urgent_qs), true);
                        trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu,
                                            TPS("WakeEmptyIsDeferred"));
                }
                        trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu,
                                            TPS("WakeOvf"));
                } else {
-                       rdp->nocb_defer_wakeup = RCU_NOGP_WAKE_FORCE;
+                       WRITE_ONCE(rdp->nocb_defer_wakeup, RCU_NOGP_WAKE_FORCE);
+                       /* Store ->nocb_defer_wakeup before ->rcu_urgent_qs. */
+                       smp_store_release(this_cpu_ptr(&rcu_dynticks.rcu_urgent_qs), true);
                        trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu,
                                            TPS("WakeOvfIsDeferred"));
                }