]> Git Repo - J-linux.git/commitdiff
Merge branches 'context_tracking.15.08.24a', 'csd.lock.15.08.24a', 'nocb.09.09.24a...
authorNeeraj Upadhyay <[email protected]>
Sun, 8 Sep 2024 18:39:47 +0000 (00:09 +0530)
committerNeeraj Upadhyay <[email protected]>
Sun, 8 Sep 2024 18:39:47 +0000 (00:09 +0530)
12 files changed:
1  2  3  4  5  6  7  8 
Documentation/admin-guide/kernel-parameters.txt
include/linux/rcupdate.h
kernel/rcu/rcu.h
kernel/rcu/rcutorture.c
kernel/rcu/tasks.h
kernel/rcu/tree.c
kernel/rcu/tree.h
kernel/rcu/tree_exp.h
kernel/rcu/tree_nocb.h
kernel/rcu/tree_plugin.h
kernel/rcu/tree_stall.h
kernel/sched/core.c

index f1384c7b59c9282fc6fb40569a92f6c13861bbb9,f1384c7b59c9282fc6fb40569a92f6c13861bbb9,db1be767c91a4cac0ed20d154c67a34150617418,d56356c13184e397df48a979e69c90ce2aad1f7c,f1384c7b59c9282fc6fb40569a92f6c13861bbb9,a6107b74507609dddb12042eb21fff2c2843fb55,f1384c7b59c9282fc6fb40569a92f6c13861bbb9,f1384c7b59c9282fc6fb40569a92f6c13861bbb9..d30b81e693f9cc02c8e596676f501778466eced8
                                Set maximum number of finished RCU callbacks to
                                process in one batch.
        
+++ ++++        rcutree.csd_lock_suppress_rcu_stall=    [KNL]
+++ ++++                        Do only a one-line RCU CPU stall warning when
+++ ++++                        there is an ongoing too-long CSD-lock wait.
+++ ++++
                rcutree.do_rcu_barrier= [KNL]
                                Request a call to rcu_barrier().  This is
                                throttled so that userspace tests can safely
                                Time to wait (s) after boot before inducing stall.
        
                rcutorture.stall_cpu_irqsoff= [KNL]
-- -----                        Disable interrupts while stalling if set.
++ +++++                        Disable interrupts while stalling if set, but only
++ +++++                        on the first stall in the set.
++ +++++
++ +++++        rcutorture.stall_cpu_repeat= [KNL]
++ +++++                        Number of times to repeat the stall sequence,
++ +++++                        so that rcutorture.stall_cpu_repeat=3 will result
++ +++++                        in four stall sequences.
        
                rcutorture.stall_gp_kthread= [KNL]
                                Duration (s) of forced sleep within RCU
                                of zero will disable batching.  Batching is
                                always disabled for synchronize_rcu_tasks().
        
----- --        rcupdate.rcu_tasks_rude_lazy_ms= [KNL]
----- --                        Set timeout in milliseconds RCU Tasks
----- --                        Rude asynchronous callback batching for
----- --                        call_rcu_tasks_rude().  A negative value
----- --                        will take the default.  A value of zero will
----- --                        disable batching.  Batching is always disabled
----- --                        for synchronize_rcu_tasks_rude().
----- --
                rcupdate.rcu_tasks_trace_lazy_ms= [KNL]
                                Set timeout in milliseconds RCU Tasks
                                Trace asynchronous callback batching for
diff --combined include/linux/rcupdate.h
index 13f6f00aecf9c975aff7ca485fb08bb36676dd86,d48d3c2373052b9048cd7a1704c3edaf5d53fb23,13f6f00aecf9c975aff7ca485fb08bb36676dd86,13f6f00aecf9c975aff7ca485fb08bb36676dd86,8d56db70d41739b539f6bef27d7ec00b8f5b656d,17463e95b6efff620cafba22c6b31d55246fc776,13f6f00aecf9c975aff7ca485fb08bb36676dd86,13f6f00aecf9c975aff7ca485fb08bb36676dd86..58d84c59f3ddae9bc242c16aa7e8ee6678d56ecd
        #define ULONG_CMP_GE(a, b)      (ULONG_MAX / 2 >= (a) - (b))
        #define ULONG_CMP_LT(a, b)      (ULONG_MAX / 2 < (a) - (b))
        
++++ +++#define RCU_SEQ_CTR_SHIFT    2
++++ +++#define RCU_SEQ_STATE_MASK   ((1 << RCU_SEQ_CTR_SHIFT) - 1)
++++ +++
        /* Exported common interfaces */
        void call_rcu(struct rcu_head *head, rcu_callback_t func);
        void rcu_barrier_tasks(void);
----- --void rcu_barrier_tasks_rude(void);
        void synchronize_rcu(void);
        
        struct rcu_gp_oldstate;
@@@@@@@@@ -144,11 -144,18 -144,11 -144,11 -147,11 -143,11 -144,11 -144,11 +146,18 @@@@@@@@@ void rcu_init_nohz(void)
        int rcu_nocb_cpu_offload(int cpu);
        int rcu_nocb_cpu_deoffload(int cpu);
        void rcu_nocb_flush_deferred_wakeup(void);
+ ++++++
+ ++++++#define RCU_NOCB_LOCKDEP_WARN(c, s) RCU_LOCKDEP_WARN(c, s)
+ ++++++
        #else /* #ifdef CONFIG_RCU_NOCB_CPU */
+ ++++++
        static inline void rcu_init_nohz(void) { }
        static inline int rcu_nocb_cpu_offload(int cpu) { return -EINVAL; }
        static inline int rcu_nocb_cpu_deoffload(int cpu) { return 0; }
        static inline void rcu_nocb_flush_deferred_wakeup(void) { }
+ ++++++
+ ++++++#define RCU_NOCB_LOCKDEP_WARN(c, s)
+ ++++++
        #endif /* #else #ifdef CONFIG_RCU_NOCB_CPU */
        
        /*
                } while (0)
        void call_rcu_tasks(struct rcu_head *head, rcu_callback_t func);
        void synchronize_rcu_tasks(void);
+++++ ++void rcu_tasks_torture_stats_print(char *tt, char *tf);
        # else
        # define rcu_tasks_classic_qs(t, preempt) do { } while (0)
        # define call_rcu_tasks call_rcu
@@@@@@@@@ -191,6 -198,6 -191,6 -191,6 -194,6 -191,7 -191,6 -191,6 +201,7 @@@@@@@@@ void rcu_tasks_trace_qs_blkd(struct tas
                                rcu_tasks_trace_qs_blkd(t);                             \
                        }                                                               \
                } while (0)
+++++ ++void rcu_tasks_trace_torture_stats_print(char *tt, char *tf);
        # else
        # define rcu_tasks_trace_qs(t) do { } while (0)
        # endif
@@@@@@@@@ -202,8 -209,8 -202,8 -202,8 -205,8 -203,8 -202,8 -202,8 +213,8 @@@@@@@@@ do {                                                                 
        } while (0)
        
        # ifdef CONFIG_TASKS_RUDE_RCU
----- --void call_rcu_tasks_rude(struct rcu_head *head, rcu_callback_t func);
        void synchronize_rcu_tasks_rude(void);
+++++ ++void rcu_tasks_rude_torture_stats_print(char *tt, char *tf);
        # endif
        
        #define rcu_note_voluntary_context_switch(t) rcu_tasks_qs(t, false)
diff --combined kernel/rcu/rcu.h
index 5564402af4cbd46767b5934ba56010e5ebd04e03,38238e595a61a45fd263df234e199c722149968b,38238e595a61a45fd263df234e199c722149968b,38238e595a61a45fd263df234e199c722149968b,2bfed9855d67b4937f0bde03e8ab3347da8e7bce,caaed27e476b2b919a25ed0bf6bd7b87e260940e,38238e595a61a45fd263df234e199c722149968b,38238e595a61a45fd263df234e199c722149968b..feb3ac1dc5d59030db1131677dda08fa9caa41a7
         *                                      grace-period sequence number.
         */
        
---- ---#define RCU_SEQ_CTR_SHIFT       2
---- ---#define RCU_SEQ_STATE_MASK      ((1 << RCU_SEQ_CTR_SHIFT) - 1)
---- ---
        /* Low-order bit definition for polled grace-period APIs. */
        #define RCU_GET_STATE_COMPLETED 0x1
        
@@@@@@@@@ -255,6 -255,6 -255,6 -255,6 -252,6 -255,11 -255,6 -255,6 +252,11 @@@@@@@@@ static inline void debug_rcu_head_callb
                        kmem_dump_obj(rhp);
        }
        
+++++ ++static inline bool rcu_barrier_cb_is_done(struct rcu_head *rhp)
+++++ ++{
+++++ ++        return rhp->next == rhp;
+++++ ++}
+++++ ++
        extern int rcu_cpu_stall_suppress_at_boot;
        
        static inline bool rcu_stall_is_suppressed_at_boot(void)
