rcu: make rcutorture more vicious: add stutter feature
[firefly-linux-kernel-4.4.55.git] / kernel / rcutorture.c
index 0ca7e9b290b06d55fabdc82ff8c44e18e9bd1ccd..98ae7d1682252f300d3aca7bb9cdf4348934d373 100644 (file)
@@ -57,7 +57,8 @@ static int stat_interval;     /* Interval between stats, in seconds. */
                                /*  Defaults to "only at end of test". */
 static int verbose;            /* Print more debug info. */
 static int test_no_idle_hz;    /* Test RCU's support for tickless idle CPUs. */
-static int shuffle_interval = 5; /* Interval between shuffles (in sec)*/
+static int shuffle_interval = 3; /* Interval between shuffles (in sec)*/
+static int stutter = 5;                /* Start/stop testing interval (in sec) */
 static char *torture_type = "rcu"; /* What RCU implementation to torture. */
 
 module_param(nreaders, int, 0444);
@@ -72,6 +73,8 @@ module_param(test_no_idle_hz, bool, 0444);
 MODULE_PARM_DESC(test_no_idle_hz, "Test support for tickless idle CPUs");
 module_param(shuffle_interval, int, 0444);
 MODULE_PARM_DESC(shuffle_interval, "Number of seconds between shuffles");
+module_param(stutter, int, 0444);
+MODULE_PARM_DESC(stutter, "Number of seconds to run/halt test");
 module_param(torture_type, charp, 0444);
 MODULE_PARM_DESC(torture_type, "Type of RCU to torture (rcu, rcu_bh, srcu)");
 
@@ -91,6 +94,7 @@ static struct task_struct **fakewriter_tasks;
 static struct task_struct **reader_tasks;
 static struct task_struct *stats_task;
 static struct task_struct *shuffler_task;
+static struct task_struct *stutter_task;
 
 #define RCU_TORTURE_PIPE_LEN 10
 
@@ -119,6 +123,8 @@ static atomic_t n_rcu_torture_mberror;
 static atomic_t n_rcu_torture_error;
 static struct list_head rcu_torture_removed;
 
+static int stutter_pause_test = 0;
+
 /*
  * Allocate an element from the rcu_tortures pool.
  */
@@ -179,6 +185,13 @@ rcu_random(struct rcu_random_state *rrsp)
        return swahw32(rrsp->rrs_state);
 }
 
+static void
+rcu_stutter_wait(void)
+{
+       while (stutter_pause_test)
+               schedule_timeout_interruptible(1);
+}
+
 /*
  * Operations vector for selecting different types of tests.
  */
@@ -563,6 +576,7 @@ rcu_torture_writer(void *arg)
                }
                rcu_torture_current_version++;
                oldbatch = cur_ops->completed();
+               rcu_stutter_wait();
        } while (!kthread_should_stop() && !fullstop);
        VERBOSE_PRINTK_STRING("rcu_torture_writer task stopping");
        while (!kthread_should_stop())
@@ -586,6 +600,7 @@ rcu_torture_fakewriter(void *arg)
                schedule_timeout_uninterruptible(1 + rcu_random(&rand)%10);
                udelay(rcu_random(&rand) & 0x3ff);
                cur_ops->sync();
+               rcu_stutter_wait();
        } while (!kthread_should_stop() && !fullstop);
 
        VERBOSE_PRINTK_STRING("rcu_torture_fakewriter task stopping");
@@ -641,6 +656,7 @@ rcu_torture_reader(void *arg)
                preempt_enable();
                cur_ops->readunlock(idx);
                schedule();
+               rcu_stutter_wait();
        } while (!kthread_should_stop() && !fullstop);
        VERBOSE_PRINTK_STRING("rcu_torture_reader task stopping");
        while (!kthread_should_stop())
@@ -812,15 +828,34 @@ rcu_torture_shuffle(void *arg)
        return 0;
 }
 
+/* Cause the rcutorture test to "stutter", starting and stopping all
+ * threads periodically.
+ */
+static int
+rcu_torture_stutter(void *arg)
+{
+       VERBOSE_PRINTK_STRING("rcu_torture_stutter task started");
+       do {
+               schedule_timeout_interruptible(stutter * HZ);
+               stutter_pause_test = 1;
+               if (!kthread_should_stop())
+                       schedule_timeout_interruptible(stutter * HZ);
+               stutter_pause_test = 0;
+       } while (!kthread_should_stop());
+       VERBOSE_PRINTK_STRING("rcu_torture_stutter task stopping");
+       return 0;
+}
+
 static inline void
 rcu_torture_print_module_parms(char *tag)
 {
        printk(KERN_ALERT "%s" TORTURE_FLAG
                "--- %s: nreaders=%d nfakewriters=%d "
                "stat_interval=%d verbose=%d test_no_idle_hz=%d "
-               "shuffle_interval = %d\n",
+               "shuffle_interval=%d stutter=%d\n",
                torture_type, tag, nrealreaders, nfakewriters,
-               stat_interval, verbose, test_no_idle_hz, shuffle_interval);
+               stat_interval, verbose, test_no_idle_hz, shuffle_interval,
+               stutter);
 }
 
 static void
@@ -829,6 +864,11 @@ rcu_torture_cleanup(void)
        int i;
 
        fullstop = 1;
+       if (stutter_task) {
+               VERBOSE_PRINTK_STRING("Stopping rcu_torture_stutter task");
+               kthread_stop(stutter_task);
+       }
+       stutter_task = NULL;
        if (shuffler_task) {
                VERBOSE_PRINTK_STRING("Stopping rcu_torture_shuffle task");
                kthread_stop(shuffler_task);
@@ -1017,6 +1057,19 @@ rcu_torture_init(void)
                        goto unwind;
                }
        }
+       if (stutter < 0)
+               stutter = 0;
+       if (stutter) {
+               /* Create the stutter thread */
+               stutter_task = kthread_run(rcu_torture_stutter, NULL,
+                                         "rcu_torture_stutter");
+               if (IS_ERR(stutter_task)) {
+                       firsterr = PTR_ERR(stutter_task);
+                       VERBOSE_PRINTK_ERRSTRING("Failed to create stutter");
+                       stutter_task = NULL;
+                       goto unwind;
+               }
+       }
        return 0;
 
 unwind: