Merge branches 'doc.2022.06.21a', 'fixes.2022.07.19a', 'nocb.2022.07.19a', 'poll...
[platform/kernel/linux-starfive.git] / kernel / rcu / rcutorture.c
index 2ba7449..d8e1b27 100644 (file)
@@ -75,62 +75,47 @@ MODULE_AUTHOR("Paul E. McKenney <paulmck@linux.ibm.com> and Josh Triplett <josh@
 
 torture_param(int, extendables, RCUTORTURE_MAX_EXTEND,
              "Extend readers by disabling bh (1), irqs (2), or preempt (4)");
-torture_param(int, fqs_duration, 0,
-             "Duration of fqs bursts (us), 0 to disable");
+torture_param(int, fqs_duration, 0, "Duration of fqs bursts (us), 0 to disable");
 torture_param(int, fqs_holdoff, 0, "Holdoff time within fqs bursts (us)");
 torture_param(int, fqs_stutter, 3, "Wait time between fqs bursts (s)");
-torture_param(int, fwd_progress, 1, "Test grace-period forward progress");
+torture_param(int, fwd_progress, 1, "Number of grace-period forward progress tasks (0 to disable)");
 torture_param(int, fwd_progress_div, 4, "Fraction of CPU stall to wait");
-torture_param(int, fwd_progress_holdoff, 60,
-             "Time between forward-progress tests (s)");
-torture_param(bool, fwd_progress_need_resched, 1,
-             "Hide cond_resched() behind need_resched()");
+torture_param(int, fwd_progress_holdoff, 60, "Time between forward-progress tests (s)");
+torture_param(bool, fwd_progress_need_resched, 1, "Hide cond_resched() behind need_resched()");
 torture_param(bool, gp_cond, false, "Use conditional/async GP wait primitives");
+torture_param(bool, gp_cond_exp, false, "Use conditional/async expedited GP wait primitives");
 torture_param(bool, gp_exp, false, "Use expedited GP wait primitives");
-torture_param(bool, gp_normal, false,
-            "Use normal (non-expedited) GP wait primitives");
+torture_param(bool, gp_normal, false, "Use normal (non-expedited) GP wait primitives");
 torture_param(bool, gp_poll, false, "Use polling GP wait primitives");
+torture_param(bool, gp_poll_exp, false, "Use polling expedited GP wait primitives");
 torture_param(bool, gp_sync, false, "Use synchronous GP wait primitives");
 torture_param(int, irqreader, 1, "Allow RCU readers from irq handlers");
 torture_param(int, leakpointer, 0, "Leak pointer dereferences from readers");
-torture_param(int, n_barrier_cbs, 0,
-            "# of callbacks/kthreads for barrier testing");
+torture_param(int, n_barrier_cbs, 0, "# of callbacks/kthreads for barrier testing");
 torture_param(int, nfakewriters, 4, "Number of RCU fake writer threads");
 torture_param(int, nreaders, -1, "Number of RCU reader threads");
-torture_param(int, object_debug, 0,
-            "Enable debug-object double call_rcu() testing");
+torture_param(int, object_debug, 0, "Enable debug-object double call_rcu() testing");
 torture_param(int, onoff_holdoff, 0, "Time after boot before CPU hotplugs (s)");
-torture_param(int, onoff_interval, 0,
-            "Time between CPU hotplugs (jiffies), 0=disable");
+torture_param(int, onoff_interval, 0, "Time between CPU hotplugs (jiffies), 0=disable");
 torture_param(int, nocbs_nthreads, 0, "Number of NOCB toggle threads, 0 to disable");
 torture_param(int, nocbs_toggle, 1000, "Time between toggling nocb state (ms)");
-torture_param(int, read_exit_delay, 13,
-             "Delay between read-then-exit episodes (s)");
-torture_param(int, read_exit_burst, 16,
-             "# of read-then-exit bursts per episode, zero to disable");
+torture_param(int, read_exit_delay, 13, "Delay between read-then-exit episodes (s)");
+torture_param(int, read_exit_burst, 16, "# of read-then-exit bursts per episode, zero to disable");
 torture_param(int, shuffle_interval, 3, "Number of seconds between shuffles");
 torture_param(int, shutdown_secs, 0, "Shutdown time (s), <= zero to disable.");
 torture_param(int, stall_cpu, 0, "Stall duration (s), zero to disable.");
-torture_param(int, stall_cpu_holdoff, 10,
-            "Time to wait before starting stall (s).");
-torture_param(bool, stall_no_softlockup, false,
-            "Avoid softlockup warning during cpu stall.");
+torture_param(int, stall_cpu_holdoff, 10, "Time to wait before starting stall (s).");
+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_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, 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");
 torture_param(int, test_boost, 1, "Test RCU prio boost: 0=no, 1=maybe, 2=yes.");
-torture_param(int, test_boost_duration, 4,
-            "Duration of each boost test, seconds.");
-torture_param(int, test_boost_interval, 7,
-            "Interval between boost tests, seconds.");
-torture_param(bool, test_no_idle_hz, true,
-            "Test support for tickless idle CPUs");
-torture_param(int, verbose, 1,
-            "Enable verbose debugging printk()s");
+torture_param(int, test_boost_duration, 4, "Duration of each boost test, seconds.");
+torture_param(int, test_boost_interval, 7, "Interval between boost tests, seconds.");
+torture_param(bool, test_no_idle_hz, true, "Test support for tickless idle CPUs");
+torture_param(int, verbose, 1, "Enable verbose debugging printk()s");
 
 static char *torture_type = "rcu";
 module_param(torture_type, charp, 0444);
@@ -209,12 +194,16 @@ static int rcu_torture_writer_state;
 #define RTWS_DEF_FREE          3
 #define RTWS_EXP_SYNC          4
 #define RTWS_COND_GET          5
-#define RTWS_COND_SYNC         6
-#define RTWS_POLL_GET          7
-#define RTWS_POLL_WAIT         8
-#define RTWS_SYNC              9
-#define RTWS_STUTTER           10
-#define RTWS_STOPPING          11
+#define RTWS_COND_GET_EXP      6
+#define RTWS_COND_SYNC         7
+#define RTWS_COND_SYNC_EXP     8
+#define RTWS_POLL_GET          9
+#define RTWS_POLL_GET_EXP      10
+#define RTWS_POLL_WAIT         11
+#define RTWS_POLL_WAIT_EXP     12
+#define RTWS_SYNC              13
+#define RTWS_STUTTER           14
+#define RTWS_STOPPING          15
 static const char * const rcu_torture_writer_state_names[] = {
        "RTWS_FIXED_DELAY",
        "RTWS_DELAY",
@@ -222,9 +211,13 @@ static const char * const rcu_torture_writer_state_names[] = {
        "RTWS_DEF_FREE",
        "RTWS_EXP_SYNC",
        "RTWS_COND_GET",
+       "RTWS_COND_GET_EXP",
        "RTWS_COND_SYNC",
+       "RTWS_COND_SYNC_EXP",
        "RTWS_POLL_GET",
+       "RTWS_POLL_GET_EXP",
        "RTWS_POLL_WAIT",
+       "RTWS_POLL_WAIT_EXP",
        "RTWS_SYNC",
        "RTWS_STUTTER",
        "RTWS_STOPPING",
@@ -337,7 +330,12 @@ struct rcu_torture_ops {
        void (*deferred_free)(struct rcu_torture *p);
        void (*sync)(void);
        void (*exp_sync)(void);
+       unsigned long (*get_gp_state_exp)(void);
+       unsigned long (*start_gp_poll_exp)(void);
+       bool (*poll_gp_state_exp)(unsigned long oldstate);
+       void (*cond_sync_exp)(unsigned long oldstate);
        unsigned long (*get_gp_state)(void);
+       unsigned long (*get_gp_completed)(void);
        unsigned long (*start_gp_poll)(void);
        bool (*poll_gp_state)(unsigned long oldstate);
        void (*cond_sync)(unsigned long oldstate);
@@ -504,9 +502,14 @@ static struct rcu_torture_ops rcu_ops = {
        .sync                   = synchronize_rcu,
        .exp_sync               = synchronize_rcu_expedited,
        .get_gp_state           = get_state_synchronize_rcu,
+       .get_gp_completed       = get_completed_synchronize_rcu,
        .start_gp_poll          = start_poll_synchronize_rcu,
        .poll_gp_state          = poll_state_synchronize_rcu,
        .cond_sync              = cond_synchronize_rcu,
+       .get_gp_state_exp       = get_state_synchronize_rcu,
+       .start_gp_poll_exp      = start_poll_synchronize_rcu_expedited,
+       .poll_gp_state_exp      = poll_state_synchronize_rcu,
+       .cond_sync_exp          = cond_synchronize_rcu_expedited,
        .call                   = call_rcu,
        .cb_barrier             = rcu_barrier,
        .fqs                    = rcu_force_quiescent_state,
@@ -1136,9 +1139,8 @@ rcu_torture_fqs(void *arg)
        return 0;
 }
 
-// Used by writers to randomly choose from the available grace-period
-// primitives.  The only purpose of the initialization is to size the array.
-static int synctype[] = { RTWS_DEF_FREE, RTWS_EXP_SYNC, RTWS_COND_GET, RTWS_POLL_GET, RTWS_SYNC };
+// Used by writers to randomly choose from the available grace-period primitives.
+static int synctype[ARRAY_SIZE(rcu_torture_writer_state_names)] = { };
 static int nsynctypes;
 
 /*
@@ -1146,18 +1148,27 @@ static int nsynctypes;
  */
 static void rcu_torture_write_types(void)
 {
-       bool gp_cond1 = gp_cond, gp_exp1 = gp_exp, gp_normal1 = gp_normal;
-       bool gp_poll1 = gp_poll, gp_sync1 = gp_sync;
+       bool gp_cond1 = gp_cond, gp_cond_exp1 = gp_cond_exp, gp_exp1 = gp_exp;
+       bool gp_poll_exp1 = gp_poll_exp, gp_normal1 = gp_normal, gp_poll1 = gp_poll;
+       bool gp_sync1 = gp_sync;
 
        /* Initialize synctype[] array.  If none set, take default. */
-       if (!gp_cond1 && !gp_exp1 && !gp_normal1 && !gp_poll1 && !gp_sync1)
-               gp_cond1 = gp_exp1 = gp_normal1 = gp_poll1 = gp_sync1 = true;
+       if (!gp_cond1 && !gp_cond_exp1 && !gp_exp1 && !gp_poll_exp &&
+           !gp_normal1 && !gp_poll1 && !gp_sync1)
+               gp_cond1 = gp_cond_exp1 = gp_exp1 = gp_poll_exp1 =
+                          gp_normal1 = gp_poll1 = gp_sync1 = true;
        if (gp_cond1 && cur_ops->get_gp_state && cur_ops->cond_sync) {
                synctype[nsynctypes++] = RTWS_COND_GET;
                pr_info("%s: Testing conditional GPs.\n", __func__);
        } else if (gp_cond && (!cur_ops->get_gp_state || !cur_ops->cond_sync)) {
                pr_alert("%s: gp_cond without primitives.\n", __func__);
        }
+       if (gp_cond_exp1 && cur_ops->get_gp_state_exp && cur_ops->cond_sync_exp) {
+               synctype[nsynctypes++] = RTWS_COND_GET_EXP;
+               pr_info("%s: Testing conditional expedited GPs.\n", __func__);
+       } else if (gp_cond_exp && (!cur_ops->get_gp_state_exp || !cur_ops->cond_sync_exp)) {
+               pr_alert("%s: gp_cond_exp without primitives.\n", __func__);
+       }
        if (gp_exp1 && cur_ops->exp_sync) {
                synctype[nsynctypes++] = RTWS_EXP_SYNC;
                pr_info("%s: Testing expedited GPs.\n", __func__);
@@ -1176,6 +1187,12 @@ static void rcu_torture_write_types(void)
        } else if (gp_poll && (!cur_ops->start_gp_poll || !cur_ops->poll_gp_state)) {
                pr_alert("%s: gp_poll without primitives.\n", __func__);
        }
+       if (gp_poll_exp1 && cur_ops->start_gp_poll_exp && cur_ops->poll_gp_state_exp) {
+               synctype[nsynctypes++] = RTWS_POLL_GET_EXP;
+               pr_info("%s: Testing polling expedited GPs.\n", __func__);
+       } else if (gp_poll_exp && (!cur_ops->start_gp_poll_exp || !cur_ops->poll_gp_state_exp)) {
+               pr_alert("%s: gp_poll_exp without primitives.\n", __func__);
+       }
        if (gp_sync1 && cur_ops->sync) {
                synctype[nsynctypes++] = RTWS_SYNC;
                pr_info("%s: Testing normal GPs.\n", __func__);
@@ -1254,6 +1271,10 @@ rcu_torture_writer(void *arg)
                                          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();
+                                       WARN_ON_ONCE(!cur_ops->poll_gp_state(cookie));
+                               }
                                cur_ops->readunlock(idx);
                        }
                        switch (synctype[torture_random(&rand) % nsynctypes]) {
@@ -1263,7 +1284,12 @@ rcu_torture_writer(void *arg)
                                break;
                        case RTWS_EXP_SYNC:
                                rcu_torture_writer_state = RTWS_EXP_SYNC;
+                               if (cur_ops->get_gp_state && cur_ops->poll_gp_state)
+                                       cookie = cur_ops->get_gp_state();
                                cur_ops->exp_sync();
+                               cur_ops->exp_sync();
+                               if (cur_ops->get_gp_state && cur_ops->poll_gp_state)
+                                       WARN_ON_ONCE(!cur_ops->poll_gp_state(cookie));
                                rcu_torture_pipe_update(old_rp);
                                break;
                        case RTWS_COND_GET:
@@ -1274,6 +1300,14 @@ rcu_torture_writer(void *arg)
                                cur_ops->cond_sync(gp_snap);
                                rcu_torture_pipe_update(old_rp);
                                break;
+                       case RTWS_COND_GET_EXP:
+                               rcu_torture_writer_state = RTWS_COND_GET_EXP;
+                               gp_snap = cur_ops->get_gp_state_exp();
+                               torture_hrtimeout_jiffies(torture_random(&rand) % 16, &rand);
+                               rcu_torture_writer_state = RTWS_COND_SYNC_EXP;
+                               cur_ops->cond_sync_exp(gp_snap);
+                               rcu_torture_pipe_update(old_rp);
+                               break;
                        case RTWS_POLL_GET:
                                rcu_torture_writer_state = RTWS_POLL_GET;
                                gp_snap = cur_ops->start_gp_poll();
@@ -1283,9 +1317,23 @@ rcu_torture_writer(void *arg)
                                                                  &rand);
                                rcu_torture_pipe_update(old_rp);
                                break;
+                       case RTWS_POLL_GET_EXP:
+                               rcu_torture_writer_state = RTWS_POLL_GET_EXP;
+                               gp_snap = cur_ops->start_gp_poll_exp();
+                               rcu_torture_writer_state = RTWS_POLL_WAIT_EXP;
+                               while (!cur_ops->poll_gp_state_exp(gp_snap))
+                                       torture_hrtimeout_jiffies(torture_random(&rand) % 16,
+                                                                 &rand);
+                               rcu_torture_pipe_update(old_rp);
+                               break;
                        case RTWS_SYNC:
                                rcu_torture_writer_state = RTWS_SYNC;
+                               if (cur_ops->get_gp_state && cur_ops->poll_gp_state)
+                                       cookie = cur_ops->get_gp_state();
+                               cur_ops->sync();
                                cur_ops->sync();
+                               if (cur_ops->get_gp_state && cur_ops->poll_gp_state)
+                                       WARN_ON_ONCE(!cur_ops->poll_gp_state(cookie));
                                rcu_torture_pipe_update(old_rp);
                                break;
                        default:
@@ -1385,6 +1433,11 @@ rcu_torture_fakewriter(void *arg)
                                torture_hrtimeout_jiffies(torture_random(&rand) % 16, &rand);
                                cur_ops->cond_sync(gp_snap);
                                break;
+                       case RTWS_COND_GET_EXP:
+                               gp_snap = cur_ops->get_gp_state_exp();
+                               torture_hrtimeout_jiffies(torture_random(&rand) % 16, &rand);
+                               cur_ops->cond_sync_exp(gp_snap);
+                               break;
                        case RTWS_POLL_GET:
                                gp_snap = cur_ops->start_gp_poll();
                                while (!cur_ops->poll_gp_state(gp_snap)) {
@@ -1392,6 +1445,13 @@ rcu_torture_fakewriter(void *arg)
                                                                  &rand);
                                }
                                break;
+                       case RTWS_POLL_GET_EXP:
+                               gp_snap = cur_ops->start_gp_poll_exp();
+                               while (!cur_ops->poll_gp_state_exp(gp_snap)) {
+                                       torture_hrtimeout_jiffies(torture_random(&rand) % 16,
+                                                                 &rand);
+                               }
+                               break;
                        case RTWS_SYNC:
                                cur_ops->sync();
                                break;