@@@@@@@@@ -606,7 -606,7 -606,7 -606,7 -603,7 -611,7 -606,7 -606,7 +608,7 @@@@@@@@@ void srcutorture_get_gp_data(struct src
        #endif
        
        #ifdef CONFIG_TINY_RCU
 -------static inline bool rcu_dynticks_zero_in_eqs(int cpu, int *vp) { return false; }
 +++++++static inline bool rcu_watching_zero_in_eqs(int cpu, int *vp) { return false; }
        static inline unsigned long rcu_get_gp_seq(void) { return 0; }
        static inline unsigned long rcu_exp_batches_completed(void) { return 0; }
        static inline unsigned long
@@@@@@@@@ -619,7 -619,7 -619,7 -619,7 -616,7 -624,7 -619,7 -619,7 +621,7 @@@@@@@@@ static inline void rcu_fwd_progress_che
        static inline void rcu_gp_slow_register(atomic_t *rgssp) { }
        static inline void rcu_gp_slow_unregister(atomic_t *rgssp) { }
        #else /* #ifdef CONFIG_TINY_RCU */
 -------bool rcu_dynticks_zero_in_eqs(int cpu, int *vp);
 +++++++bool rcu_watching_zero_in_eqs(int cpu, int *vp);
        unsigned long rcu_get_gp_seq(void);
        unsigned long rcu_exp_batches_completed(void);
        unsigned long srcu_batches_completed(struct srcu_struct *sp);
diff --combined kernel/rcu/rcutorture.c
index ef757c3e84a27f72bbec67cc36c2773024f44e7c,08bf7c669dd3dbf8088328c1f87d7b25ab80122c,4fd23cae0e9e49f434791f1bb9e30bd23baa72a4,08bf7c669dd3dbf8088328c1f87d7b25ab80122c,08bf7c669dd3dbf8088328c1f87d7b25ab80122c,cd8752b2a960ade9b8faeb3b2385d83e61427112,08bf7c669dd3dbf8088328c1f87d7b25ab80122c,08bf7c669dd3dbf8088328c1f87d7b25ab80122c..bb75dbf5c800cf72b94e6fad4624218ad5a94134
@@@@@@@@@ -115,6 -115,6 -115,7 -115,6 -115,6 -115,6 -115,6 -115,6 +115,7 @@@@@@@@@ torture_param(int, stall_cpu_holdoff, 1
        torture_param(bool, stall_no_softlockup, false, "Avoid softlockup warning during cpu stall.");
        torture_param(int, stall_cpu_irqsoff, 0, "Disable interrupts while stalling.");
        torture_param(int, stall_cpu_block, 0, "Sleep while stalling.");
++ +++++torture_param(int, stall_cpu_repeat, 0, "Number of additional stalls after the first one.");
        torture_param(int, stall_gp_kthread, 0, "Grace-period kthread stall duration (s).");
        torture_param(int, stat_interval, 60, "Number of seconds between stats printk()s");
        torture_param(int, stutter, 5, "Number of seconds to run/halt test");
@@@@@@@@@ -366,8 -366,8 -367,6 -366,8 -366,8 -366,8 -366,8 -366,8 +367,6 @@@@@@@@@ struct rcu_torture_ops 
                bool (*same_gp_state_full)(struct rcu_gp_oldstate *rgosp1, struct rcu_gp_oldstate *rgosp2);
                unsigned long (*get_gp_state)(void);
                void (*get_gp_state_full)(struct rcu_gp_oldstate *rgosp);
-- -----        unsigned long (*get_gp_completed)(void);
-- -----        void (*get_gp_completed_full)(struct rcu_gp_oldstate *rgosp);
                unsigned long (*start_gp_poll)(void);
                void (*start_gp_poll_full)(struct rcu_gp_oldstate *rgosp);
                bool (*poll_gp_state)(unsigned long oldstate);
                bool (*poll_need_2gp)(bool poll, bool poll_full);
                void (*cond_sync)(unsigned long oldstate);
                void (*cond_sync_full)(struct rcu_gp_oldstate *rgosp);
++ +++++        int poll_active;
++ +++++        int poll_active_full;
                call_rcu_func_t call;
                void (*cb_barrier)(void);
                void (*fqs)(void);
@@@@@@@@@ -553,8 -553,8 -554,6 -553,8 -553,8 -553,8 -553,8 -553,8 +554,6 @@@@@@@@@ static struct rcu_torture_ops rcu_ops 
                .get_comp_state_full    = get_completed_synchronize_rcu_full,
                .get_gp_state           = get_state_synchronize_rcu,
                .get_gp_state_full      = get_state_synchronize_rcu_full,
-- -----        .get_gp_completed       = get_completed_synchronize_rcu,
-- -----        .get_gp_completed_full  = get_completed_synchronize_rcu_full,
                .start_gp_poll          = start_poll_synchronize_rcu,
                .start_gp_poll_full     = start_poll_synchronize_rcu_full,
                .poll_gp_state          = poll_state_synchronize_rcu,
                .poll_need_2gp          = rcu_poll_need_2gp,
                .cond_sync              = cond_synchronize_rcu,
                .cond_sync_full         = cond_synchronize_rcu_full,
++ +++++        .poll_active            = NUM_ACTIVE_RCU_POLL_OLDSTATE,
++ +++++        .poll_active_full       = NUM_ACTIVE_RCU_POLL_FULL_OLDSTATE,
                .get_gp_state_exp       = get_state_synchronize_rcu,
                .start_gp_poll_exp      = start_poll_synchronize_rcu_expedited,
                .start_gp_poll_exp_full = start_poll_synchronize_rcu_expedited_full,
@@@@@@@@@ -740,9 -740,9 -741,12 -740,9 -740,9 -740,9 -740,9 -740,9 +741,12 @@@@@@@@@ static struct rcu_torture_ops srcu_ops 
                .deferred_free  = srcu_torture_deferred_free,
                .sync           = srcu_torture_synchronize,
                .exp_sync       = srcu_torture_synchronize_expedited,
++ +++++        .same_gp_state  = same_state_synchronize_srcu,
++ +++++        .get_comp_state = get_completed_synchronize_srcu,
                .get_gp_state   = srcu_torture_get_gp_state,
                .start_gp_poll  = srcu_torture_start_gp_poll,
                .poll_gp_state  = srcu_torture_poll_gp_state,
++ +++++        .poll_active    = NUM_ACTIVE_SRCU_POLL_OLDSTATE,
                .call           = srcu_torture_call,
                .cb_barrier     = srcu_torture_barrier,
                .stats          = srcu_torture_stats,
@@@@@@@@@ -780,9 -780,9 -784,12 -780,9 -780,9 -780,9 -780,9 -780,9 +784,12 @@@@@@@@@ static struct rcu_torture_ops srcud_op
                .deferred_free  = srcu_torture_deferred_free,
                .sync           = srcu_torture_synchronize,
                .exp_sync       = srcu_torture_synchronize_expedited,
++ +++++        .same_gp_state  = same_state_synchronize_srcu,
++ +++++        .get_comp_state = get_completed_synchronize_srcu,
                .get_gp_state   = srcu_torture_get_gp_state,
                .start_gp_poll  = srcu_torture_start_gp_poll,
                .poll_gp_state  = srcu_torture_poll_gp_state,
++ +++++        .poll_active    = NUM_ACTIVE_SRCU_POLL_OLDSTATE,
                .call           = srcu_torture_call,
                .cb_barrier     = srcu_torture_barrier,
                .stats          = srcu_torture_stats,
@@@@@@@@@ -915,11 -915,11 -922,11 -915,11 -915,11 -915,6 -915,11 -915,11 +922,6 @@@@@@@@@ static struct rcu_torture_ops tasks_op
         * Definitions for rude RCU-tasks torture testing.
         */
        
----- --static void rcu_tasks_rude_torture_deferred_free(struct rcu_torture *p)
----- --{
----- --        call_rcu_tasks_rude(&p->rtort_rcu, rcu_torture_cb);
----- --}
----- --
        static struct rcu_torture_ops tasks_rude_ops = {
                .ttype          = RCU_TASKS_RUDE_FLAVOR,
                .init           = rcu_sync_torture_init,
                .read_delay     = rcu_read_delay,  /* just reuse rcu's version. */
                .readunlock     = rcu_torture_read_unlock_trivial,
                .get_gp_seq     = rcu_no_completed,
----- --        .deferred_free  = rcu_tasks_rude_torture_deferred_free,
                .sync           = synchronize_rcu_tasks_rude,
                .exp_sync       = synchronize_rcu_tasks_rude,
----- --        .call           = call_rcu_tasks_rude,
----- --        .cb_barrier     = rcu_barrier_tasks_rude,
                .gp_kthread_dbg = show_rcu_tasks_rude_gp_kthread,
                .get_gp_data    = rcu_tasks_rude_get_gp_data,
                .cbflood_max    = 50000,
@@@@@@@@@ -1318,6 -1318,6 -1325,7 -1318,6 -1318,6 -1310,6 -1318,6 -1318,6 +1317,7 @@@@@@@@@ static void rcu_torture_write_types(voi
                } else if (gp_sync && !cur_ops->sync) {
                        pr_alert("%s: gp_sync without primitives.\n", __func__);
                }
++ +++++        pr_alert("%s: Testing %d update types.\n", __func__, nsynctypes);
        }
        
        /*
@@@@@@@@@ -1374,17 -1374,17 -1382,20 -1374,17 -1374,17 -1366,17 -1374,17 -1374,17 +1374,20 @@@@@@@@@ rcu_torture_writer(void *arg
                int i;
                int idx;
                int oldnice = task_nice(current);
-- -----        struct rcu_gp_oldstate rgo[NUM_ACTIVE_RCU_POLL_FULL_OLDSTATE];
++ +++++        struct rcu_gp_oldstate *rgo = NULL;
++ +++++        int rgo_size = 0;
                struct rcu_torture *rp;
                struct rcu_torture *old_rp;
                static DEFINE_TORTURE_RANDOM(rand);
                unsigned long stallsdone = jiffies;
                bool stutter_waited;
-- -----        unsigned long ulo[NUM_ACTIVE_RCU_POLL_OLDSTATE];
++ +++++        unsigned long *ulo = NULL;
++ +++++        int ulo_size = 0;
        
                // If a new stall test is added, this must be adjusted.
                if (stall_cpu_holdoff + stall_gp_kthread + stall_cpu)
-- -----                stallsdone += (stall_cpu_holdoff + stall_gp_kthread + stall_cpu + 60) * HZ;
++ +++++                stallsdone += (stall_cpu_holdoff + stall_gp_kthread + stall_cpu + 60) *
++ +++++                              HZ * (stall_cpu_repeat + 1);
                VERBOSE_TOROUT_STRING("rcu_torture_writer task started");
                if (!can_expedite)
                        pr_alert("%s" TORTURE_FLAG
                        torture_kthread_stopping("rcu_torture_writer");
                        return 0;
                }
++ +++++        if (cur_ops->poll_active > 0) {
++ +++++                ulo = kzalloc(cur_ops->poll_active * sizeof(ulo[0]), GFP_KERNEL);
++ +++++                if (!WARN_ON(!ulo))
++ +++++                        ulo_size = cur_ops->poll_active;
++ +++++        }
++ +++++        if (cur_ops->poll_active_full > 0) {
++ +++++                rgo = kzalloc(cur_ops->poll_active_full * sizeof(rgo[0]), GFP_KERNEL);
++ +++++                if (!WARN_ON(!rgo))
++ +++++                        rgo_size = cur_ops->poll_active_full;
++ +++++        }
        
                do {
                        rcu_torture_writer_state = RTWS_FIXED_DELAY;
                                                  rcu_torture_writer_state_getname(),
                                                  rcu_torture_writer_state,
                                                  cookie, cur_ops->get_gp_state());
-- -----                                if (cur_ops->get_gp_completed) {
-- -----                                        cookie = cur_ops->get_gp_completed();
++ +++++                                if (cur_ops->get_comp_state) {
++ +++++                                        cookie = cur_ops->get_comp_state();
                                                WARN_ON_ONCE(!cur_ops->poll_gp_state(cookie));
                                        }
                                        cur_ops->readunlock(idx);
                                                  rcu_torture_writer_state_getname(),
                                                  rcu_torture_writer_state,
                                                  cpumask_pr_args(cpu_online_mask));
-- -----                                if (cur_ops->get_gp_completed_full) {
-- -----                                        cur_ops->get_gp_completed_full(&cookie_full);
++ +++++                                if (cur_ops->get_comp_state_full) {
++ +++++                                        cur_ops->get_comp_state_full(&cookie_full);
                                                WARN_ON_ONCE(!cur_ops->poll_gp_state_full(&cookie_full));
                                        }
                                        cur_ops->readunlock(idx);
                                        break;
                                case RTWS_POLL_GET:
                                        rcu_torture_writer_state = RTWS_POLL_GET;
-- -----                                for (i = 0; i < ARRAY_SIZE(ulo); i++)
++ +++++                                for (i = 0; i < ulo_size; i++)
                                                ulo[i] = cur_ops->get_comp_state();
                                        gp_snap = cur_ops->start_gp_poll();
                                        rcu_torture_writer_state = RTWS_POLL_WAIT;
                                        while (!cur_ops->poll_gp_state(gp_snap)) {
                                                gp_snap1 = cur_ops->get_gp_state();
-- -----                                        for (i = 0; i < ARRAY_SIZE(ulo); i++)
++ +++++                                        for (i = 0; i < ulo_size; i++)
                                                        if (cur_ops->poll_gp_state(ulo[i]) ||
                                                            cur_ops->same_gp_state(ulo[i], gp_snap1)) {
                                                                ulo[i] = gp_snap1;
                                                                break;
                                                        }
-- -----                                        WARN_ON_ONCE(i >= ARRAY_SIZE(ulo));
++ +++++                                        WARN_ON_ONCE(ulo_size > 0 && i >= ulo_size);
                                                torture_hrtimeout_jiffies(torture_random(&rand) % 16,
                                                                          &rand);
                                        }
                                        break;
                                case RTWS_POLL_GET_FULL:
                                        rcu_torture_writer_state = RTWS_POLL_GET_FULL;
-- -----                                for (i = 0; i < ARRAY_SIZE(rgo); i++)
++ +++++                                for (i = 0; i < rgo_size; i++)
                                                cur_ops->get_comp_state_full(&rgo[i]);
                                        cur_ops->start_gp_poll_full(&gp_snap_full);
                                        rcu_torture_writer_state = RTWS_POLL_WAIT_FULL;
                                        while (!cur_ops->poll_gp_state_full(&gp_snap_full)) {
                                                cur_ops->get_gp_state_full(&gp_snap1_full);
-- -----                                        for (i = 0; i < ARRAY_SIZE(rgo); i++)
++ +++++                                        for (i = 0; i < rgo_size; i++)
                                                        if (cur_ops->poll_gp_state_full(&rgo[i]) ||
                                                            cur_ops->same_gp_state_full(&rgo[i],
                                                                                        &gp_snap1_full)) {
                                                                rgo[i] = gp_snap1_full;
                                                                break;
                                                        }
-- -----                                        WARN_ON_ONCE(i >= ARRAY_SIZE(rgo));
++ +++++                                        WARN_ON_ONCE(rgo_size > 0 && i >= rgo_size);
                                                torture_hrtimeout_jiffies(torture_random(&rand) % 16,
                                                                          &rand);
                                        }
                        pr_alert("%s" TORTURE_FLAG
                                 " Dynamic grace-period expediting was disabled.\n",
                                 torture_type);
++ +++++        kfree(ulo);
++ +++++        kfree(rgo);
                rcu_torture_writer_state = RTWS_STOPPING;
                torture_kthread_stopping("rcu_torture_writer");
                return 0;
@@@@@@@@@ -2370,7 -2370,7 -2393,7 -2370,7 -2370,7 -2362,7 -2370,7 -2370,7 +2385,7 @@@@@@@@@ rcu_torture_print_module_parms(struct r
                         "test_boost=%d/%d test_boost_interval=%d "
                         "test_boost_duration=%d shutdown_secs=%d "
                         "stall_cpu=%d stall_cpu_holdoff=%d stall_cpu_irqsoff=%d "
-- -----                 "stall_cpu_block=%d "
++ +++++                 "stall_cpu_block=%d stall_cpu_repeat=%d "
                         "n_barrier_cbs=%d "
                         "onoff_interval=%d onoff_holdoff=%d "
                         "read_exit_delay=%d read_exit_burst=%d "
                         test_boost, cur_ops->can_boost,
                         test_boost_interval, test_boost_duration, shutdown_secs,
                         stall_cpu, stall_cpu_holdoff, stall_cpu_irqsoff,
-- -----                 stall_cpu_block,
++ +++++                 stall_cpu_block, stall_cpu_repeat,
                         n_barrier_cbs,
                         onoff_interval, onoff_holdoff,
                         read_exit_delay, read_exit_burst,
@@@@@@@@@ -2460,19 -2460,19 -2483,11 -2460,19 -2460,19 -2452,19 -2460,19 -2460,19 +2475,11 @@@@@@@@@ static struct notifier_block rcu_tortur
         * induces a CPU stall for the time specified by stall_cpu.  If a new
         * stall test is added, stallsdone in rcu_torture_writer() must be adjusted.
         */
-- -----static int rcu_torture_stall(void *args)
++ +++++static void rcu_torture_stall_one(int rep, int irqsoff)
        {
                int idx;
-- -----        int ret;
                unsigned long stop_at;
        
-- -----        VERBOSE_TOROUT_STRING("rcu_torture_stall task started");
-- -----        if (rcu_cpu_stall_notifiers) {
-- -----                ret = rcu_stall_chain_notifier_register(&rcu_torture_stall_block);
-- -----                if (ret)
-- -----                        pr_info("%s: rcu_stall_chain_notifier_register() returned %d, %sexpected.\n",
-- -----                                __func__, ret, !IS_ENABLED(CONFIG_RCU_STALL_COMMON) ? "un" : "");
-- -----        }
                if (stall_cpu_holdoff > 0) {
                        VERBOSE_TOROUT_STRING("rcu_torture_stall begin holdoff");
                        schedule_timeout_interruptible(stall_cpu_holdoff * HZ);
                        stop_at = ktime_get_seconds() + stall_cpu;
                        /* RCU CPU stall is expected behavior in following code. */
                        idx = cur_ops->readlock();
-- -----                if (stall_cpu_irqsoff)
++ +++++                if (irqsoff)
                                local_irq_disable();
                        else if (!stall_cpu_block)
                                preempt_disable();
-- -----                pr_alert("%s start on CPU %d.\n",
-- -----                          __func__, raw_smp_processor_id());
++ +++++                pr_alert("%s start stall episode %d on CPU %d.\n",
++ +++++                          __func__, rep + 1, raw_smp_processor_id());
                        while (ULONG_CMP_LT((unsigned long)ktime_get_seconds(), stop_at) &&
                               !kthread_should_stop())
                                if (stall_cpu_block) {
                                } else if (stall_no_softlockup) {
                                        touch_softlockup_watchdog();
                                }
-- -----                if (stall_cpu_irqsoff)
++ +++++                if (irqsoff)
                                local_irq_enable();
                        else if (!stall_cpu_block)
                                preempt_enable();
                        cur_ops->readunlock(idx);
                }
++ +++++}
++ +++++
++ +++++/*
++ +++++ * CPU-stall kthread.  Invokes rcu_torture_stall_one() once, and then as many
++ +++++ * additional times as specified by the stall_cpu_repeat module parameter.
++ +++++ * Note that stall_cpu_irqsoff is ignored on the second and subsequent
++ +++++ * stall.
++ +++++ */
++ +++++static int rcu_torture_stall(void *args)
++ +++++{
++ +++++        int i;
++ +++++        int repeat = stall_cpu_repeat;
++ +++++        int ret;
++ +++++
++ +++++        VERBOSE_TOROUT_STRING("rcu_torture_stall task started");
++ +++++        if (repeat < 0) {
++ +++++                repeat = 0;
++ +++++                WARN_ON_ONCE(IS_BUILTIN(CONFIG_RCU_TORTURE_TEST));
++ +++++        }
++ +++++        if (rcu_cpu_stall_notifiers) {
++ +++++                ret = rcu_stall_chain_notifier_register(&rcu_torture_stall_block);
++ +++++                if (ret)
++ +++++                        pr_info("%s: rcu_stall_chain_notifier_register() returned %d, %sexpected.\n",
++ +++++                                __func__, ret, !IS_ENABLED(CONFIG_RCU_STALL_COMMON) ? "un" : "");
++ +++++        }
++ +++++        for (i = 0; i <= repeat; i++) {
++ +++++                if (kthread_should_stop())
++ +++++                        break;
++ +++++                rcu_torture_stall_one(i, i == 0 ? stall_cpu_irqsoff : 0);
++ +++++        }
                pr_alert("%s end.\n", __func__);
                if (rcu_cpu_stall_notifiers && !ret) {
                        ret = rcu_stall_chain_notifier_unregister(&rcu_torture_stall_block);
@@@@@@@@@ -2680,7 -2680,7 -2725,7 -2680,7 -2680,7 -2672,7 -2680,7 -2680,7 +2717,7 @@@@@@@@@ static unsigned long rcu_torture_fwd_pr
                        rcu_torture_fwd_prog_cond_resched(freed);
                        if (tick_nohz_full_enabled()) {
                                local_irq_save(flags);
 -------                        rcu_momentary_dyntick_idle();
 +++++++                        rcu_momentary_eqs();
                                local_irq_restore(flags);
                        }
                }
@@@@@@@@@ -2830,7 -2830,7 -2875,7 -2830,7 -2830,7 -2822,7 -2830,7 -2830,7 +2867,7 @@@@@@@@@ static void rcu_torture_fwd_prog_cr(str
                        rcu_torture_fwd_prog_cond_resched(n_launders + n_max_cbs);
                        if (tick_nohz_full_enabled()) {
                                local_irq_save(flags);
 -------                        rcu_momentary_dyntick_idle();
 +++++++                        rcu_momentary_eqs();
                                local_irq_restore(flags);
                        }
                }
diff --combined kernel/rcu/tasks.h
index 2484c1a8e051a82025917204b7ef46e99a9c94ac,ba3440a45b6dd49a40b649722396df1958b4adee,ba3440a45b6dd49a40b649722396df1958b4adee,ba3440a45b6dd49a40b649722396df1958b4adee,ba3440a45b6dd49a40b649722396df1958b4adee,36be92efb0daa8fedbb6ba6bf25675101b7b5fb7,ba3440a45b6dd49a40b649722396df1958b4adee,ba3440a45b6dd49a40b649722396df1958b4adee..6333f4ccf024be2cb5f8dfffc82f3ca679161415
@@@@@@@@@ -34,6 -34,6 -34,6 -34,6 -34,6 -34,7 -34,6 -34,6 +34,7 @@@@@@@@@ typedef void (*postgp_func_t)(struct rc
         * @rtp_blkd_tasks: List of tasks blocked as readers.
         * @rtp_exit_list: List of tasks in the latter portion of do_exit().
         * @cpu: CPU number corresponding to this entry.
+++++ ++ * @index: Index of this CPU in rtpcp_array of the rcu_tasks structure.
         * @rtpp: Pointer to the rcu_tasks structure.
         */
        struct rcu_tasks_percpu {
                struct list_head rtp_blkd_tasks;
                struct list_head rtp_exit_list;
                int cpu;
+++++ ++        int index;
                struct rcu_tasks *rtpp;
        };
        
         * @init_fract: Initial backoff sleep interval.
         * @gp_jiffies: Time of last @gp_state transition.
         * @gp_start: Most recent grace-period start in jiffies.
----- -- * @tasks_gp_seq: Number of grace periods completed since boot.
+++++ ++ * @tasks_gp_seq: Number of grace periods completed since boot in upper bits.
         * @n_ipis: Number of IPIs sent to encourage grace periods to end.
         * @n_ipis_fails: Number of IPI-send failures.
         * @kthread_ptr: This flavor's grace-period/callback-invocation kthread.
         * @call_func: This flavor's call_rcu()-equivalent function.
         * @wait_state: Task state for synchronous grace-period waits (default TASK_UNINTERRUPTIBLE).
         * @rtpcpu: This flavor's rcu_tasks_percpu structure.
+++++ ++ * @rtpcp_array: Array of pointers to rcu_tasks_percpu structure of CPUs in cpu_possible_mask.
         * @percpu_enqueue_shift: Shift down CPU ID this much when enqueuing callbacks.
         * @percpu_enqueue_lim: Number of per-CPU callback queues in use for enqueuing.
         * @percpu_dequeue_lim: Number of per-CPU callback queues in use for dequeuing.
         * @barrier_q_count: Number of queues being waited on.
         * @barrier_q_completion: Barrier wait/wakeup mechanism.
         * @barrier_q_seq: Sequence number for barrier operations.
+++++ ++ * @barrier_q_start: Most recent barrier start in jiffies.
         * @name: This flavor's textual name.
         * @kname: This flavor's kthread name.
         */
@@@@@@@@@ -110,6 -110,6 -110,6 -110,6 -110,6 -114,7 -110,6 -110,6 +114,7 @@@@@@@@@ struct rcu_tasks 
                call_rcu_func_t call_func;
                unsigned int wait_state;
                struct rcu_tasks_percpu __percpu *rtpcpu;
+++++ ++        struct rcu_tasks_percpu **rtpcp_array;
                int percpu_enqueue_shift;
                int percpu_enqueue_lim;
                int percpu_dequeue_lim;
                atomic_t barrier_q_count;
                struct completion barrier_q_completion;
                unsigned long barrier_q_seq;
+++++ ++        unsigned long barrier_q_start;
                char *name;
                char *kname;
        };
@@@@@@@@@ -182,6 -182,6 -182,6 -182,6 -182,6 -188,8 -182,6 -182,6 +188,8 @@@@@@@@@ module_param(rcu_task_collapse_lim, int
        static int rcu_task_lazy_lim __read_mostly = 32;
        module_param(rcu_task_lazy_lim, int, 0444);
        
+++++ ++static int rcu_task_cpu_ids;
+++++ ++
        /* RCU tasks grace-period state for debugging. */
        #define RTGS_INIT                0
        #define RTGS_WAIT_WAIT_CBS       1
@@@@@@@@@ -245,6 -245,6 -245,6 -245,6 -245,6 -253,8 -245,6 -245,6 +253,8 @@@@@@@@@ static void cblist_init_generic(struct 
                int cpu;
                int lim;
                int shift;
+++++ ++        int maxcpu;
+++++ ++        int index = 0;
        
                if (rcu_task_enqueue_lim < 0) {
                        rcu_task_enqueue_lim = 1;
                }
                lim = rcu_task_enqueue_lim;
        
----- --        if (lim > nr_cpu_ids)
----- --                lim = nr_cpu_ids;
----- --        shift = ilog2(nr_cpu_ids / lim);
----- --        if (((nr_cpu_ids - 1) >> shift) >= lim)
----- --                shift++;
----- --        WRITE_ONCE(rtp->percpu_enqueue_shift, shift);
----- --        WRITE_ONCE(rtp->percpu_dequeue_lim, lim);
----- --        smp_store_release(&rtp->percpu_enqueue_lim, lim);
+++++ ++        rtp->rtpcp_array = kcalloc(num_possible_cpus(), sizeof(struct rcu_tasks_percpu *), GFP_KERNEL);
+++++ ++        BUG_ON(!rtp->rtpcp_array);
+++++ ++
                for_each_possible_cpu(cpu) {
                        struct rcu_tasks_percpu *rtpcp = per_cpu_ptr(rtp->rtpcpu, cpu);
        
                        INIT_WORK(&rtpcp->rtp_work, rcu_tasks_invoke_cbs_wq);
                        rtpcp->cpu = cpu;
                        rtpcp->rtpp = rtp;
+++++ ++                rtpcp->index = index;
+++++ ++                rtp->rtpcp_array[index] = rtpcp;
+++++ ++                index++;
                        if (!rtpcp->rtp_blkd_tasks.next)
                                INIT_LIST_HEAD(&rtpcp->rtp_blkd_tasks);
                        if (!rtpcp->rtp_exit_list.next)
                                INIT_LIST_HEAD(&rtpcp->rtp_exit_list);
+++++ ++                rtpcp->barrier_q_head.next = &rtpcp->barrier_q_head;
+++++ ++                maxcpu = cpu;
                }
        
----- --        pr_info("%s: Setting shift to %d and lim to %d rcu_task_cb_adjust=%d.\n", rtp->name,
----- --                        data_race(rtp->percpu_enqueue_shift), data_race(rtp->percpu_enqueue_lim), rcu_task_cb_adjust);
+++++ ++        rcu_task_cpu_ids = maxcpu + 1;
+++++ ++        if (lim > rcu_task_cpu_ids)
+++++ ++                lim = rcu_task_cpu_ids;
+++++ ++        shift = ilog2(rcu_task_cpu_ids / lim);
+++++ ++        if (((rcu_task_cpu_ids - 1) >> shift) >= lim)
+++++ ++                shift++;
+++++ ++        WRITE_ONCE(rtp->percpu_enqueue_shift, shift);
+++++ ++        WRITE_ONCE(rtp->percpu_dequeue_lim, lim);
+++++ ++        smp_store_release(&rtp->percpu_enqueue_lim, lim);
+++++ ++
+++++ ++        pr_info("%s: Setting shift to %d and lim to %d rcu_task_cb_adjust=%d rcu_task_cpu_ids=%d.\n",
+++++ ++                        rtp->name, data_race(rtp->percpu_enqueue_shift), data_race(rtp->percpu_enqueue_lim),
+++++ ++                        rcu_task_cb_adjust, rcu_task_cpu_ids);
        }
        
        // Compute wakeup time for lazy callback timer.
@@@@@@@@@ -339,6 -339,6 -339,6 -339,6 -339,6 -360,7 -339,6 -339,6 +360,7 @@@@@@@@@ static void call_rcu_tasks_generic(stru
                rcu_read_lock();
                ideal_cpu = smp_processor_id() >> READ_ONCE(rtp->percpu_enqueue_shift);
                chosen_cpu = cpumask_next(ideal_cpu - 1, cpu_possible_mask);
+++++ ++        WARN_ON_ONCE(chosen_cpu >= rcu_task_cpu_ids);
                rtpcp = per_cpu_ptr(rtp->rtpcpu, chosen_cpu);
                if (!raw_spin_trylock_rcu_node(rtpcp)) { // irqs already disabled.
                        raw_spin_lock_rcu_node(rtpcp); // irqs already disabled.
                                rtpcp->rtp_n_lock_retries = 0;
                        }
                        if (rcu_task_cb_adjust && ++rtpcp->rtp_n_lock_retries > rcu_task_contend_lim &&
----- --                    READ_ONCE(rtp->percpu_enqueue_lim) != nr_cpu_ids)
+++++ ++                    READ_ONCE(rtp->percpu_enqueue_lim) != rcu_task_cpu_ids)
                                needadjust = true;  // Defer adjustment to avoid deadlock.
                }
                // Queuing callbacks before initialization not yet supported.
                raw_spin_unlock_irqrestore_rcu_node(rtpcp, flags);
                if (unlikely(needadjust)) {
                        raw_spin_lock_irqsave(&rtp->cbs_gbl_lock, flags);
----- --                if (rtp->percpu_enqueue_lim != nr_cpu_ids) {
+++++ ++                if (rtp->percpu_enqueue_lim != rcu_task_cpu_ids) {
                                WRITE_ONCE(rtp->percpu_enqueue_shift, 0);
----- --                        WRITE_ONCE(rtp->percpu_dequeue_lim, nr_cpu_ids);
----- --                        smp_store_release(&rtp->percpu_enqueue_lim, nr_cpu_ids);
+++++ ++                        WRITE_ONCE(rtp->percpu_dequeue_lim, rcu_task_cpu_ids);
+++++ ++                        smp_store_release(&rtp->percpu_enqueue_lim, rcu_task_cpu_ids);
                                pr_info("Switching %s to per-CPU callback queuing.\n", rtp->name);
                        }
                        raw_spin_unlock_irqrestore(&rtp->cbs_gbl_lock, flags);
@@@@@@@@@ -388,6 -388,6 -388,6 -388,6 -388,6 -410,7 -388,6 -388,6 +410,7 @@@@@@@@@ static void rcu_barrier_tasks_generic_c
                struct rcu_tasks *rtp;
                struct rcu_tasks_percpu *rtpcp;
        
+++++ ++        rhp->next = rhp; // Mark the callback as having been invoked.
                rtpcp = container_of(rhp, struct rcu_tasks_percpu, barrier_q_head);
                rtp = rtpcp->rtpp;
                if (atomic_dec_and_test(&rtp->barrier_q_count))
        
        // Wait for all in-flight callbacks for the specified RCU Tasks flavor.
        // Operates in a manner similar to rcu_barrier().
----- --static void rcu_barrier_tasks_generic(struct rcu_tasks *rtp)
+++++ ++static void __maybe_unused rcu_barrier_tasks_generic(struct rcu_tasks *rtp)
        {
                int cpu;
                unsigned long flags;
                        mutex_unlock(&rtp->barrier_q_mutex);
                        return;
                }
+++++ ++        rtp->barrier_q_start = jiffies;
                rcu_seq_start(&rtp->barrier_q_seq);
                init_completion(&rtp->barrier_q_completion);
                atomic_set(&rtp->barrier_q_count, 2);
@@@@@@@@@ -444,6 -444,6 -444,6 -444,6 -444,6 -468,8 -444,6 -444,6 +468,8 @@@@@@@@@ static int rcu_tasks_need_gpcb(struct r
        
                dequeue_limit = smp_load_acquire(&rtp->percpu_dequeue_lim);
                for (cpu = 0; cpu < dequeue_limit; cpu++) {
+++++ ++                if (!cpu_possible(cpu))
+++++ ++                        continue;
                        struct rcu_tasks_percpu *rtpcp = per_cpu_ptr(rtp->rtpcpu, cpu);
        
                        /* Advance and accelerate any new callbacks. */
                if (rcu_task_cb_adjust && ncbs <= rcu_task_collapse_lim) {
                        raw_spin_lock_irqsave(&rtp->cbs_gbl_lock, flags);
                        if (rtp->percpu_enqueue_lim > 1) {
----- --                        WRITE_ONCE(rtp->percpu_enqueue_shift, order_base_2(nr_cpu_ids));
+++++ ++                        WRITE_ONCE(rtp->percpu_enqueue_shift, order_base_2(rcu_task_cpu_ids));
                                smp_store_release(&rtp->percpu_enqueue_lim, 1);
                                rtp->percpu_dequeue_gpseq = get_state_synchronize_rcu();
                                gpdone = false;
                                pr_info("Completing switch %s to CPU-0 callback queuing.\n", rtp->name);
                        }
                        if (rtp->percpu_dequeue_lim == 1) {
----- --                        for (cpu = rtp->percpu_dequeue_lim; cpu < nr_cpu_ids; cpu++) {
+++++ ++                        for (cpu = rtp->percpu_dequeue_lim; cpu < rcu_task_cpu_ids; cpu++) {
+++++ ++                                if (!cpu_possible(cpu))
+++++ ++                                        continue;
                                        struct rcu_tasks_percpu *rtpcp = per_cpu_ptr(rtp->rtpcpu, cpu);
        
                                        WARN_ON_ONCE(rcu_segcblist_n_cbs(&rtpcp->cblist));
        // Advance callbacks and invoke any that are ready.
        static void rcu_tasks_invoke_cbs(struct rcu_tasks *rtp, struct rcu_tasks_percpu *rtpcp)
        {
----- --        int cpu;
----- --        int cpunext;
                int cpuwq;
                unsigned long flags;
                int len;
+++++ ++        int index;
                struct rcu_head *rhp;
                struct rcu_cblist rcl = RCU_CBLIST_INITIALIZER(rcl);
                struct rcu_tasks_percpu *rtpcp_next;
        
----- --        cpu = rtpcp->cpu;
----- --        cpunext = cpu * 2 + 1;
----- --        if (cpunext < smp_load_acquire(&rtp->percpu_dequeue_lim)) {
----- --                rtpcp_next = per_cpu_ptr(rtp->rtpcpu, cpunext);
----- --                cpuwq = rcu_cpu_beenfullyonline(cpunext) ? cpunext : WORK_CPU_UNBOUND;
----- --                queue_work_on(cpuwq, system_wq, &rtpcp_next->rtp_work);
----- --                cpunext++;
----- --                if (cpunext < smp_load_acquire(&rtp->percpu_dequeue_lim)) {
----- --                        rtpcp_next = per_cpu_ptr(rtp->rtpcpu, cpunext);
----- --                        cpuwq = rcu_cpu_beenfullyonline(cpunext) ? cpunext : WORK_CPU_UNBOUND;
+++++ ++        index = rtpcp->index * 2 + 1;
+++++ ++        if (index < num_possible_cpus()) {
+++++ ++                rtpcp_next = rtp->rtpcp_array[index];
+++++ ++                if (rtpcp_next->cpu < smp_load_acquire(&rtp->percpu_dequeue_lim)) {
+++++ ++                        cpuwq = rcu_cpu_beenfullyonline(rtpcp_next->cpu) ? rtpcp_next->cpu : WORK_CPU_UNBOUND;
                                queue_work_on(cpuwq, system_wq, &rtpcp_next->rtp_work);
+++++ ++                        index++;
+++++ ++                        if (index < num_possible_cpus()) {
+++++ ++                                rtpcp_next = rtp->rtpcp_array[index];
+++++ ++                                if (rtpcp_next->cpu < smp_load_acquire(&rtp->percpu_dequeue_lim)) {
+++++ ++                                        cpuwq = rcu_cpu_beenfullyonline(rtpcp_next->cpu) ? rtpcp_next->cpu : WORK_CPU_UNBOUND;
+++++ ++                                        queue_work_on(cpuwq, system_wq, &rtpcp_next->rtp_work);
+++++ ++                                }
+++++ ++                        }
                        }
                }
        
----- --        if (rcu_segcblist_empty(&rtpcp->cblist) || !cpu_possible(cpu))
+++++ ++        if (rcu_segcblist_empty(&rtpcp->cblist))
                        return;
                raw_spin_lock_irqsave_rcu_node(rtpcp, flags);
                rcu_segcblist_advance(&rtpcp->cblist, rcu_seq_current(&rtp->tasks_gp_seq));
@@@@@@@@@ -687,9 -687,9 -687,9 -687,9 -687,9 -717,7 -687,9 -687,9 +717,7 @@@@@@@@@ static void __init rcu_tasks_bootup_odd
        #endif /* #ifdef CONFIG_TASKS_TRACE_RCU */
        }
        
----- --#endif /* #ifndef CONFIG_TINY_RCU */
        
----- --#ifndef CONFIG_TINY_RCU
        /* Dump out rcutorture-relevant state common to all RCU-tasks flavors. */
        static void show_rcu_tasks_generic_gp_kthread(struct rcu_tasks *rtp, char *s)
        {
                        rtp->lazy_jiffies,
                        s);
        }
+++++ ++
+++++ ++/* Dump out more rcutorture-relevant state common to all RCU-tasks flavors. */
+++++ ++static void rcu_tasks_torture_stats_print_generic(struct rcu_tasks *rtp, char *tt,
+++++ ++                                                  char *tf, char *tst)
+++++ ++{
+++++ ++        cpumask_var_t cm;
+++++ ++        int cpu;
+++++ ++        bool gotcb = false;
+++++ ++        unsigned long j = jiffies;
+++++ ++
+++++ ++        pr_alert("%s%s Tasks%s RCU g%ld gp_start %lu gp_jiffies %lu gp_state %d (%s).\n",
+++++ ++                 tt, tf, tst, data_race(rtp->tasks_gp_seq),
+++++ ++                 j - data_race(rtp->gp_start), j - data_race(rtp->gp_jiffies),
+++++ ++                 data_race(rtp->gp_state), tasks_gp_state_getname(rtp));
+++++ ++        pr_alert("\tEnqueue shift %d limit %d Dequeue limit %d gpseq %lu.\n",
+++++ ++                 data_race(rtp->percpu_enqueue_shift),
+++++ ++                 data_race(rtp->percpu_enqueue_lim),
+++++ ++                 data_race(rtp->percpu_dequeue_lim),
+++++ ++                 data_race(rtp->percpu_dequeue_gpseq));
+++++ ++        (void)zalloc_cpumask_var(&cm, GFP_KERNEL);
+++++ ++        pr_alert("\tCallback counts:");
+++++ ++        for_each_possible_cpu(cpu) {
+++++ ++                long n;
+++++ ++                struct rcu_tasks_percpu *rtpcp = per_cpu_ptr(rtp->rtpcpu, cpu);
+++++ ++
+++++ ++                if (cpumask_available(cm) && !rcu_barrier_cb_is_done(&rtpcp->barrier_q_head))
+++++ ++                        cpumask_set_cpu(cpu, cm);
+++++ ++                n = rcu_segcblist_n_cbs(&rtpcp->cblist);
+++++ ++                if (!n)
+++++ ++                        continue;
+++++ ++                pr_cont(" %d:%ld", cpu, n);
+++++ ++                gotcb = true;
+++++ ++        }
+++++ ++        if (gotcb)
+++++ ++                pr_cont(".\n");
+++++ ++        else
+++++ ++                pr_cont(" (none).\n");
+++++ ++        pr_alert("\tBarrier seq %lu start %lu count %d holdout CPUs ",
+++++ ++                 data_race(rtp->barrier_q_seq), j - data_race(rtp->barrier_q_start),
+++++ ++                 atomic_read(&rtp->barrier_q_count));
+++++ ++        if (cpumask_available(cm) && !cpumask_empty(cm))
+++++ ++                pr_cont(" %*pbl.\n", cpumask_pr_args(cm));
+++++ ++        else
+++++ ++                pr_cont("(none).\n");
+++++ ++        free_cpumask_var(cm);
+++++ ++}
+++++ ++
        #endif // #ifndef CONFIG_TINY_RCU
        
        static void exit_tasks_rcu_finish_trace(struct task_struct *t);
@@@@@@@@@ -1174,6 -1174,6 -1174,6 -1174,6 -1174,6 -1249,12 -1174,6 -1174,6 +1249,12 @@@@@@@@@ void show_rcu_tasks_classic_gp_kthread(
                show_rcu_tasks_generic_gp_kthread(&rcu_tasks, "");
        }
        EXPORT_SYMBOL_GPL(show_rcu_tasks_classic_gp_kthread);
+++++ ++
+++++ ++void rcu_tasks_torture_stats_print(char *tt, char *tf)
+++++ ++{
+++++ ++        rcu_tasks_torture_stats_print_generic(&rcu_tasks, tt, tf, "");
+++++ ++}
+++++ ++EXPORT_SYMBOL_GPL(rcu_tasks_torture_stats_print);
        #endif // !defined(CONFIG_TINY_RCU)
        
        struct task_struct *get_rcu_tasks_gp_kthread(void)
@@@@@@@@@ -1244,13 -1244,13 -1244,13 -1244,13 -1244,13 -1325,12 -1244,13 -1244,13 +1325,12 @@@@@@@@@ void exit_tasks_rcu_finish(void) { exit
        
        ////////////////////////////////////////////////////////////////////////
        //
----- --// "Rude" variant of Tasks RCU, inspired by Steve Rostedt's trick of
----- --// passing an empty function to schedule_on_each_cpu().  This approach
----- --// provides an asynchronous call_rcu_tasks_rude() API and batching of
----- --// concurrent calls to the synchronous synchronize_rcu_tasks_rude() API.
----- --// This invokes schedule_on_each_cpu() in order to send IPIs far and wide
----- --// and induces otherwise unnecessary context switches on all online CPUs,
----- --// whether idle or not.
+++++ ++// "Rude" variant of Tasks RCU, inspired by Steve Rostedt's
+++++ ++// trick of passing an empty function to schedule_on_each_cpu().
+++++ ++// This approach provides batching of concurrent calls to the synchronous
+++++ ++// synchronize_rcu_tasks_rude() API.  This invokes schedule_on_each_cpu()
+++++ ++// in order to send IPIs far and wide and induces otherwise unnecessary
+++++ ++// context switches on all online CPUs, whether idle or not.
        //
        // Callback handling is provided by the rcu_tasks_kthread() function.
        //
@@@@@@@@@ -1268,11 -1268,11 -1268,11 -1268,11 -1268,11 -1348,11 -1268,11 -1268,11 +1348,11 @@@@@@@@@ static void rcu_tasks_rude_wait_gp(stru
                schedule_on_each_cpu(rcu_tasks_be_rude);
        }
        
----- --void call_rcu_tasks_rude(struct rcu_head *rhp, rcu_callback_t func);
+++++ ++static void call_rcu_tasks_rude(struct rcu_head *rhp, rcu_callback_t func);
        DEFINE_RCU_TASKS(rcu_tasks_rude, rcu_tasks_rude_wait_gp, call_rcu_tasks_rude,
                         "RCU Tasks Rude");
        
----- --/**
+++++ ++/*
         * call_rcu_tasks_rude() - Queue a callback rude task-based grace period
         * @rhp: structure to be used for queueing the RCU updates.
         * @func: actual callback function to be invoked after the grace period
         *
         * See the description of call_rcu() for more detailed information on
         * memory ordering guarantees.
+++++ ++ *
+++++ ++ * This is no longer exported, and is instead reserved for use by
+++++ ++ * synchronize_rcu_tasks_rude().
         */
----- --void call_rcu_tasks_rude(struct rcu_head *rhp, rcu_callback_t func)
+++++ ++static void call_rcu_tasks_rude(struct rcu_head *rhp, rcu_callback_t func)
        {
                call_rcu_tasks_generic(rhp, func, &rcu_tasks_rude);
        }
----- --EXPORT_SYMBOL_GPL(call_rcu_tasks_rude);
        
        /**
         * synchronize_rcu_tasks_rude - wait for a rude rcu-tasks grace period
@@@@@@@@@ -1320,26 -1320,26 -1320,26 -1320,26 -1320,26 -1402,9 -1320,26 -1320,26 +1402,9 @@@@@@@@@ void synchronize_rcu_tasks_rude(void
        }
        EXPORT_SYMBOL_GPL(synchronize_rcu_tasks_rude);
        
----- --/**
----- -- * rcu_barrier_tasks_rude - Wait for in-flight call_rcu_tasks_rude() callbacks.
----- -- *
----- -- * Although the current implementation is guaranteed to wait, it is not
----- -- * obligated to, for example, if there are no pending callbacks.
----- -- */
----- --void rcu_barrier_tasks_rude(void)
----- --{
----- --        rcu_barrier_tasks_generic(&rcu_tasks_rude);
----- --}
----- --EXPORT_SYMBOL_GPL(rcu_barrier_tasks_rude);
----- --
----- --int rcu_tasks_rude_lazy_ms = -1;
----- --module_param(rcu_tasks_rude_lazy_ms, int, 0444);
----- --
        static int __init rcu_spawn_tasks_rude_kthread(void)
        {
                rcu_tasks_rude.gp_sleep = HZ / 10;
----- --        if (rcu_tasks_rude_lazy_ms >= 0)
----- --                rcu_tasks_rude.lazy_jiffies = msecs_to_jiffies(rcu_tasks_rude_lazy_ms);
                rcu_spawn_tasks_kthread_generic(&rcu_tasks_rude);
                return 0;
        }
@@@@@@@@@ -1350,6 -1350,6 -1350,6 -1350,6 -1350,6 -1415,12 -1350,6 -1350,6 +1415,12 @@@@@@@@@ void show_rcu_tasks_rude_gp_kthread(voi
                show_rcu_tasks_generic_gp_kthread(&rcu_tasks_rude, "");
        }
        EXPORT_SYMBOL_GPL(show_rcu_tasks_rude_gp_kthread);
+++++ ++
+++++ ++void rcu_tasks_rude_torture_stats_print(char *tt, char *tf)
+++++ ++{
+++++ ++        rcu_tasks_torture_stats_print_generic(&rcu_tasks_rude, tt, tf, "");
+++++ ++}
+++++ ++EXPORT_SYMBOL_GPL(rcu_tasks_rude_torture_stats_print);
        #endif // !defined(CONFIG_TINY_RCU)
        
        struct task_struct *get_rcu_tasks_rude_gp_kthread(void)
@@@@@@@@@ -1613,7 -1613,7 -1613,7 -1613,7 -1613,7 -1684,7 -1613,7 -1613,7 +1684,7 @@@@@@@@@ static int trc_inspect_reader(struct ta
                        // However, we cannot safely change its state.
                        n_heavy_reader_attempts++;
                        // Check for "running" idle tasks on offline CPUs.
 -------                if (!rcu_dynticks_zero_in_eqs(cpu, &t->trc_reader_nesting))
 +++++++                if (!rcu_watching_zero_in_eqs(cpu, &t->trc_reader_nesting))
                                return -EINVAL; // No quiescent state, do it the hard way.
                        n_heavy_reader_updates++;
                        nesting = 0;
@@@@@@@@@ -2027,6 -2027,6 -2027,6 -2027,6 -2027,6 -2098,12 -2027,6 -2027,6 +2098,12 @@@@@@@@@ void show_rcu_tasks_trace_gp_kthread(vo
                show_rcu_tasks_generic_gp_kthread(&rcu_tasks_trace, buf);
        }
        EXPORT_SYMBOL_GPL(show_rcu_tasks_trace_gp_kthread);
+++++ ++
+++++ ++void rcu_tasks_trace_torture_stats_print(char *tt, char *tf)
+++++ ++{
+++++ ++        rcu_tasks_torture_stats_print_generic(&rcu_tasks_trace, tt, tf, "");
+++++ ++}
+++++ ++EXPORT_SYMBOL_GPL(rcu_tasks_trace_torture_stats_print);
        #endif // !defined(CONFIG_TINY_RCU)
        
        struct task_struct *get_rcu_tasks_trace_gp_kthread(void)
@@@@@@@@@ -2069,11 -2069,11 -2069,11 -2069,11 -2069,11 -2146,6 -2069,11 -2069,11 +2146,6 @@@@@@@@@ static struct rcu_tasks_test_desc tests
                        /* If not defined, the test is skipped. */
                        .notrun = IS_ENABLED(CONFIG_TASKS_RCU),
                },
----- --        {
----- --                .name = "call_rcu_tasks_rude()",
----- --                /* If not defined, the test is skipped. */
----- --                .notrun = IS_ENABLED(CONFIG_TASKS_RUDE_RCU),
----- --        },
                {
                        .name = "call_rcu_tasks_trace()",
                        /* If not defined, the test is skipped. */
                }
        };
        
+++++ ++#if defined(CONFIG_TASKS_RCU) || defined(CONFIG_TASKS_TRACE_RCU)
        static void test_rcu_tasks_callback(struct rcu_head *rhp)
        {
                struct rcu_tasks_test_desc *rttd =
        
                rttd->notrun = false;
        }
+++++ ++#endif // #if defined(CONFIG_TASKS_RCU) || defined(CONFIG_TASKS_TRACE_RCU)
        
        static void rcu_tasks_initiate_self_tests(void)
        {
        
        #ifdef CONFIG_TASKS_RUDE_RCU
                pr_info("Running RCU Tasks Rude wait API self tests\n");
----- --        tests[1].runstart = jiffies;
                synchronize_rcu_tasks_rude();
----- --        call_rcu_tasks_rude(&tests[1].rh, test_rcu_tasks_callback);
        #endif
        
        #ifdef CONFIG_TASKS_TRACE_RCU
                pr_info("Running RCU Tasks Trace wait API self tests\n");
----- --        tests[2].runstart = jiffies;
+++++ ++        tests[1].runstart = jiffies;
                synchronize_rcu_tasks_trace();
----- --        call_rcu_tasks_trace(&tests[2].rh, test_rcu_tasks_callback);
+++++ ++        call_rcu_tasks_trace(&tests[1].rh, test_rcu_tasks_callback);
        #endif
        }
        
diff --combined kernel/rcu/tree.c
index e0f6fc272906fb238d201252c5fa3aba8d28b99d,82e831b969e41bba9b8eac1f9f9a538146279a80,e641cc681901a5e5c7a7e1791a836ba0db89d7d3,e641cc681901a5e5c7a7e1791a836ba0db89d7d3,e641cc681901a5e5c7a7e1791a836ba0db89d7d3,f931171daecdf83ee17967eaf13d2c94786af948,494aa9513d0b479725b05a77463b316f682f2f41,d5bf824159dab39ccff28c3b82f6387ca3dc1828..0c8b56c4ee88e8695837d23264a584adfb987af0
@@@@@@@@@ -79,9 -79,6 -79,9 -79,9 -79,9 -79,9 -79,9 -79,9 +79,6 @@@@@@@@@ static void rcu_sr_normal_gp_cleanup_wo
        
        static DEFINE_PER_CPU_SHARED_ALIGNED(struct rcu_data, rcu_data) = {
                .gpwrap = true,
- ------#ifdef CONFIG_RCU_NOCB_CPU
- ------        .cblist.flags = SEGCBLIST_RCU_CORE,
- ------#endif
        };
        static struct rcu_state rcu_state = {
                .level = { &rcu_state.node[0] },
                .srs_cleanup_work = __WORK_INITIALIZER(rcu_state.srs_cleanup_work,
                        rcu_sr_normal_gp_cleanup_work),
                .srs_cleanups_pending = ATOMIC_INIT(0),
+ ++++++#ifdef CONFIG_RCU_NOCB_CPU
+ ++++++        .nocb_mutex = __MUTEX_INITIALIZER(rcu_state.nocb_mutex),
+ ++++++#endif
        };
        
        /* Dump rcu_node combining tree at boot to verify correct setup. */
@@@@@@@@@ -283,45 -283,37 -283,37 -283,37 -283,37 -283,37 -283,37 -283,37 +283,45 @@@@@@@@@ void rcu_softirq_qs(void
        }
        
        /*
 ------- * Reset the current CPU's ->dynticks counter to indicate that the
 +++++++ * Reset the current CPU's RCU_WATCHING counter to indicate that the
         * newly onlined CPU is no longer in an extended quiescent state.
         * This will either leave the counter unchanged, or increment it
         * to the next non-quiescent value.
         *
         * The non-atomic test/increment sequence works because the upper bits
 ------- * of the ->dynticks counter are manipulated only by the corresponding CPU,
 +++++++ * of the ->state variable are manipulated only by the corresponding CPU,
         * or when the corresponding CPU is offline.
         */
 -------static void rcu_dynticks_eqs_online(void)
 +++++++static void rcu_watching_online(void)
        {
 -------        if (ct_dynticks() & RCU_DYNTICKS_IDX)
 +++++++        if (ct_rcu_watching() & CT_RCU_WATCHING)
                        return;
 -------        ct_state_inc(RCU_DYNTICKS_IDX);
 +++++++        ct_state_inc(CT_RCU_WATCHING);
        }
        
        /*
 ------- * Return true if the snapshot returned from rcu_dynticks_snap()
 +++++++ * Return true if the snapshot returned from ct_rcu_watching()
         * indicates that RCU is in an extended quiescent state.
         */
 -------static bool rcu_dynticks_in_eqs(int snap)
 +++++++static bool rcu_watching_snap_in_eqs(int snap)
        {
 -------        return !(snap & RCU_DYNTICKS_IDX);
 +++++++        return !(snap & CT_RCU_WATCHING);
        }
        
 -------/*
 ------- * Return true if the CPU corresponding to the specified rcu_data
 ------- * structure has spent some time in an extended quiescent state since
 ------- * rcu_dynticks_snap() returned the specified snapshot.
 +++++++/**
 +++++++ * rcu_watching_snap_stopped_since() - Has RCU stopped watching a given CPU
 +++++++ * since the specified @snap?
 +++++++ *
 +++++++ * @rdp: The rcu_data corresponding to the CPU for which to check EQS.
 +++++++ * @snap: rcu_watching snapshot taken when the CPU wasn't in an EQS.
 +++++++ *
 +++++++ * Returns true if the CPU corresponding to @rdp has spent some time in an
 +++++++ * extended quiescent state since @snap. Note that this doesn't check if it
 +++++++ * /still/ is in an EQS, just that it went through one since @snap.
 +++++++ *
 +++++++ * This is meant to be used in a loop waiting for a CPU to go through an EQS.
         */
 -------static bool rcu_dynticks_in_eqs_since(struct rcu_data *rdp, int snap)
 +++++++static bool rcu_watching_snap_stopped_since(struct rcu_data *rdp, int snap)
        {
                /*
                 * The first failing snapshot is already ordered against the accesses
                 * performed by the remote CPU prior to entering idle and therefore can
                 * rely solely on acquire semantics.
                 */
 -------        return snap != ct_dynticks_cpu_acquire(rdp->cpu);
 +++++++        if (WARN_ON_ONCE(rcu_watching_snap_in_eqs(snap)))
 +++++++                return true;
 +++++++
 +++++++        return snap != ct_rcu_watching_cpu_acquire(rdp->cpu);
        }
        
        /*
         * Return true if the referenced integer is zero while the specified
         * CPU remains within a single extended quiescent state.
         */
 -------bool rcu_dynticks_zero_in_eqs(int cpu, int *vp)
 +++++++bool rcu_watching_zero_in_eqs(int cpu, int *vp)
        {
                int snap;
        
                // If not quiescent, force back to earlier extended quiescent state.
 -------        snap = ct_dynticks_cpu(cpu) & ~RCU_DYNTICKS_IDX;
 -------        smp_rmb(); // Order ->dynticks and *vp reads.
 +++++++        snap = ct_rcu_watching_cpu(cpu) & ~CT_RCU_WATCHING;
 +++++++        smp_rmb(); // Order CT state and *vp reads.
                if (READ_ONCE(*vp))
                        return false;  // Non-zero, so report failure;
 -------        smp_rmb(); // Order *vp read and ->dynticks re-read.
 +++++++        smp_rmb(); // Order *vp read and CT state re-read.
        
                // If still in the same extended quiescent state, we are good!
 -------        return snap == ct_dynticks_cpu(cpu);
 +++++++        return snap == ct_rcu_watching_cpu(cpu);
        }
        
        /*
         *
         * The caller must have disabled interrupts and must not be idle.
         */
 -------notrace void rcu_momentary_dyntick_idle(void)
 +++++++notrace void rcu_momentary_eqs(void)
        {
                int seq;
        
                raw_cpu_write(rcu_data.rcu_need_heavy_qs, false);
 -------        seq = ct_state_inc(2 * RCU_DYNTICKS_IDX);
 +++++++        seq = ct_state_inc(2 * CT_RCU_WATCHING);
                /* It is illegal to call this from idle state. */
 -------        WARN_ON_ONCE(!(seq & RCU_DYNTICKS_IDX));
 +++++++        WARN_ON_ONCE(!(seq & CT_RCU_WATCHING));
                rcu_preempt_deferred_qs(current);
        }
 -------EXPORT_SYMBOL_GPL(rcu_momentary_dyntick_idle);
 +++++++EXPORT_SYMBOL_GPL(rcu_momentary_eqs);
        
        /**
         * rcu_is_cpu_rrupt_from_idle - see if 'interrupted' from idle
@@@@@@@@@ -399,13 -388,13 -388,13 -388,13 -388,13 -388,13 -388,13 -388,13 +399,13 @@@@@@@@@ static int rcu_is_cpu_rrupt_from_idle(v
                lockdep_assert_irqs_disabled();
        
                /* Check for counter underflows */
 -------        RCU_LOCKDEP_WARN(ct_dynticks_nesting() < 0,
 -------                         "RCU dynticks_nesting counter underflow!");
 -------        RCU_LOCKDEP_WARN(ct_dynticks_nmi_nesting() <= 0,
 -------                         "RCU dynticks_nmi_nesting counter underflow/zero!");
 +++++++        RCU_LOCKDEP_WARN(ct_nesting() < 0,
 +++++++                         "RCU nesting counter underflow!");
 +++++++        RCU_LOCKDEP_WARN(ct_nmi_nesting() <= 0,
 +++++++                         "RCU nmi_nesting counter underflow/zero!");
        
                /* Are we at first interrupt nesting level? */
 -------        nesting = ct_dynticks_nmi_nesting();
 +++++++        nesting = ct_nmi_nesting();
                if (nesting > 1)
                        return false;
        
                WARN_ON_ONCE(!nesting && !is_idle_task(current));
        
                /* Does CPU appear to be idle from an RCU standpoint? */
 -------        return ct_dynticks_nesting() == 0;
 +++++++        return ct_nesting() == 0;
        }
        
        #define DEFAULT_RCU_BLIMIT (IS_ENABLED(CONFIG_RCU_STRICT_GRACE_PERIOD) ? 1000 : 10)
@@@@@@@@@ -607,12 -596,12 -596,12 -596,12 -596,12 -596,12 -596,12 -596,12 +607,12 @@@@@@@@@ void rcu_irq_exit_check_preempt(void
        {
                lockdep_assert_irqs_disabled();
        
 -------        RCU_LOCKDEP_WARN(ct_dynticks_nesting() <= 0,
 -------                         "RCU dynticks_nesting counter underflow/zero!");
 -------        RCU_LOCKDEP_WARN(ct_dynticks_nmi_nesting() !=
 -------                         DYNTICK_IRQ_NONIDLE,
 -------                         "Bad RCU  dynticks_nmi_nesting counter\n");
 -------        RCU_LOCKDEP_WARN(rcu_dynticks_curr_cpu_in_eqs(),
 +++++++        RCU_LOCKDEP_WARN(ct_nesting() <= 0,
 +++++++                         "RCU nesting counter underflow/zero!");
 +++++++        RCU_LOCKDEP_WARN(ct_nmi_nesting() !=
 +++++++                         CT_NESTING_IRQ_NONIDLE,
 +++++++                         "Bad RCU  nmi_nesting counter\n");
 +++++++        RCU_LOCKDEP_WARN(!rcu_is_watching_curr_cpu(),
                                 "RCU in extended quiescent state!");
        }
        #endif /* #ifdef CONFIG_PROVE_RCU */
@@@@@@@@@ -652,7 -641,7 -641,7 -641,7 -641,7 -641,7 -641,7 -641,7 +652,7 @@@@@@@@@ void __rcu_irq_enter_check_tick(void
                if (in_nmi())
                        return;
        
 -------        RCU_LOCKDEP_WARN(rcu_dynticks_curr_cpu_in_eqs(),
 +++++++        RCU_LOCKDEP_WARN(!rcu_is_watching_curr_cpu(),
                                 "Illegal rcu_irq_enter_check_tick() from extended quiescent state");
        
                if (!tick_nohz_full_cpu(rdp->cpu) ||
@@@@@@@@@ -734,7 -723,7 -723,7 -723,7 -723,7 -723,7 -723,7 -723,7 +734,7 @@@@@@@@@ notrace bool rcu_is_watching(void
                bool ret;
        
                preempt_disable_notrace();
 -------        ret = !rcu_dynticks_curr_cpu_in_eqs();
 +++++++        ret = rcu_is_watching_curr_cpu();
                preempt_enable_notrace();
                return ret;
        }
@@@@@@@@@ -776,11 -765,11 -765,11 -765,11 -765,11 -765,11 -765,11 -765,11 +776,11 @@@@@@@@@ static void rcu_gpnum_ovf(struct rcu_no
        }
        
        /*
 ------- * Snapshot the specified CPU's dynticks counter so that we can later
 +++++++ * Snapshot the specified CPU's RCU_WATCHING counter so that we can later
         * credit them with an implicit quiescent state.  Return 1 if this CPU
         * is in dynticks idle mode, which is an extended quiescent state.
         */
 -------static int dyntick_save_progress_counter(struct rcu_data *rdp)
 +++++++static int rcu_watching_snap_save(struct rcu_data *rdp)
        {
                /*
                 * Full ordering between remote CPU's post idle accesses and updater's
                 * Ordering between remote CPU's pre idle accesses and post grace period
                 * updater's accesses is enforced by the below acquire semantic.
                 */
 -------        rdp->dynticks_snap = ct_dynticks_cpu_acquire(rdp->cpu);
 -------        if (rcu_dynticks_in_eqs(rdp->dynticks_snap)) {
 +++++++        rdp->watching_snap = ct_rcu_watching_cpu_acquire(rdp->cpu);
 +++++++        if (rcu_watching_snap_in_eqs(rdp->watching_snap)) {
                        trace_rcu_fqs(rcu_state.name, rdp->gp_seq, rdp->cpu, TPS("dti"));
                        rcu_gpnum_ovf(rdp->mynode, rdp);
                        return 1;
        /*
         * Returns positive if the specified CPU has passed through a quiescent state
         * by virtue of being in or having passed through an dynticks idle state since
 ------- * the last call to dyntick_save_progress_counter() for this same CPU, or by
 +++++++ * the last call to rcu_watching_snap_save() for this same CPU, or by
         * virtue of having been offline.
         *
         * Returns negative if the specified CPU needs a force resched.
         *
         * Returns zero otherwise.
         */
 -------static int rcu_implicit_dynticks_qs(struct rcu_data *rdp)
 +++++++static int rcu_watching_snap_recheck(struct rcu_data *rdp)
        {
                unsigned long jtsq;
                int ret = 0;
                 * read-side critical section that started before the beginning
                 * of the current RCU grace period.
                 */
 -------        if (rcu_dynticks_in_eqs_since(rdp, rdp->dynticks_snap)) {
 +++++++        if (rcu_watching_snap_stopped_since(rdp, rdp->watching_snap)) {
                        trace_rcu_fqs(rcu_state.name, rdp->gp_seq, rdp->cpu, TPS("dti"));
                        rcu_gpnum_ovf(rnp, rdp);
                        return 1;
@@@@@@@@@ -1660,7 -1649,7 -1649,7 -1649,7 -1649,7 -1649,7 -1649,7 -1649,7 +1660,7 @@@@@@@@@ static void rcu_sr_normal_gp_cleanup_wo
                 * the done tail list manipulations are protected here.
                 */
                done = smp_load_acquire(&rcu_state.srs_done_tail);
-------         if (!done)
+++++++         if (WARN_ON_ONCE(!done))
                        return;
        
                WARN_ON_ONCE(!rcu_sr_is_wait_head(done));
@@@@@@@@@ -1995,10 -1984,10 -1984,10 -1984,10 -1984,10 -1984,10 -1984,10 -1984,10 +1995,10 @@@@@@@@@ static void rcu_gp_fqs(bool first_time
        
                if (first_time) {
                        /* Collect dyntick-idle snapshots. */
 -------                force_qs_rnp(dyntick_save_progress_counter);
 +++++++                force_qs_rnp(rcu_watching_snap_save);
                } else {
                        /* Handle dyntick-idle and offline CPUs. */
 -------                force_qs_rnp(rcu_implicit_dynticks_qs);
 +++++++                force_qs_rnp(rcu_watching_snap_recheck);
                }
                /* Clear flag to prevent immediate re-entry. */
                if (READ_ONCE(rcu_state.gp_flags) & RCU_GP_FLAG_FQS) {
@@@@@@@@@ -2394,7 -2383,6 -2383,7 -2383,7 -2383,7 -2383,7 -2383,7 -2383,7 +2394,6 @@@@@@@@@ rcu_report_qs_rdp(struct rcu_data *rdp
        {
                unsigned long flags;
                unsigned long mask;
- ------        bool needacc = false;
                struct rcu_node *rnp;
        
                WARN_ON_ONCE(rdp->cpu != smp_processor_id());
                                 * to return true.  So complain, but don't awaken.
                                 */
                                WARN_ON_ONCE(rcu_accelerate_cbs(rnp, rdp));
- ------                } else if (!rcu_segcblist_completely_offloaded(&rdp->cblist)) {
- ------                        /*
- ------                         * ...but NOCB kthreads may miss or delay callbacks acceleration
- ------                         * if in the middle of a (de-)offloading process.
- ------                         */
- ------                        needacc = true;
                        }
        
                        rcu_disable_urgency_upon_qs(rdp);
                        rcu_report_qs_rnp(mask, rnp, rnp->gp_seq, flags);
                        /* ^^^ Released rnp->lock */
- ------
- ------                if (needacc) {
- ------                        rcu_nocb_lock_irqsave(rdp, flags);
- ------                        rcu_accelerate_cbs_unlocked(rnp, rdp);
- ------                        rcu_nocb_unlock_irqrestore(rdp, flags);
- ------                }
                }
        }
        
@@@@@@@@@ -2802,24 -2778,6 -2791,24 -2791,24 -2791,24 -2791,24 -2791,24 -2791,24 +2789,6 @@@@@@@@@ static __latent_entropy void rcu_core(v
                unsigned long flags;
                struct rcu_data *rdp = raw_cpu_ptr(&rcu_data);
                struct rcu_node *rnp = rdp->mynode;
- ------        /*
- ------         * On RT rcu_core() can be preempted when IRQs aren't disabled.
- ------         * Therefore this function can race with concurrent NOCB (de-)offloading
- ------         * on this CPU and the below condition must be considered volatile.
- ------         * However if we race with:
- ------         *
- ------         * _ Offloading:   In the worst case we accelerate or process callbacks
- ------         *                 concurrently with NOCB kthreads. We are guaranteed to
- ------         *                 call rcu_nocb_lock() if that happens.
- ------         *
- ------         * _ Deoffloading: In the worst case we miss callbacks acceleration or
- ------         *                 processing. This is fine because the early stage
- ------         *                 of deoffloading invokes rcu_core() after setting
- ------         *                 SEGCBLIST_RCU_CORE. So we guarantee that we'll process
- ------         *                 what could have been dismissed without the need to wait
- ------         *                 for the next rcu_pending() check in the next jiffy.
- ------         */
- ------        const bool do_batch = !rcu_segcblist_completely_offloaded(&rdp->cblist);
        
                if (cpu_is_offline(smp_processor_id()))
                        return;
        
                /* No grace period and unregistered callbacks? */
                if (!rcu_gp_in_progress() &&
- ------            rcu_segcblist_is_enabled(&rdp->cblist) && do_batch) {
- ------                rcu_nocb_lock_irqsave(rdp, flags);
+ ++++++            rcu_segcblist_is_enabled(&rdp->cblist) && !rcu_rdp_is_offloaded(rdp)) {
+ ++++++                local_irq_save(flags);
                        if (!rcu_segcblist_restempty(&rdp->cblist, RCU_NEXT_READY_TAIL))
                                rcu_accelerate_cbs_unlocked(rnp, rdp);
- ------                rcu_nocb_unlock_irqrestore(rdp, flags);
+ ++++++                local_irq_restore(flags);
                }
        
                rcu_check_gp_start_stall(rnp, rdp, rcu_jiffies_till_stall_check());
        
                /* If there are callbacks ready, invoke them. */
- ------        if (do_batch && rcu_segcblist_ready_cbs(&rdp->cblist) &&
+ ++++++        if (!rcu_rdp_is_offloaded(rdp) && rcu_segcblist_ready_cbs(&rdp->cblist) &&
                    likely(READ_ONCE(rcu_scheduler_fully_active))) {
                        rcu_do_batch(rdp);
                        /* Re-invoke RCU core processing if there are callbacks remaining. */
@@@@@@@@@ -3238,7 -3196,7 -3227,7 -3227,7 -3227,7 -3227,7 -3227,7 -3227,7 +3207,7 @@@@@@@@@ struct kvfree_rcu_bulk_data 
                struct list_head list;
                struct rcu_gp_oldstate gp_snap;
                unsigned long nr_records;
-------         void *records[];
+++++++         void *records[] __counted_by(nr_records);
        };
        
        /*
@@@@@@@@@ -3550,10 -3508,10 -3539,10 -3539,10 -3539,10 -3539,10 -3539,10 -3539,10 +3519,10 @@@@@@@@@ schedule_delayed_monitor_work(struct kf
                if (delayed_work_pending(&krcp->monitor_work)) {
                        delay_left = krcp->monitor_work.timer.expires - jiffies;
                        if (delay < delay_left)
------ -                        mod_delayed_work(system_wq, &krcp->monitor_work, delay);
++++++ +                        mod_delayed_work(system_unbound_wq, &krcp->monitor_work, delay);
                        return;
                }
------ -        queue_delayed_work(system_wq, &krcp->monitor_work, delay);
++++++ +        queue_delayed_work(system_unbound_wq, &krcp->monitor_work, delay);
        }
        
        static void
@@@@@@@@@ -3645,7 -3603,7 -3634,7 -3634,7 -3634,7 -3634,7 -3634,7 -3634,7 +3614,7 @@@@@@@@@ static void kfree_rcu_monitor(struct wo
                                // be that the work is in the pending state when
                                // channels have been detached following by each
                                // other.
------ -                        queue_rcu_work(system_wq, &krwp->rcu_work);
++++++ +                        queue_rcu_work(system_unbound_wq, &krwp->rcu_work);
                        }
                }
        
@@@@@@@@@ -3715,7 -3673,7 -3704,7 -3704,7 -3704,7 -3704,7 -3704,7 -3704,7 +3684,7 @@@@@@@@@ run_page_cache_worker(struct kfree_rcu_
                if (rcu_scheduler_active == RCU_SCHEDULER_RUNNING &&
                                !atomic_xchg(&krcp->work_in_progress, 1)) {
                        if (atomic_read(&krcp->backoff_page_cache_fill)) {
------ -                        queue_delayed_work(system_wq,
++++++ +                        queue_delayed_work(system_unbound_wq,
                                        &krcp->page_cache_work,
                                                msecs_to_jiffies(rcu_delay_page_cache_fill_msec));
                        } else {
@@@@@@@@@ -3778,7 -3736,7 -3767,7 -3767,7 -3767,7 -3767,7 -3767,7 -3767,8 +3747,8 @@@@@@@@@ add_ptr_to_bulk_krc_lock(struct kfree_r
                }
        
                // Finally insert and update the GP for this page.
-------         bnode->records[bnode->nr_records++] = ptr;
+++++++         bnode->nr_records++;
+++++++         bnode->records[bnode->nr_records - 1] = ptr;
                get_state_synchronize_rcu_full(&bnode->gp_snap);
                atomic_inc(&(*krcp)->bulk_count[idx]);
        
@@@@@@@@@ -4414,6 -4372,6 -4403,6 -4403,6 -4403,6 -4403,7 -4403,6 -4404,6 +4384,7 @@@@@@@@@ static void rcu_barrier_callback(struc
        {
                unsigned long __maybe_unused s = rcu_state.barrier_sequence;
        
+++++ ++        rhp->next = rhp; // Mark the callback as having been invoked.
                if (atomic_dec_and_test(&rcu_state.barrier_cpu_count)) {
                        rcu_barrier_trace(TPS("LastCB"), -1, s);
                        complete(&rcu_state.barrier_completion);
@@@@@@@@@ -4815,8 -4773,8 -4804,8 -4804,8 -4804,8 -4805,8 -4804,8 -4805,8 +4786,8 @@@@@@@@@ rcu_boot_init_percpu_data(int cpu
                /* Set up local state, ensuring consistent view of global state. */
                rdp->grpmask = leaf_node_cpu_bit(rdp->mynode, cpu);
                INIT_WORK(&rdp->strict_work, strict_work_handler);
 -------        WARN_ON_ONCE(ct->dynticks_nesting != 1);
 -------        WARN_ON_ONCE(rcu_dynticks_in_eqs(ct_dynticks_cpu(cpu)));
 +++++++        WARN_ON_ONCE(ct->nesting != 1);
 +++++++        WARN_ON_ONCE(rcu_watching_snap_in_eqs(ct_rcu_watching_cpu(cpu)));
                rdp->barrier_seq_snap = rcu_state.barrier_sequence;
                rdp->rcu_ofl_gp_seq = rcu_state.gp_seq;
                rdp->rcu_ofl_gp_state = RCU_GP_CLEANED;
@@@@@@@@@ -4909,7 -4867,7 -4898,7 -4898,7 -4898,7 -4899,7 -4898,7 -4899,7 +4880,7 @@@@@@@@@ int rcutree_prepare_cpu(unsigned int cp
                rdp->qlen_last_fqs_check = 0;
                rdp->n_force_qs_snap = READ_ONCE(rcu_state.n_force_qs);
                rdp->blimit = blimit;
 -------        ct->dynticks_nesting = 1;       /* CPU not up, no tearing. */
 +++++++        ct->nesting = 1;        /* CPU not up, no tearing. */
                raw_spin_unlock_rcu_node(rnp);          /* irqs remain disabled. */
        
                /*
@@@@@@@@@ -5069,7 -5027,7 -5058,7 -5058,7 -5058,7 -5059,7 -5058,7 -5059,7 +5040,7 @@@@@@@@@ void rcutree_report_cpu_starting(unsign
                rnp = rdp->mynode;
                mask = rdp->grpmask;
                arch_spin_lock(&rcu_state.ofl_lock);
 -------        rcu_dynticks_eqs_online();
 +++++++        rcu_watching_online();
                raw_spin_lock(&rcu_state.barrier_lock);
                raw_spin_lock_rcu_node(rnp);
                WRITE_ONCE(rnp->qsmaskinitnext, rnp->qsmaskinitnext | mask);
@@@@@@@@@ -5435,6 -5393,6 -5424,6 -5424,6 -5424,6 -5425,8 -5424,6 -5425,6 +5406,8 @@@@@@@@@ static void __init rcu_init_one(void
                        while (i > rnp->grphi)
                                rnp++;
                        per_cpu_ptr(&rcu_data, i)->mynode = rnp;
+++++ ++                per_cpu_ptr(&rcu_data, i)->barrier_head.next =
+++++ ++                        &per_cpu_ptr(&rcu_data, i)->barrier_head;
                        rcu_boot_init_percpu_data(i);
                }
        }
diff --combined kernel/rcu/tree.h
index 13fdcc2aa081232cd844be255955af28ea1278df,16e6fe63d93cda50ff336f4bf2226d12d755733b,fcf2b4aa34417e02c21f9e5a7e9073687d907368,fcf2b4aa34417e02c21f9e5a7e9073687d907368,fcf2b4aa34417e02c21f9e5a7e9073687d907368,fcf2b4aa34417e02c21f9e5a7e9073687d907368,fcf2b4aa34417e02c21f9e5a7e9073687d907368,fcf2b4aa34417e02c21f9e5a7e9073687d907368..a9a811d9d7a372abc80dc64e7cf3808e1e8f14fd
@@@@@@@@@ -206,7 -206,7 -206,7 -206,7 -206,7 -206,7 -206,7 -206,7 +206,7 @@@@@@@@@ struct rcu_data 
                long            blimit;         /* Upper limit on a processed batch */
        
                /* 3) dynticks interface. */
 -------        int dynticks_snap;              /* Per-GP tracking for dynticks. */
 +++++++        int  watching_snap;             /* Per-GP tracking for dynticks. */
                bool rcu_need_heavy_qs;         /* GP old, so heavy quiescent state! */
                bool rcu_urgent_qs;             /* GP old need light quiescent state. */
                bool rcu_forced_tick;           /* Forced tick to provide QS. */
                /* 4) rcu_barrier(), OOM callbacks, and expediting. */
                unsigned long barrier_seq_snap; /* Snap of rcu_state.barrier_sequence. */
                struct rcu_head barrier_head;
 -------        int exp_dynticks_snap;          /* Double-check need for IPI. */
 +++++++        int exp_watching_snap;          /* Double-check need for IPI. */
        
                /* 5) Callback offloading. */
        #ifdef CONFIG_RCU_NOCB_CPU
@@@@@@@@@ -411,7 -411,6 -411,7 -411,7 -411,7 -411,7 -411,7 -411,7 +411,6 @@@@@@@@@ struct rcu_state 
                arch_spinlock_t ofl_lock ____cacheline_internodealigned_in_smp;
                                                        /* Synchronize offline with */
                                                        /*  GP pre-initialization. */
- ------        int nocb_is_setup;                      /* nocb is setup from boot */
        
                /* synchronize_rcu() part. */
                struct llist_head srs_next;     /* request a GP users. */
                struct sr_wait_node srs_wait_nodes[SR_NORMAL_GP_WAIT_HEAD_MAX];
                struct work_struct srs_cleanup_work;
                atomic_t srs_cleanups_pending; /* srs inflight worker cleanups. */
+ ++++++
+ ++++++#ifdef CONFIG_RCU_NOCB_CPU
+ ++++++        struct mutex nocb_mutex;                /* Guards (de-)offloading */
+ ++++++        int nocb_is_setup;                      /* nocb is setup from boot */
+ ++++++#endif
        };
        
        /* Values for rcu_state structure's gp_flags field. */
diff --combined kernel/rcu/tree_exp.h
index eec42df0c018d23857316955127dd7b60fb7ddce,4acd29d16fdb999af51ef5cf65e6998640c4e221,4acd29d16fdb999af51ef5cf65e6998640c4e221,c5d9a7eb08034cca56f8d1a91bad2613e7c91fe4,4acd29d16fdb999af51ef5cf65e6998640c4e221,4acd29d16fdb999af51ef5cf65e6998640c4e221,4acd29d16fdb999af51ef5cf65e6998640c4e221,4acd29d16fdb999af51ef5cf65e6998640c4e221..c3266bf709d5934beffe69bc6dee08a96a8e4549
@@@@@@@@@ -376,11 -376,11 -376,11 -376,11 -376,11 -376,11 -376,11 -376,11 +376,11 @@@@@@@@@ static void __sync_rcu_exp_select_node_
                                 * post grace period updater's accesses is enforced by the
                                 * below acquire semantic.
                                 */
 -------                        snap = ct_dynticks_cpu_acquire(cpu);
 -------                        if (rcu_dynticks_in_eqs(snap))
 +++++++                        snap = ct_rcu_watching_cpu_acquire(cpu);
 +++++++                        if (rcu_watching_snap_in_eqs(snap))
                                        mask_ofl_test |= mask;
                                else
 -------                                rdp->exp_dynticks_snap = snap;
 +++++++                                rdp->exp_watching_snap = snap;
                        }
                }
                mask_ofl_ipi = rnp->expmask & ~mask_ofl_test;
                        unsigned long mask = rdp->grpmask;
        
        retry_ipi:
 -------                if (rcu_dynticks_in_eqs_since(rdp, rdp->exp_dynticks_snap)) {
 +++++++                if (rcu_watching_snap_stopped_since(rdp, rdp->exp_watching_snap)) {
                                mask_ofl_test |= mask;
                                continue;
                        }
@@@@@@@@@ -542,6 -542,6 -542,6 -542,67 -542,6 -542,6 -542,6 -542,6 +542,67 @@@@@@@@@ static bool synchronize_rcu_expedited_w
                return false;
        }
        
+++ ++++/*
+++ ++++ * Print out an expedited RCU CPU stall warning message.
+++ ++++ */
+++ ++++static void synchronize_rcu_expedited_stall(unsigned long jiffies_start, unsigned long j)
+++ ++++{
+++ ++++        int cpu;
+++ ++++        unsigned long mask;
+++ ++++        int ndetected;
+++ ++++        struct rcu_node *rnp;
+++ ++++        struct rcu_node *rnp_root = rcu_get_root();
+++ ++++
+++ ++++        if (READ_ONCE(csd_lock_suppress_rcu_stall) && csd_lock_is_stuck()) {
+++ ++++                pr_err("INFO: %s detected expedited stalls, but suppressed full report due to a stuck CSD-lock.\n", rcu_state.name);
+++ ++++                return;
+++ ++++        }
+++ ++++        pr_err("INFO: %s detected expedited stalls on CPUs/tasks: {", rcu_state.name);
+++ ++++        ndetected = 0;
+++ ++++        rcu_for_each_leaf_node(rnp) {
+++ ++++                ndetected += rcu_print_task_exp_stall(rnp);
+++ ++++                for_each_leaf_node_possible_cpu(rnp, cpu) {
+++ ++++                        struct rcu_data *rdp;
+++ ++++
+++ ++++                        mask = leaf_node_cpu_bit(rnp, cpu);
+++ ++++                        if (!(READ_ONCE(rnp->expmask) & mask))
+++ ++++                                continue;
+++ ++++                        ndetected++;
+++ ++++                        rdp = per_cpu_ptr(&rcu_data, cpu);
+++ ++++                        pr_cont(" %d-%c%c%c%c", cpu,
+++ ++++                                "O."[!!cpu_online(cpu)],
+++ ++++                                "o."[!!(rdp->grpmask & rnp->expmaskinit)],
+++ ++++                                "N."[!!(rdp->grpmask & rnp->expmaskinitnext)],
+++ ++++                                "D."[!!data_race(rdp->cpu_no_qs.b.exp)]);
+++ ++++                }
+++ ++++        }
+++ ++++        pr_cont(" } %lu jiffies s: %lu root: %#lx/%c\n",
+++ ++++                j - jiffies_start, rcu_state.expedited_sequence, data_race(rnp_root->expmask),
+++ ++++                ".T"[!!data_race(rnp_root->exp_tasks)]);
+++ ++++        if (ndetected) {
+++ ++++                pr_err("blocking rcu_node structures (internal RCU debug):");
+++ ++++                rcu_for_each_node_breadth_first(rnp) {
+++ ++++                        if (rnp == rnp_root)
+++ ++++                                continue; /* printed unconditionally */
+++ ++++                        if (sync_rcu_exp_done_unlocked(rnp))
+++ ++++                                continue;
+++ ++++                        pr_cont(" l=%u:%d-%d:%#lx/%c",
+++ ++++                                rnp->level, rnp->grplo, rnp->grphi, data_race(rnp->expmask),
+++ ++++                                ".T"[!!data_race(rnp->exp_tasks)]);
+++ ++++                }
+++ ++++                pr_cont("\n");
+++ ++++        }
+++ ++++        rcu_for_each_leaf_node(rnp) {
+++ ++++                for_each_leaf_node_possible_cpu(rnp, cpu) {
+++ ++++                        mask = leaf_node_cpu_bit(rnp, cpu);
+++ ++++                        if (!(READ_ONCE(rnp->expmask) & mask))
+++ ++++                                continue;
+++ ++++                        dump_cpu_task(cpu);
+++ ++++                }
+++ ++++                rcu_exp_print_detail_task_stall_rnp(rnp);
+++ ++++        }
+++ ++++}
+++ ++++
        /*
         * Wait for the expedited grace period to elapse, issuing any needed
         * RCU CPU stall warnings along the way.
@@@@@@@@@ -553,10 -553,10 -553,10 -614,8 -553,10 -553,10 -553,10 -553,10 +614,8 @@@@@@@@@ static void synchronize_rcu_expedited_w
                unsigned long jiffies_stall;
                unsigned long jiffies_start;
                unsigned long mask;
--- ----        int ndetected;
                struct rcu_data *rdp;
                struct rcu_node *rnp;
--- ----        struct rcu_node *rnp_root = rcu_get_root();
                unsigned long flags;
        
                trace_rcu_exp_grace_period(rcu_state.name, rcu_exp_gp_seq_endval(), TPS("startwait"));
                        j = jiffies;
                        rcu_stall_notifier_call_chain(RCU_STALL_NOTIFY_EXP, (void *)(j - jiffies_start));
                        trace_rcu_stall_warning(rcu_state.name, TPS("ExpeditedStall"));
--- ----                pr_err("INFO: %s detected expedited stalls on CPUs/tasks: {",
--- ----                       rcu_state.name);
--- ----                ndetected = 0;
--- ----                rcu_for_each_leaf_node(rnp) {
--- ----                        ndetected += rcu_print_task_exp_stall(rnp);
--- ----                        for_each_leaf_node_possible_cpu(rnp, cpu) {
--- ----                                struct rcu_data *rdp;
--- ----
--- ----                                mask = leaf_node_cpu_bit(rnp, cpu);
--- ----                                if (!(READ_ONCE(rnp->expmask) & mask))
--- ----                                        continue;
--- ----                                ndetected++;
--- ----                                rdp = per_cpu_ptr(&rcu_data, cpu);
--- ----                                pr_cont(" %d-%c%c%c%c", cpu,
--- ----                                        "O."[!!cpu_online(cpu)],
--- ----                                        "o."[!!(rdp->grpmask & rnp->expmaskinit)],
--- ----                                        "N."[!!(rdp->grpmask & rnp->expmaskinitnext)],
--- ----                                        "D."[!!data_race(rdp->cpu_no_qs.b.exp)]);
--- ----                        }
--- ----                }
--- ----                pr_cont(" } %lu jiffies s: %lu root: %#lx/%c\n",
--- ----                        j - jiffies_start, rcu_state.expedited_sequence,
--- ----                        data_race(rnp_root->expmask),
--- ----                        ".T"[!!data_race(rnp_root->exp_tasks)]);
--- ----                if (ndetected) {
--- ----                        pr_err("blocking rcu_node structures (internal RCU debug):");
--- ----                        rcu_for_each_node_breadth_first(rnp) {
--- ----                                if (rnp == rnp_root)
--- ----                                        continue; /* printed unconditionally */
--- ----                                if (sync_rcu_exp_done_unlocked(rnp))
--- ----                                        continue;
--- ----                                pr_cont(" l=%u:%d-%d:%#lx/%c",
--- ----                                        rnp->level, rnp->grplo, rnp->grphi,
--- ----                                        data_race(rnp->expmask),
--- ----                                        ".T"[!!data_race(rnp->exp_tasks)]);
--- ----                        }
--- ----                        pr_cont("\n");
--- ----                }
--- ----                rcu_for_each_leaf_node(rnp) {
--- ----                        for_each_leaf_node_possible_cpu(rnp, cpu) {
--- ----                                mask = leaf_node_cpu_bit(rnp, cpu);
--- ----                                if (!(READ_ONCE(rnp->expmask) & mask))
--- ----                                        continue;
--- ----                                preempt_disable(); // For smp_processor_id() in dump_cpu_task().
--- ----                                dump_cpu_task(cpu);
--- ----                                preempt_enable();
--- ----                        }
--- ----                        rcu_exp_print_detail_task_stall_rnp(rnp);
--- ----                }
+++ ++++                synchronize_rcu_expedited_stall(jiffies_start, j);
                        jiffies_stall = 3 * rcu_exp_jiffies_till_stall_check() + 3;
                        panic_on_rcu_stall();
                }
diff --combined kernel/rcu/tree_nocb.h
index e629646ac6f52fe9cd311c9d1805122c342f7730,4ffb8c90d6955a810dbc24e6520b50548f24fb95,3ce30841119ade393f00a9245e0922f1a2159b50,3ce30841119ade393f00a9245e0922f1a2159b50,3ce30841119ade393f00a9245e0922f1a2159b50,3ce30841119ade393f00a9245e0922f1a2159b50,3ce30841119ade393f00a9245e0922f1a2159b50,3ce30841119ade393f00a9245e0922f1a2159b50..97b99cd0692323eda39013951ed4e01eb9382a11
        #ifdef CONFIG_RCU_NOCB_CPU
        static cpumask_var_t rcu_nocb_mask; /* CPUs to have callbacks offloaded. */
        static bool __read_mostly rcu_nocb_poll;    /* Offload kthread are to poll. */
- ------static inline int rcu_lockdep_is_held_nocb(struct rcu_data *rdp)
- ------{
- ------        return lockdep_is_held(&rdp->nocb_lock);
- ------}
        
        static inline bool rcu_current_is_nocb_kthread(struct rcu_data *rdp)
        {
@@@@@@@@@ -220,7 -216,7 -220,7 -220,7 -220,7 -220,7 -220,7 -220,7 +216,7 @@@@@@@@@ static bool __wake_nocb_gp(struct rcu_d
                raw_spin_unlock_irqrestore(&rdp_gp->nocb_gp_lock, flags);
                if (needwake) {
                        trace_rcu_nocb_wake(rcu_state.name, rdp->cpu, TPS("DoWake"));
- ------                wake_up_process(rdp_gp->nocb_gp_kthread);
+ ++++++                swake_up_one_online(&rdp_gp->nocb_gp_wq);
                }
        
                return needwake;
@@@@@@@@@ -413,14 -409,6 -413,14 -413,14 -413,14 -413,14 -413,14 -413,14 +409,6 @@@@@@@@@ static bool rcu_nocb_try_bypass(struct 
                        return false;
                }
        
- ------        // In the process of (de-)offloading: no bypassing, but
- ------        // locking.
- ------        if (!rcu_segcblist_completely_offloaded(&rdp->cblist)) {
- ------                rcu_nocb_lock(rdp);
- ------                *was_alldone = !rcu_segcblist_pend_cbs(&rdp->cblist);
- ------                return false; /* Not offloaded, no bypassing. */
- ------        }
- ------
                // Don't use ->nocb_bypass during early boot.
                if (rcu_scheduler_active != RCU_SCHEDULER_RUNNING) {
                        rcu_nocb_lock(rdp);
                        trace_rcu_nocb_wake(rcu_state.name, rdp->cpu, TPS("FirstBQ"));
                }
                rcu_nocb_bypass_unlock(rdp);
- ------        smp_mb(); /* Order enqueue before wake. */
+ ++++++
                // A wake up of the grace period kthread or timer adjustment
                // needs to be done only if:
                // 1. Bypass list was fully empty before (this is the first
@@@@@@@@@ -616,37 -604,33 -616,37 -616,37 -616,37 -616,37 -616,37 -616,37 +604,33 @@@@@@@@@ static void call_rcu_nocb(struct rcu_da
                }
        }
        
- ------static int nocb_gp_toggle_rdp(struct rcu_data *rdp)
+ ++++++static void nocb_gp_toggle_rdp(struct rcu_data *rdp_gp, struct rcu_data *rdp)
        {
                struct rcu_segcblist *cblist = &rdp->cblist;
                unsigned long flags;
- ------        int ret;
        
- ------        rcu_nocb_lock_irqsave(rdp, flags);
- ------        if (rcu_segcblist_test_flags(cblist, SEGCBLIST_OFFLOADED) &&
- ------            !rcu_segcblist_test_flags(cblist, SEGCBLIST_KTHREAD_GP)) {
+ ++++++        /*
+ ++++++         * Locking orders future de-offloaded callbacks enqueue against previous
+ ++++++         * handling of this rdp. Ie: Make sure rcuog is done with this rdp before
+ ++++++         * deoffloaded callbacks can be enqueued.
+ ++++++         */
+ ++++++        raw_spin_lock_irqsave(&rdp->nocb_lock, flags);
+ ++++++        if (!rcu_segcblist_test_flags(cblist, SEGCBLIST_OFFLOADED)) {
                        /*
                         * Offloading. Set our flag and notify the offload worker.
                         * We will handle this rdp until it ever gets de-offloaded.
                         */
- ------                rcu_segcblist_set_flags(cblist, SEGCBLIST_KTHREAD_GP);
- ------                ret = 1;
- ------        } else if (!rcu_segcblist_test_flags(cblist, SEGCBLIST_OFFLOADED) &&
- ------                   rcu_segcblist_test_flags(cblist, SEGCBLIST_KTHREAD_GP)) {
+ ++++++                list_add_tail(&rdp->nocb_entry_rdp, &rdp_gp->nocb_head_rdp);
+ ++++++                rcu_segcblist_set_flags(cblist, SEGCBLIST_OFFLOADED);
+ ++++++        } else {
                        /*
                         * De-offloading. Clear our flag and notify the de-offload worker.
                         * We will ignore this rdp until it ever gets re-offloaded.
                         */
- ------                rcu_segcblist_clear_flags(cblist, SEGCBLIST_KTHREAD_GP);
- ------                ret = 0;
- ------        } else {
- ------                WARN_ON_ONCE(1);
- ------                ret = -1;
+ ++++++                list_del(&rdp->nocb_entry_rdp);
+ ++++++                rcu_segcblist_clear_flags(cblist, SEGCBLIST_OFFLOADED);
                }
- ------
- ------        rcu_nocb_unlock_irqrestore(rdp, flags);
- ------
- ------        return ret;
+ ++++++        raw_spin_unlock_irqrestore(&rdp->nocb_lock, flags);
        }
        
        static void nocb_gp_sleep(struct rcu_data *my_rdp, int cpu)
@@@@@@@@@ -853,14 -837,7 -853,14 -853,14 -853,14 -853,14 -853,14 -853,14 +837,7 @@@@@@@@@ static void nocb_gp_wait(struct rcu_dat
                }
        
                if (rdp_toggling) {
- ------                int ret;
- ------
- ------                ret = nocb_gp_toggle_rdp(rdp_toggling);
- ------                if (ret == 1)
- ------                        list_add_tail(&rdp_toggling->nocb_entry_rdp, &my_rdp->nocb_head_rdp);
- ------                else if (ret == 0)
- ------                        list_del(&rdp_toggling->nocb_entry_rdp);
- ------
+ ++++++                nocb_gp_toggle_rdp(my_rdp, rdp_toggling);
                        swake_up_one(&rdp_toggling->nocb_state_wq);
                }
        
@@@@@@@@@ -917,7 -894,7 -917,7 -917,7 -917,7 -917,7 -917,7 -917,7 +894,7 @@@@@@@@@ static void nocb_cb_wait(struct rcu_dat
                WARN_ON_ONCE(!rcu_rdp_is_offloaded(rdp));
        
                local_irq_save(flags);
 -------        rcu_momentary_dyntick_idle();
 +++++++        rcu_momentary_eqs();
                local_irq_restore(flags);
                /*
                 * Disable BH to provide the expected environment.  Also, when
@@@@@@@@@ -1030,16 -1007,11 -1030,16 -1030,16 -1030,16 -1030,16 -1030,16 -1030,16 +1007,11 @@@@@@@@@ void rcu_nocb_flush_deferred_wakeup(voi
        }
        EXPORT_SYMBOL_GPL(rcu_nocb_flush_deferred_wakeup);
        
- ------static int rdp_offload_toggle(struct rcu_data *rdp,
- ------                               bool offload, unsigned long flags)
- ------        __releases(rdp->nocb_lock)
+ ++++++static int rcu_nocb_queue_toggle_rdp(struct rcu_data *rdp)
        {
- ------        struct rcu_segcblist *cblist = &rdp->cblist;
                struct rcu_data *rdp_gp = rdp->nocb_gp_rdp;
                bool wake_gp = false;
- ------
- ------        rcu_segcblist_offload(cblist, offload);
- ------        rcu_nocb_unlock_irqrestore(rdp, flags);
+ ++++++        unsigned long flags;
        
                raw_spin_lock_irqsave(&rdp_gp->nocb_gp_lock, flags);
                // Queue this rdp for add/del to/from the list to iterate on rcuog
                return wake_gp;
        }
        
- ------static long rcu_nocb_rdp_deoffload(void *arg)
+ ++++++static bool rcu_nocb_rdp_deoffload_wait_cond(struct rcu_data *rdp)
        {
- ------        struct rcu_data *rdp = arg;
- ------        struct rcu_segcblist *cblist = &rdp->cblist;
                unsigned long flags;
- ------        int wake_gp;
- ------        struct rcu_data *rdp_gp = rdp->nocb_gp_rdp;
+ ++++++        bool ret;
        
                /*
- ------         * rcu_nocb_rdp_deoffload() may be called directly if
- ------         * rcuog/o[p] spawn failed, because at this time the rdp->cpu
- ------         * is not online yet.
+ ++++++         * Locking makes sure rcuog is done handling this rdp before deoffloaded
+ ++++++         * enqueue can happen. Also it keeps the SEGCBLIST_OFFLOADED flag stable
+ ++++++         * while the ->nocb_lock is held.
                 */
- ------        WARN_ON_ONCE((rdp->cpu != raw_smp_processor_id()) && cpu_online(rdp->cpu));
+ ++++++        raw_spin_lock_irqsave(&rdp->nocb_lock, flags);
+ ++++++        ret = !rcu_segcblist_test_flags(&rdp->cblist, SEGCBLIST_OFFLOADED);
+ ++++++        raw_spin_unlock_irqrestore(&rdp->nocb_lock, flags);
+ ++++++
+ ++++++        return ret;
+ ++++++}
+ ++++++
+ ++++++static int rcu_nocb_rdp_deoffload(struct rcu_data *rdp)
+ ++++++{
+ ++++++        unsigned long flags;
+ ++++++        int wake_gp;
+ ++++++        struct rcu_data *rdp_gp = rdp->nocb_gp_rdp;
+ ++++++
+ ++++++        /* CPU must be offline, unless it's early boot */
+ ++++++        WARN_ON_ONCE(cpu_online(rdp->cpu) && rdp->cpu != raw_smp_processor_id());
        
                pr_info("De-offloading %d\n", rdp->cpu);
        
- ------        rcu_nocb_lock_irqsave(rdp, flags);
- ------        /*
- ------         * Flush once and for all now. This suffices because we are
- ------         * running on the target CPU holding ->nocb_lock (thus having
- ------         * interrupts disabled), and because rdp_offload_toggle()
- ------         * invokes rcu_segcblist_offload(), which clears SEGCBLIST_OFFLOADED.
- ------         * Thus future calls to rcu_segcblist_completely_offloaded() will
- ------         * return false, which means that future calls to rcu_nocb_try_bypass()
- ------         * will refuse to put anything into the bypass.
- ------         */
- ------        WARN_ON_ONCE(!rcu_nocb_flush_bypass(rdp, NULL, jiffies, false));
+ ++++++        /* Flush all callbacks from segcblist and bypass */
+ ++++++        rcu_barrier();
+ ++++++
                /*
- ------         * Start with invoking rcu_core() early. This way if the current thread
- ------         * happens to preempt an ongoing call to rcu_core() in the middle,
- ------         * leaving some work dismissed because rcu_core() still thinks the rdp is
- ------         * completely offloaded, we are guaranteed a nearby future instance of
- ------         * rcu_core() to catch up.
+ ++++++         * Make sure the rcuoc kthread isn't in the middle of a nocb locked
+ ++++++         * sequence while offloading is deactivated, along with nocb locking.
                 */
- ------        rcu_segcblist_set_flags(cblist, SEGCBLIST_RCU_CORE);
- ------        invoke_rcu_core();
- ------        wake_gp = rdp_offload_toggle(rdp, false, flags);
+ ++++++        if (rdp->nocb_cb_kthread)
+ ++++++                kthread_park(rdp->nocb_cb_kthread);
+ ++++++
+ ++++++        rcu_nocb_lock_irqsave(rdp, flags);
+ ++++++        WARN_ON_ONCE(rcu_cblist_n_cbs(&rdp->nocb_bypass));
+ ++++++        WARN_ON_ONCE(rcu_segcblist_n_cbs(&rdp->cblist));
+ ++++++        rcu_nocb_unlock_irqrestore(rdp, flags);
+ ++++++
+ ++++++        wake_gp = rcu_nocb_queue_toggle_rdp(rdp);
        
                mutex_lock(&rdp_gp->nocb_gp_kthread_mutex);
+ ++++++
                if (rdp_gp->nocb_gp_kthread) {
                        if (wake_gp)
                                wake_up_process(rdp_gp->nocb_gp_kthread);
        
                        swait_event_exclusive(rdp->nocb_state_wq,
- ------                                      !rcu_segcblist_test_flags(cblist,
- ------                                                                SEGCBLIST_KTHREAD_GP));
- ------                if (rdp->nocb_cb_kthread)
- ------                        kthread_park(rdp->nocb_cb_kthread);
+ ++++++                                      rcu_nocb_rdp_deoffload_wait_cond(rdp));
                } else {
                        /*
                         * No kthread to clear the flags for us or remove the rdp from the nocb list
                         * to iterate. Do it here instead. Locking doesn't look stricly necessary
                         * but we stick to paranoia in this rare path.
                         */
- ------                rcu_nocb_lock_irqsave(rdp, flags);
- ------                rcu_segcblist_clear_flags(&rdp->cblist, SEGCBLIST_KTHREAD_GP);
- ------                rcu_nocb_unlock_irqrestore(rdp, flags);
+ ++++++                raw_spin_lock_irqsave(&rdp->nocb_lock, flags);
+ ++++++                rcu_segcblist_clear_flags(&rdp->cblist, SEGCBLIST_OFFLOADED);
+ ++++++                raw_spin_unlock_irqrestore(&rdp->nocb_lock, flags);
        
                        list_del(&rdp->nocb_entry_rdp);
                }
- ------        mutex_unlock(&rdp_gp->nocb_gp_kthread_mutex);
- ------
- ------        /*
- ------         * Lock one last time to acquire latest callback updates from kthreads
- ------         * so we can later handle callbacks locally without locking.
- ------         */
- ------        rcu_nocb_lock_irqsave(rdp, flags);
- ------        /*
- ------         * Theoretically we could clear SEGCBLIST_LOCKING after the nocb
- ------         * lock is released but how about being paranoid for once?
- ------         */
- ------        rcu_segcblist_clear_flags(cblist, SEGCBLIST_LOCKING);
- ------        /*
- ------         * Without SEGCBLIST_LOCKING, we can't use
- ------         * rcu_nocb_unlock_irqrestore() anymore.
- ------         */
- ------        raw_spin_unlock_irqrestore(&rdp->nocb_lock, flags);
- ------
- ------        /* Sanity check */
- ------        WARN_ON_ONCE(rcu_cblist_n_cbs(&rdp->nocb_bypass));
        
+ ++++++        mutex_unlock(&rdp_gp->nocb_gp_kthread_mutex);
        
                return 0;
        }
@@@@@@@@@ -1145,33 -1102,42 -1145,33 -1145,33 -1145,33 -1145,33 -1145,33 -1145,33 +1102,42 @@@@@@@@@ int rcu_nocb_cpu_deoffload(int cpu
                int ret = 0;
        
                cpus_read_lock();
- ------        mutex_lock(&rcu_state.barrier_mutex);
+ ++++++        mutex_lock(&rcu_state.nocb_mutex);
                if (rcu_rdp_is_offloaded(rdp)) {
- ------                if (cpu_online(cpu)) {
- ------                        ret = work_on_cpu(cpu, rcu_nocb_rdp_deoffload, rdp);
+ ++++++                if (!cpu_online(cpu)) {
+ ++++++                        ret = rcu_nocb_rdp_deoffload(rdp);
                                if (!ret)
                                        cpumask_clear_cpu(cpu, rcu_nocb_mask);
                        } else {
- ------                        pr_info("NOCB: Cannot CB-deoffload offline CPU %d\n", rdp->cpu);
+ ++++++                        pr_info("NOCB: Cannot CB-deoffload online CPU %d\n", rdp->cpu);
                                ret = -EINVAL;
                        }
                }
- ------        mutex_unlock(&rcu_state.barrier_mutex);
+ ++++++        mutex_unlock(&rcu_state.nocb_mutex);
                cpus_read_unlock();
        
                return ret;
        }
        EXPORT_SYMBOL_GPL(rcu_nocb_cpu_deoffload);
        
- ------static long rcu_nocb_rdp_offload(void *arg)
+ ++++++static bool rcu_nocb_rdp_offload_wait_cond(struct rcu_data *rdp)
        {
- ------        struct rcu_data *rdp = arg;
- ------        struct rcu_segcblist *cblist = &rdp->cblist;
                unsigned long flags;
+ ++++++        bool ret;
+ ++++++
+ ++++++        raw_spin_lock_irqsave(&rdp->nocb_lock, flags);
+ ++++++        ret = rcu_segcblist_test_flags(&rdp->cblist, SEGCBLIST_OFFLOADED);
+ ++++++        raw_spin_unlock_irqrestore(&rdp->nocb_lock, flags);
+ ++++++
+ ++++++        return ret;
+ ++++++}
+ ++++++
+ ++++++static int rcu_nocb_rdp_offload(struct rcu_data *rdp)
+ ++++++{
                int wake_gp;
                struct rcu_data *rdp_gp = rdp->nocb_gp_rdp;
        
- ------        WARN_ON_ONCE(rdp->cpu != raw_smp_processor_id());
+ ++++++        WARN_ON_ONCE(cpu_online(rdp->cpu));
                /*
                 * For now we only support re-offload, ie: the rdp must have been
                 * offloaded on boot first.
        
                pr_info("Offloading %d\n", rdp->cpu);
        
- ------        /*
- ------         * Can't use rcu_nocb_lock_irqsave() before SEGCBLIST_LOCKING
- ------         * is set.
- ------         */
- ------        raw_spin_lock_irqsave(&rdp->nocb_lock, flags);
+ ++++++        WARN_ON_ONCE(rcu_cblist_n_cbs(&rdp->nocb_bypass));
+ ++++++        WARN_ON_ONCE(rcu_segcblist_n_cbs(&rdp->cblist));
        
- ------        /*
- ------         * We didn't take the nocb lock while working on the
- ------         * rdp->cblist with SEGCBLIST_LOCKING cleared (pure softirq/rcuc mode).
- ------         * Every modifications that have been done previously on
- ------         * rdp->cblist must be visible remotely by the nocb kthreads
- ------         * upon wake up after reading the cblist flags.
- ------         *
- ------         * The layout against nocb_lock enforces that ordering:
- ------         *
- ------         *  __rcu_nocb_rdp_offload()   nocb_cb_wait()/nocb_gp_wait()
- ------         * -------------------------   ----------------------------
- ------         *      WRITE callbacks           rcu_nocb_lock()
- ------         *      rcu_nocb_lock()           READ flags
- ------         *      WRITE flags               READ callbacks
- ------         *      rcu_nocb_unlock()         rcu_nocb_unlock()
- ------         */
- ------        wake_gp = rdp_offload_toggle(rdp, true, flags);
+ ++++++        wake_gp = rcu_nocb_queue_toggle_rdp(rdp);
                if (wake_gp)
                        wake_up_process(rdp_gp->nocb_gp_kthread);
        
- ------        kthread_unpark(rdp->nocb_cb_kthread);
- ------
                swait_event_exclusive(rdp->nocb_state_wq,
- ------                              rcu_segcblist_test_flags(cblist, SEGCBLIST_KTHREAD_GP));
+ ++++++                              rcu_nocb_rdp_offload_wait_cond(rdp));
        
- ------        /*
- ------         * All kthreads are ready to work, we can finally relieve rcu_core() and
- ------         * enable nocb bypass.
- ------         */
- ------        rcu_nocb_lock_irqsave(rdp, flags);
- ------        rcu_segcblist_clear_flags(cblist, SEGCBLIST_RCU_CORE);
- ------        rcu_nocb_unlock_irqrestore(rdp, flags);
+ ++++++        kthread_unpark(rdp->nocb_cb_kthread);
        
                return 0;
        }
@@@@@@@@@ -1232,18 -1171,18 -1232,18 -1232,18 -1232,18 -1232,18 -1232,18 -1232,18 +1171,18 @@@@@@@@@ int rcu_nocb_cpu_offload(int cpu
                int ret = 0;
        
                cpus_read_lock();
- ------        mutex_lock(&rcu_state.barrier_mutex);
+ ++++++        mutex_lock(&rcu_state.nocb_mutex);
                if (!rcu_rdp_is_offloaded(rdp)) {
- ------                if (cpu_online(cpu)) {
- ------                        ret = work_on_cpu(cpu, rcu_nocb_rdp_offload, rdp);
+ ++++++                if (!cpu_online(cpu)) {
+ ++++++                        ret = rcu_nocb_rdp_offload(rdp);
                                if (!ret)
                                        cpumask_set_cpu(cpu, rcu_nocb_mask);
                        } else {
- ------                        pr_info("NOCB: Cannot CB-offload offline CPU %d\n", rdp->cpu);
+ ++++++                        pr_info("NOCB: Cannot CB-offload online CPU %d\n", rdp->cpu);
                                ret = -EINVAL;
                        }
                }
- ------        mutex_unlock(&rcu_state.barrier_mutex);
+ ++++++        mutex_unlock(&rcu_state.nocb_mutex);
                cpus_read_unlock();
        
                return ret;
@@@@@@@@@ -1261,7 -1200,7 -1261,7 -1261,7 -1261,7 -1261,7 -1261,7 -1261,7 +1200,7 @@@@@@@@@ lazy_rcu_shrink_count(struct shrinker *
                        return 0;
        
                /*  Protect rcu_nocb_mask against concurrent (de-)offloading. */
- ------        if (!mutex_trylock(&rcu_state.barrier_mutex))
+ ++++++        if (!mutex_trylock(&rcu_state.nocb_mutex))
                        return 0;
        
                /* Snapshot count of all CPUs */
                        count +=  READ_ONCE(rdp->lazy_len);
                }
        
- ------        mutex_unlock(&rcu_state.barrier_mutex);
+ ++++++        mutex_unlock(&rcu_state.nocb_mutex);
        
                return count ? count : SHRINK_EMPTY;
        }
@@@@@@@@@ -1289,9 -1228,9 -1289,9 -1289,9 -1289,9 -1289,9 -1289,9 -1289,9 +1228,9 @@@@@@@@@ lazy_rcu_shrink_scan(struct shrinker *s
                 * Protect against concurrent (de-)offloading. Otherwise nocb locking
                 * may be ignored or imbalanced.
                 */
- ------        if (!mutex_trylock(&rcu_state.barrier_mutex)) {
+ ++++++        if (!mutex_trylock(&rcu_state.nocb_mutex)) {
                        /*
- ------                 * But really don't insist if barrier_mutex is contended since we
+ ++++++                 * But really don't insist if nocb_mutex is contended since we
                         * can't guarantee that it will never engage in a dependency
                         * chain involving memory allocation. The lock is seldom contended
                         * anyway.
                                break;
                }
        
- ------        mutex_unlock(&rcu_state.barrier_mutex);
+ ++++++        mutex_unlock(&rcu_state.nocb_mutex);
        
                return count ? count : SHRINK_STOP;
        }
@@@@@@@@@ -1396,9 -1335,7 -1396,9 -1396,9 -1396,9 -1396,9 -1396,9 -1396,9 +1335,7 @@@@@@@@@ void __init rcu_init_nohz(void
                        rdp = per_cpu_ptr(&rcu_data, cpu);
                        if (rcu_segcblist_empty(&rdp->cblist))
                                rcu_segcblist_init(&rdp->cblist);
- ------                rcu_segcblist_offload(&rdp->cblist, true);
- ------                rcu_segcblist_set_flags(&rdp->cblist, SEGCBLIST_KTHREAD_GP);
- ------                rcu_segcblist_clear_flags(&rdp->cblist, SEGCBLIST_RCU_CORE);
+ ++++++                rcu_segcblist_set_flags(&rdp->cblist, SEGCBLIST_OFFLOADED);
                }
                rcu_organize_nocb_kthreads();
        }
@@@@@@@@@ -1446,7 -1383,7 -1446,7 -1446,7 -1446,7 -1446,7 -1446,7 -1446,7 +1383,7 @@@@@@@@@ static void rcu_spawn_cpu_nocb_kthread(
                                        "rcuog/%d", rdp_gp->cpu);
                        if (WARN_ONCE(IS_ERR(t), "%s: Could not start rcuo GP kthread, OOM is now expected behavior\n", __func__)) {
                                mutex_unlock(&rdp_gp->nocb_gp_kthread_mutex);
- ------                        goto end;
+ ++++++                        goto err;
                        }
                        WRITE_ONCE(rdp_gp->nocb_gp_kthread, t);
                        if (kthread_prio)
                t = kthread_create(rcu_nocb_cb_kthread, rdp,
                                   "rcuo%c/%d", rcu_state.abbr, cpu);
                if (WARN_ONCE(IS_ERR(t), "%s: Could not start rcuo CB kthread, OOM is now expected behavior\n", __func__))
- ------                goto end;
+ ++++++                goto err;
        
                if (rcu_rdp_is_offloaded(rdp))
                        wake_up_process(t);
                WRITE_ONCE(rdp->nocb_cb_kthread, t);
                WRITE_ONCE(rdp->nocb_gp_kthread, rdp_gp->nocb_gp_kthread);
                return;
- ------end:
- ------        mutex_lock(&rcu_state.barrier_mutex);
+ ++++++
+ ++++++err:
+ ++++++        /*
+ ++++++         * No need to protect against concurrent rcu_barrier()
+ ++++++         * because the number of callbacks should be 0 for a non-boot CPU,
+ ++++++         * therefore rcu_barrier() shouldn't even try to grab the nocb_lock.
+ ++++++         * But hold nocb_mutex to avoid nocb_lock imbalance from shrinker.
+ ++++++         */
+ ++++++        WARN_ON_ONCE(system_state > SYSTEM_BOOTING && rcu_segcblist_n_cbs(&rdp->cblist));
+ ++++++        mutex_lock(&rcu_state.nocb_mutex);
                if (rcu_rdp_is_offloaded(rdp)) {
                        rcu_nocb_rdp_deoffload(rdp);
                        cpumask_clear_cpu(cpu, rcu_nocb_mask);
                }
- ------        mutex_unlock(&rcu_state.barrier_mutex);
+ ++++++        mutex_unlock(&rcu_state.nocb_mutex);
        }
        
        /* How many CB CPU IDs per GP kthread?  Default of -1 for sqrt(nr_cpu_ids). */
@@@@@@@@@ -1653,16 -1598,6 -1653,16 -1653,16 -1653,16 -1653,16 -1653,16 -1653,16 +1598,6 @@@@@@@@@ static void show_rcu_nocb_state(struct 
        
        #else /* #ifdef CONFIG_RCU_NOCB_CPU */
        
- ------static inline int rcu_lockdep_is_held_nocb(struct rcu_data *rdp)
- ------{
- ------        return 0;
- ------}
- ------
- ------static inline bool rcu_current_is_nocb_kthread(struct rcu_data *rdp)
- ------{
- ------        return false;
- ------}
- ------
        /* No ->nocb_lock to acquire.  */
        static void rcu_nocb_lock(struct rcu_data *rdp)
        {
diff --combined kernel/rcu/tree_plugin.h
index 354fbf2e411cef92359ca85cacbc880de9be4dcd,c662376c8af0a952055b63bad6fb35a937c9556a,c569da65b42157915d8cacba011cca3cab726238,c569da65b42157915d8cacba011cca3cab726238,c569da65b42157915d8cacba011cca3cab726238,c569da65b42157915d8cacba011cca3cab726238,c569da65b42157915d8cacba011cca3cab726238,c569da65b42157915d8cacba011cca3cab726238..1c7cbd145d5e3766c1cfd67e99ffb8a69ce8adc5
@@@@@@@@@ -24,10 -24,11 -24,10 -24,10 -24,10 -24,10 -24,10 -24,10 +24,11 @@@@@@@@@ static bool rcu_rdp_is_offloaded(struc
                 * timers have their own means of synchronization against the
                 * offloaded state updaters.
                 */
- ------        RCU_LOCKDEP_WARN(
+ ++++++        RCU_NOCB_LOCKDEP_WARN(
                        !(lockdep_is_held(&rcu_state.barrier_mutex) ||
                          (IS_ENABLED(CONFIG_HOTPLUG_CPU) && lockdep_is_cpus_held()) ||
- ------                  rcu_lockdep_is_held_nocb(rdp) ||
+ ++++++                  lockdep_is_held(&rdp->nocb_lock) ||
+ ++++++                  lockdep_is_held(&rcu_state.nocb_mutex) ||
                          (!(IS_ENABLED(CONFIG_PREEMPT_COUNT) && preemptible()) &&
                           rdp == this_cpu_ptr(&rcu_data)) ||
                          rcu_current_is_nocb_kthread(rdp)),
@@@@@@@@@ -869,7 -870,7 -869,7 -869,7 -869,7 -869,7 -869,7 -869,7 +870,7 @@@@@@@@@ static void rcu_qs(void
        
        /*
         * Register an urgently needed quiescent state.  If there is an
 ------- * emergency, invoke rcu_momentary_dyntick_idle() to do a heavy-weight
 +++++++ * emergency, invoke rcu_momentary_eqs() to do a heavy-weight
         * dyntick-idle quiescent state visible to other CPUs, which will in
         * some cases serve for expedited as well as normal grace periods.
         * Either way, register a lightweight quiescent state.
@@@@@@@@@ -889,7 -890,7 -889,7 -889,7 -889,7 -889,7 -889,7 -889,7 +890,7 @@@@@@@@@ void rcu_all_qs(void
                this_cpu_write(rcu_data.rcu_urgent_qs, false);
                if (unlikely(raw_cpu_read(rcu_data.rcu_need_heavy_qs))) {
                        local_irq_save(flags);
 -------                rcu_momentary_dyntick_idle();
 +++++++                rcu_momentary_eqs();
                        local_irq_restore(flags);
                }
                rcu_qs();
@@@@@@@@@ -909,7 -910,7 -909,7 -909,7 -909,7 -909,7 -909,7 -909,7 +910,7 @@@@@@@@@ void rcu_note_context_switch(bool preem
                        goto out;
                this_cpu_write(rcu_data.rcu_urgent_qs, false);
                if (unlikely(raw_cpu_read(rcu_data.rcu_need_heavy_qs)))
 -------                rcu_momentary_dyntick_idle();
 +++++++                rcu_momentary_eqs();
        out:
                rcu_tasks_qs(current, preempt);
                trace_rcu_utilization(TPS("End context switch"));
diff --combined kernel/rcu/tree_stall.h
index e933c6a58d5fd1985223bdad9af08ccd7cbc59bb,4b0e9d7c4c68ee029c72d7094c4be7dc3b0d1582,4b0e9d7c4c68ee029c72d7094c4be7dc3b0d1582,9772e1ffcf6e1e51d5cd9ad1c5041f4f833f0499,4b0e9d7c4c68ee029c72d7094c4be7dc3b0d1582,4b0e9d7c4c68ee029c72d7094c4be7dc3b0d1582,4b0e9d7c4c68ee029c72d7094c4be7dc3b0d1582,4b0e9d7c4c68ee029c72d7094c4be7dc3b0d1582..2fb40ec4b2aea38756bebca8e248dea69277dd39
@@@@@@@@@ -9,6 -9,6 -9,6 -9,7 -9,6 -9,6 -9,6 -9,6 +9,7 @@@@@@@@@
        
        #include <linux/kvm_para.h>
        #include <linux/rcu_notifier.h>
+++ ++++#include <linux/smp.h>
        
        //////////////////////////////////////////////////////////////////////////////
        //
@@@@@@@@@ -370,6 -370,6 -370,6 -371,7 -370,6 -370,6 -370,6 -370,6 +371,7 @@@@@@@@@ static void rcu_dump_cpu_stacks(void
                struct rcu_node *rnp;
        
                rcu_for_each_leaf_node(rnp) {
+++ ++++                printk_deferred_enter();
                        raw_spin_lock_irqsave_rcu_node(rnp, flags);
                        for_each_leaf_node_possible_cpu(rnp, cpu)
                                if (rnp->qsmask & leaf_node_cpu_bit(rnp, cpu)) {
                                                dump_cpu_task(cpu);
                                }
                        raw_spin_unlock_irqrestore_rcu_node(rnp, flags);
+++ ++++                printk_deferred_exit();
                }
        }
        
@@@@@@@@@ -501,7 -501,7 -501,7 -504,7 -501,7 -501,7 -501,7 -501,7 +504,7 @@@@@@@@@ static void print_cpu_stall_info(int cp
                }
                delta = rcu_seq_ctr(rdp->mynode->gp_seq - rdp->rcu_iw_gp_seq);
                falsepositive = rcu_is_gp_kthread_starving(NULL) &&
 -------                        rcu_dynticks_in_eqs(ct_dynticks_cpu(cpu));
 +++++++                        rcu_watching_snap_in_eqs(ct_rcu_watching_cpu(cpu));
                rcuc_starved = rcu_is_rcuc_kthread_starving(rdp, &j);
                if (rcuc_starved)
                        // Print signed value, as negative values indicate a probable bug.
                                rdp->rcu_iw_pending ? (int)min(delta, 9UL) + '0' :
                                        "!."[!delta],
                       ticks_value, ticks_title,
 -------               ct_dynticks_cpu(cpu) & 0xffff,
 -------               ct_dynticks_nesting_cpu(cpu), ct_dynticks_nmi_nesting_cpu(cpu),
 +++++++               ct_rcu_watching_cpu(cpu) & 0xffff,
 +++++++               ct_nesting_cpu(cpu), ct_nmi_nesting_cpu(cpu),
                       rdp->softirq_snap, kstat_softirqs_cpu(RCU_SOFTIRQ, cpu),
                       data_race(rcu_state.n_force_qs) - rcu_state.n_force_qs_gpstart,
                       rcuc_starved ? buf : "",
@@@@@@@@@ -719,6 -719,6 -719,6 -722,9 -719,6 -719,6 -719,6 -719,6 +722,9 @@@@@@@@@ static void print_cpu_stall(unsigned lo
                set_preempt_need_resched();
        }
        
+++ ++++static bool csd_lock_suppress_rcu_stall;
+++ ++++module_param(csd_lock_suppress_rcu_stall, bool, 0644);
+++ ++++
        static void check_cpu_stall(struct rcu_data *rdp)
        {
                bool self_detected;
                                return;
        
                        rcu_stall_notifier_call_chain(RCU_STALL_NOTIFY_NORM, (void *)j - gps);
--- ----                if (self_detected) {
+++ ++++                if (READ_ONCE(csd_lock_suppress_rcu_stall) && csd_lock_is_stuck()) {
+++ ++++                        pr_err("INFO: %s detected stall, but suppressed full report due to a stuck CSD-lock.\n", rcu_state.name);
+++ ++++                } else if (self_detected) {
                                /* We haven't checked in, so go dump stack. */
                                print_cpu_stall(gps);
                        } else {
diff --combined kernel/sched/core.c
index 93a845fe844982a6b5b28b660eefb54966aa38b0,a9f655025607b977a790adbc7f33b1265fce6636,a9f655025607b977a790adbc7f33b1265fce6636,78ae888a1fa2f314b03152b68408eb19bf2d8755,a9f655025607b977a790adbc7f33b1265fce6636,a9f655025607b977a790adbc7f33b1265fce6636,a9f655025607b977a790adbc7f33b1265fce6636,a9f655025607b977a790adbc7f33b1265fce6636..6569d036ddb48b80001a906bb0d071a8587a9418
@@@@@@@@@ -5762,7 -5762,7 -5762,7 -5762,7 -5762,7 -5762,7 -5762,7 -5762,7 +5762,7 @@@@@@@@@ static inline void schedule_debug(struc
                        preempt_count_set(PREEMPT_DISABLED);
                }
                rcu_sleep_check();
 -------        SCHED_WARN_ON(ct_state() == CONTEXT_USER);
 +++++++        SCHED_WARN_ON(ct_state() == CT_STATE_USER);
        
                profile_hit(SCHED_PROFILING, __builtin_return_address(0));
        
@@@@@@@@@ -6658,7 -6658,7 -6658,7 -6658,7 -6658,7 -6658,7 -6658,7 -6658,7 +6658,7 @@@@@@@@@ asmlinkage __visible void __sched sched
                 * we find a better solution.
                 *
                 * NB: There are buggy callers of this function.  Ideally we
 -------         * should warn if prev_state != CONTEXT_USER, but that will trigger
 +++++++         * should warn if prev_state != CT_STATE_USER, but that will trigger
                 * too frequently to make sense yet.
                 */
                enum ctx_state prev_state = exception_enter();
@@@@@@@@@ -9726,7 -9726,7 -9726,7 -9726,7 -9726,7 -9726,7 -9726,7 -9726,7 +9726,7 @@@@@@@@@ struct cgroup_subsys cpu_cgrp_subsys = 
        
        void dump_cpu_task(int cpu)
        {
--- ----        if (cpu == smp_processor_id() && in_hardirq()) {
+++ ++++        if (in_hardirq() && cpu == smp_processor_id()) {
                        struct pt_regs *regs;
        
                        regs = get_irq_regs();
This page took 0.266696 seconds and 4 git commands to generate.