aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul E. McKenney <paulmck@linux.vnet.ibm.com>2014-01-27 14:49:39 -0500
committerPaul E. McKenney <paulmck@linux.vnet.ibm.com>2014-02-23 12:00:58 -0500
commit51b1130eb5823ddb90a9ad07d243031d8cb7ecf2 (patch)
treeab66b2dfa679027a90b122ee95c1a82c4ff5a1f7
parent806274c018e9858320a27b785df761f45c33a56c (diff)
rcutorture: Abstract rcu_torture_random()
Because rcu_torture_random() will be used by the locking equivalent to rcutorture, pull it out into its own module. This new module cannot be separately configured, instead, use the Kconfig "select" statement from the Kconfig options of tests depending on it. Suggested-by: Rusty Russell <rusty@rustcorp.com.au> Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
-rw-r--r--include/linux/torture.h47
-rw-r--r--kernel/Makefile1
-rw-r--r--kernel/rcu/Makefile2
-rw-r--r--kernel/rcu/rcutorture.c (renamed from kernel/rcu/torture.c)67
-rw-r--r--kernel/torture.c71
-rw-r--r--lib/Kconfig.debug5
6 files changed, 147 insertions, 46 deletions
diff --git a/include/linux/torture.h b/include/linux/torture.h
new file mode 100644
index 000000000000..979e3e6b378a
--- /dev/null
+++ b/include/linux/torture.h
@@ -0,0 +1,47 @@
1/*
2 * Common functions for in-kernel torture tests.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, you can access it online at
16 * http://www.gnu.org/licenses/gpl-2.0.html.
17 *
18 * Copyright IBM Corporation, 2014
19 *
20 * Author: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
21 */
22
23#ifndef __LINUX_TORTURE_H
24#define __LINUX_TORTURE_H
25
26#include <linux/types.h>
27#include <linux/cache.h>
28#include <linux/spinlock.h>
29#include <linux/threads.h>
30#include <linux/cpumask.h>
31#include <linux/seqlock.h>
32#include <linux/lockdep.h>
33#include <linux/completion.h>
34#include <linux/debugobjects.h>
35#include <linux/bug.h>
36#include <linux/compiler.h>
37
38struct torture_random_state {
39 unsigned long trs_state;
40 long trs_count;
41};
42
43#define DEFINE_TORTURE_RANDOM(name) struct torture_random_state name = { 0, 0 }
44
45unsigned long torture_random(struct torture_random_state *trsp);
46
47#endif /* __LINUX_TORTURE_H */
diff --git a/kernel/Makefile b/kernel/Makefile
index bc010ee272b6..5c0e7666811d 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -93,6 +93,7 @@ obj-$(CONFIG_PADATA) += padata.o
93obj-$(CONFIG_CRASH_DUMP) += crash_dump.o 93obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
94obj-$(CONFIG_JUMP_LABEL) += jump_label.o 94obj-$(CONFIG_JUMP_LABEL) += jump_label.o
95obj-$(CONFIG_CONTEXT_TRACKING) += context_tracking.o 95obj-$(CONFIG_CONTEXT_TRACKING) += context_tracking.o
96obj-$(CONFIG_TORTURE_TEST) += torture.o
96 97
97$(obj)/configs.o: $(obj)/config_data.h 98$(obj)/configs.o: $(obj)/config_data.h
98 99
diff --git a/kernel/rcu/Makefile b/kernel/rcu/Makefile
index 01e9ec37a3e3..807ccfbf69b3 100644
--- a/kernel/rcu/Makefile
+++ b/kernel/rcu/Makefile
@@ -1,5 +1,5 @@
1obj-y += update.o srcu.o 1obj-y += update.o srcu.o
2obj-$(CONFIG_RCU_TORTURE_TEST) += torture.o 2obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o
3obj-$(CONFIG_TREE_RCU) += tree.o 3obj-$(CONFIG_TREE_RCU) += tree.o
4obj-$(CONFIG_TREE_PREEMPT_RCU) += tree.o 4obj-$(CONFIG_TREE_PREEMPT_RCU) += tree.o
5obj-$(CONFIG_TREE_RCU_TRACE) += tree_trace.o 5obj-$(CONFIG_TREE_RCU_TRACE) += tree_trace.o
diff --git a/kernel/rcu/torture.c b/kernel/rcu/rcutorture.c
index dad67238d086..94b1cd8b214c 100644
--- a/kernel/rcu/torture.c
+++ b/kernel/rcu/rcutorture.c
@@ -48,6 +48,7 @@
48#include <linux/slab.h> 48#include <linux/slab.h>
49#include <linux/trace_clock.h> 49#include <linux/trace_clock.h>
50#include <asm/byteorder.h> 50#include <asm/byteorder.h>
51#include <linux/torture.h>
51 52
52MODULE_LICENSE("GPL"); 53MODULE_LICENSE("GPL");
53MODULE_AUTHOR("Paul E. McKenney <paulmck@us.ibm.com> and Josh Triplett <josh@freedesktop.org>"); 54MODULE_AUTHOR("Paul E. McKenney <paulmck@us.ibm.com> and Josh Triplett <josh@freedesktop.org>");
@@ -320,32 +321,6 @@ rcu_torture_free(struct rcu_torture *p)
320 spin_unlock_bh(&rcu_torture_lock); 321 spin_unlock_bh(&rcu_torture_lock);
321} 322}
322 323
323struct rcu_random_state {
324 unsigned long rrs_state;
325 long rrs_count;
326};
327
328#define RCU_RANDOM_MULT 39916801 /* prime */
329#define RCU_RANDOM_ADD 479001701 /* prime */
330#define RCU_RANDOM_REFRESH 10000
331
332#define DEFINE_RCU_RANDOM(name) struct rcu_random_state name = { 0, 0 }
333
334/*
335 * Crude but fast random-number generator. Uses a linear congruential
336 * generator, with occasional help from cpu_clock().
337 */
338static unsigned long
339rcu_random(struct rcu_random_state *rrsp)
340{
341 if (--rrsp->rrs_count < 0) {
342 rrsp->rrs_state += (unsigned long)local_clock();
343 rrsp->rrs_count = RCU_RANDOM_REFRESH;
344 }
345 rrsp->rrs_state = rrsp->rrs_state * RCU_RANDOM_MULT + RCU_RANDOM_ADD;
346 return swahw32(rrsp->rrs_state);
347}
348
349static void 324static void
350rcu_stutter_wait(const char *title) 325rcu_stutter_wait(const char *title)
351{ 326{
@@ -365,7 +340,7 @@ rcu_stutter_wait(const char *title)
365struct rcu_torture_ops { 340struct rcu_torture_ops {
366 void (*init)(void); 341 void (*init)(void);
367 int (*readlock)(void); 342 int (*readlock)(void);
368 void (*read_delay)(struct rcu_random_state *rrsp); 343 void (*read_delay)(struct torture_random_state *rrsp);
369 void (*readunlock)(int idx); 344 void (*readunlock)(int idx);
370 int (*completed)(void); 345 int (*completed)(void);
371 void (*deferred_free)(struct rcu_torture *p); 346 void (*deferred_free)(struct rcu_torture *p);
@@ -392,7 +367,7 @@ static int rcu_torture_read_lock(void) __acquires(RCU)
392 return 0; 367 return 0;
393} 368}
394 369
395static void rcu_read_delay(struct rcu_random_state *rrsp) 370static void rcu_read_delay(struct torture_random_state *rrsp)
396{ 371{
397 const unsigned long shortdelay_us = 200; 372 const unsigned long shortdelay_us = 200;
398 const unsigned long longdelay_ms = 50; 373 const unsigned long longdelay_ms = 50;
@@ -401,12 +376,13 @@ static void rcu_read_delay(struct rcu_random_state *rrsp)
401 * period, and we want a long delay occasionally to trigger 376 * period, and we want a long delay occasionally to trigger
402 * force_quiescent_state. */ 377 * force_quiescent_state. */
403 378
404 if (!(rcu_random(rrsp) % (nrealreaders * 2000 * longdelay_ms))) 379 if (!(torture_random(rrsp) % (nrealreaders * 2000 * longdelay_ms)))
405 mdelay(longdelay_ms); 380 mdelay(longdelay_ms);
406 if (!(rcu_random(rrsp) % (nrealreaders * 2 * shortdelay_us))) 381 if (!(torture_random(rrsp) % (nrealreaders * 2 * shortdelay_us)))
407 udelay(shortdelay_us); 382 udelay(shortdelay_us);
408#ifdef CONFIG_PREEMPT 383#ifdef CONFIG_PREEMPT
409 if (!preempt_count() && !(rcu_random(rrsp) % (nrealreaders * 20000))) 384 if (!preempt_count() &&
385 !(torture_random(rrsp) % (nrealreaders * 20000)))
410 preempt_schedule(); /* No QS if preempt_disable() in effect */ 386 preempt_schedule(); /* No QS if preempt_disable() in effect */
411#endif 387#endif
412} 388}
@@ -530,7 +506,7 @@ static int srcu_torture_read_lock(void) __acquires(&srcu_ctl)
530 return srcu_read_lock(&srcu_ctl); 506 return srcu_read_lock(&srcu_ctl);
531} 507}
532 508
533static void srcu_read_delay(struct rcu_random_state *rrsp) 509static void srcu_read_delay(struct torture_random_state *rrsp)
534{ 510{
535 long delay; 511 long delay;
536 const long uspertick = 1000000 / HZ; 512 const long uspertick = 1000000 / HZ;
@@ -538,7 +514,8 @@ static void srcu_read_delay(struct rcu_random_state *rrsp)
538 514
539 /* We want there to be long-running readers, but not all the time. */ 515 /* We want there to be long-running readers, but not all the time. */
540 516
541 delay = rcu_random(rrsp) % (nrealreaders * 2 * longdelay * uspertick); 517 delay = torture_random(rrsp) %
518 (nrealreaders * 2 * longdelay * uspertick);
542 if (!delay) 519 if (!delay)
543 schedule_timeout_interruptible(longdelay); 520 schedule_timeout_interruptible(longdelay);
544 else 521 else
@@ -802,7 +779,7 @@ rcu_torture_writer(void *arg)
802 struct rcu_torture *rp; 779 struct rcu_torture *rp;
803 struct rcu_torture *rp1; 780 struct rcu_torture *rp1;
804 struct rcu_torture *old_rp; 781 struct rcu_torture *old_rp;
805 static DEFINE_RCU_RANDOM(rand); 782 static DEFINE_TORTURE_RANDOM(rand);
806 783
807 VERBOSE_PRINTK_STRING("rcu_torture_writer task started"); 784 VERBOSE_PRINTK_STRING("rcu_torture_writer task started");
808 set_user_nice(current, 19); 785 set_user_nice(current, 19);
@@ -813,7 +790,7 @@ rcu_torture_writer(void *arg)
813 if (rp == NULL) 790 if (rp == NULL)
814 continue; 791 continue;
815 rp->rtort_pipe_count = 0; 792 rp->rtort_pipe_count = 0;
816 udelay(rcu_random(&rand) & 0x3ff); 793 udelay(torture_random(&rand) & 0x3ff);
817 old_rp = rcu_dereference_check(rcu_torture_current, 794 old_rp = rcu_dereference_check(rcu_torture_current,
818 current == writer_task); 795 current == writer_task);
819 rp->rtort_mbtest = 1; 796 rp->rtort_mbtest = 1;
@@ -826,7 +803,7 @@ rcu_torture_writer(void *arg)
826 atomic_inc(&rcu_torture_wcount[i]); 803 atomic_inc(&rcu_torture_wcount[i]);
827 old_rp->rtort_pipe_count++; 804 old_rp->rtort_pipe_count++;
828 if (gp_normal == gp_exp) 805 if (gp_normal == gp_exp)
829 exp = !!(rcu_random(&rand) & 0x80); 806 exp = !!(torture_random(&rand) & 0x80);
830 else 807 else
831 exp = gp_exp; 808 exp = gp_exp;
832 if (!exp) { 809 if (!exp) {
@@ -868,19 +845,19 @@ rcu_torture_writer(void *arg)
868static int 845static int
869rcu_torture_fakewriter(void *arg) 846rcu_torture_fakewriter(void *arg)
870{ 847{
871 DEFINE_RCU_RANDOM(rand); 848 DEFINE_TORTURE_RANDOM(rand);
872 849
873 VERBOSE_PRINTK_STRING("rcu_torture_fakewriter task started"); 850 VERBOSE_PRINTK_STRING("rcu_torture_fakewriter task started");
874 set_user_nice(current, 19); 851 set_user_nice(current, 19);
875 852
876 do { 853 do {
877 schedule_timeout_uninterruptible(1 + rcu_random(&rand)%10); 854 schedule_timeout_uninterruptible(1 + torture_random(&rand)%10);
878 udelay(rcu_random(&rand) & 0x3ff); 855 udelay(torture_random(&rand) & 0x3ff);
879 if (cur_ops->cb_barrier != NULL && 856 if (cur_ops->cb_barrier != NULL &&
880 rcu_random(&rand) % (nfakewriters * 8) == 0) { 857 torture_random(&rand) % (nfakewriters * 8) == 0) {
881 cur_ops->cb_barrier(); 858 cur_ops->cb_barrier();
882 } else if (gp_normal == gp_exp) { 859 } else if (gp_normal == gp_exp) {
883 if (rcu_random(&rand) & 0x80) 860 if (torture_random(&rand) & 0x80)
884 cur_ops->sync(); 861 cur_ops->sync();
885 else 862 else
886 cur_ops->exp_sync(); 863 cur_ops->exp_sync();
@@ -921,7 +898,7 @@ static void rcu_torture_timer(unsigned long unused)
921 int idx; 898 int idx;
922 int completed; 899 int completed;
923 int completed_end; 900 int completed_end;
924 static DEFINE_RCU_RANDOM(rand); 901 static DEFINE_TORTURE_RANDOM(rand);
925 static DEFINE_SPINLOCK(rand_lock); 902 static DEFINE_SPINLOCK(rand_lock);
926 struct rcu_torture *p; 903 struct rcu_torture *p;
927 int pipe_count; 904 int pipe_count;
@@ -980,7 +957,7 @@ rcu_torture_reader(void *arg)
980 int completed; 957 int completed;
981 int completed_end; 958 int completed_end;
982 int idx; 959 int idx;
983 DEFINE_RCU_RANDOM(rand); 960 DEFINE_TORTURE_RANDOM(rand);
984 struct rcu_torture *p; 961 struct rcu_torture *p;
985 int pipe_count; 962 int pipe_count;
986 struct timer_list t; 963 struct timer_list t;
@@ -1389,7 +1366,7 @@ rcu_torture_onoff(void *arg)
1389 int cpu; 1366 int cpu;
1390 unsigned long delta; 1367 unsigned long delta;
1391 int maxcpu = -1; 1368 int maxcpu = -1;
1392 DEFINE_RCU_RANDOM(rand); 1369 DEFINE_TORTURE_RANDOM(rand);
1393 int ret; 1370 int ret;
1394 unsigned long starttime; 1371 unsigned long starttime;
1395 1372
@@ -1403,7 +1380,7 @@ rcu_torture_onoff(void *arg)
1403 VERBOSE_PRINTK_STRING("rcu_torture_onoff end holdoff"); 1380 VERBOSE_PRINTK_STRING("rcu_torture_onoff end holdoff");
1404 } 1381 }
1405 while (!kthread_should_stop()) { 1382 while (!kthread_should_stop()) {
1406 cpu = (rcu_random(&rand) >> 4) % (maxcpu + 1); 1383 cpu = (torture_random(&rand) >> 4) % (maxcpu + 1);
1407 if (cpu_online(cpu) && cpu_is_hotpluggable(cpu)) { 1384 if (cpu_online(cpu) && cpu_is_hotpluggable(cpu)) {
1408 if (verbose) 1385 if (verbose)
1409 pr_alert("%s" TORTURE_FLAG 1386 pr_alert("%s" TORTURE_FLAG
diff --git a/kernel/torture.c b/kernel/torture.c
new file mode 100644
index 000000000000..c82c70f7828e
--- /dev/null
+++ b/kernel/torture.c
@@ -0,0 +1,71 @@
1/*
2 * Common functions for in-kernel torture tests.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, you can access it online at
16 * http://www.gnu.org/licenses/gpl-2.0.html.
17 *
18 * Copyright (C) IBM Corporation, 2014
19 *
20 * Author: Paul E. McKenney <paulmck@us.ibm.com>
21 * Based on kernel/rcu/torture.c.
22 */
23#include <linux/types.h>
24#include <linux/kernel.h>
25#include <linux/init.h>
26#include <linux/module.h>
27#include <linux/kthread.h>
28#include <linux/err.h>
29#include <linux/spinlock.h>
30#include <linux/smp.h>
31#include <linux/interrupt.h>
32#include <linux/sched.h>
33#include <linux/atomic.h>
34#include <linux/bitops.h>
35#include <linux/completion.h>
36#include <linux/moduleparam.h>
37#include <linux/percpu.h>
38#include <linux/notifier.h>
39#include <linux/reboot.h>
40#include <linux/freezer.h>
41#include <linux/cpu.h>
42#include <linux/delay.h>
43#include <linux/stat.h>
44#include <linux/slab.h>
45#include <linux/trace_clock.h>
46#include <asm/byteorder.h>
47#include <linux/torture.h>
48
49MODULE_LICENSE("GPL");
50MODULE_AUTHOR("Paul E. McKenney <paulmck@us.ibm.com>");
51
52#define TORTURE_RANDOM_MULT 39916801 /* prime */
53#define TORTURE_RANDOM_ADD 479001701 /* prime */
54#define TORTURE_RANDOM_REFRESH 10000
55
56/*
57 * Crude but fast random-number generator. Uses a linear congruential
58 * generator, with occasional help from cpu_clock().
59 */
60unsigned long
61torture_random(struct torture_random_state *trsp)
62{
63 if (--trsp->trs_count < 0) {
64 trsp->trs_state += (unsigned long)local_clock();
65 trsp->trs_count = TORTURE_RANDOM_REFRESH;
66 }
67 trsp->trs_state = trsp->trs_state * TORTURE_RANDOM_MULT +
68 TORTURE_RANDOM_ADD;
69 return swahw32(trsp->trs_state);
70}
71EXPORT_SYMBOL_GPL(torture_random);
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index a48abeac753f..2bfb4e5cdf8c 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -1141,9 +1141,14 @@ config SPARSE_RCU_POINTER
1141 1141
1142 Say N if you are unsure. 1142 Say N if you are unsure.
1143 1143
1144config TORTURE_TEST
1145 tristate
1146 default n
1147
1144config RCU_TORTURE_TEST 1148config RCU_TORTURE_TEST
1145 tristate "torture tests for RCU" 1149 tristate "torture tests for RCU"
1146 depends on DEBUG_KERNEL 1150 depends on DEBUG_KERNEL
1151 select TORTURE_TEST
1147 default n 1152 default n
1148 help 1153 help
1149 This option provides a kernel module that runs torture tests 1154 This option provides a kernel module that runs torture tests