|
@@ -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:
|