]> git.karo-electronics.de Git - linux-beck.git/commitdiff
rcutorture: Abstract rcu_torture_random()
authorPaul E. McKenney <paulmck@linux.vnet.ibm.com>
Mon, 27 Jan 2014 19:49:39 +0000 (11:49 -0800)
committerPaul E. McKenney <paulmck@linux.vnet.ibm.com>
Sun, 23 Feb 2014 17:00:58 +0000 (09:00 -0800)
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>
include/linux/torture.h [new file with mode: 0644]
kernel/Makefile
kernel/rcu/Makefile
kernel/rcu/rcutorture.c [moved from kernel/rcu/torture.c with 97% similarity]
kernel/torture.c [new file with mode: 0644]
lib/Kconfig.debug

diff --git a/include/linux/torture.h b/include/linux/torture.h
new file mode 100644 (file)
index 0000000..979e3e6
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Common functions for in-kernel torture tests.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can access it online at
+ * http://www.gnu.org/licenses/gpl-2.0.html.
+ *
+ * Copyright IBM Corporation, 2014
+ *
+ * Author: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
+ */
+
+#ifndef __LINUX_TORTURE_H
+#define __LINUX_TORTURE_H
+
+#include <linux/types.h>
+#include <linux/cache.h>
+#include <linux/spinlock.h>
+#include <linux/threads.h>
+#include <linux/cpumask.h>
+#include <linux/seqlock.h>
+#include <linux/lockdep.h>
+#include <linux/completion.h>
+#include <linux/debugobjects.h>
+#include <linux/bug.h>
+#include <linux/compiler.h>
+
+struct torture_random_state {
+       unsigned long trs_state;
+       long trs_count;
+};
+
+#define DEFINE_TORTURE_RANDOM(name) struct torture_random_state name = { 0, 0 }
+
+unsigned long torture_random(struct torture_random_state *trsp);
+
+#endif /* __LINUX_TORTURE_H */
index bc010ee272b6cfec39892e6cb04b98cc06995e1a..5c0e7666811df47c1144b70a8bc4cecce99586e5 100644 (file)
@@ -93,6 +93,7 @@ obj-$(CONFIG_PADATA) += padata.o
 obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
 obj-$(CONFIG_JUMP_LABEL) += jump_label.o
 obj-$(CONFIG_CONTEXT_TRACKING) += context_tracking.o
+obj-$(CONFIG_TORTURE_TEST) += torture.o
 
 $(obj)/configs.o: $(obj)/config_data.h
 
index 01e9ec37a3e39af2d7e5d889a770b099dc1eb473..807ccfbf69b3359fe85b736efd14d7050e5e4990 100644 (file)
@@ -1,5 +1,5 @@
 obj-y += update.o srcu.o
-obj-$(CONFIG_RCU_TORTURE_TEST) += torture.o
+obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o
 obj-$(CONFIG_TREE_RCU) += tree.o
 obj-$(CONFIG_TREE_PREEMPT_RCU) += tree.o
 obj-$(CONFIG_TREE_RCU_TRACE) += tree_trace.o
similarity index 97%
rename from kernel/rcu/torture.c
rename to kernel/rcu/rcutorture.c
index dad67238d086eb84256ded3d96685e833f4a000e..94b1cd8b214c22de25b160f73e2bb67e470504ce 100644 (file)
@@ -48,6 +48,7 @@
 #include <linux/slab.h>
 #include <linux/trace_clock.h>
 #include <asm/byteorder.h>
+#include <linux/torture.h>
 
 MODULE_LICENSE("GPL");
 MODULE_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)
        spin_unlock_bh(&rcu_torture_lock);
 }
 
-struct rcu_random_state {
-       unsigned long rrs_state;
-       long rrs_count;
-};
-
-#define RCU_RANDOM_MULT 39916801  /* prime */
-#define RCU_RANDOM_ADD 479001701 /* prime */
-#define RCU_RANDOM_REFRESH 10000
-
-#define DEFINE_RCU_RANDOM(name) struct rcu_random_state name = { 0, 0 }
-
-/*
- * Crude but fast random-number generator.  Uses a linear congruential
- * generator, with occasional help from cpu_clock().
- */
-static unsigned long
-rcu_random(struct rcu_random_state *rrsp)
-{
-       if (--rrsp->rrs_count < 0) {
-               rrsp->rrs_state += (unsigned long)local_clock();
-               rrsp->rrs_count = RCU_RANDOM_REFRESH;
-       }
-       rrsp->rrs_state = rrsp->rrs_state * RCU_RANDOM_MULT + RCU_RANDOM_ADD;
-       return swahw32(rrsp->rrs_state);
-}
-
 static void
 rcu_stutter_wait(const char *title)
 {
@@ -365,7 +340,7 @@ rcu_stutter_wait(const char *title)
 struct rcu_torture_ops {
        void (*init)(void);
        int (*readlock)(void);
-       void (*read_delay)(struct rcu_random_state *rrsp);
+       void (*read_delay)(struct torture_random_state *rrsp);
        void (*readunlock)(int idx);
        int (*completed)(void);
        void (*deferred_free)(struct rcu_torture *p);
@@ -392,7 +367,7 @@ static int rcu_torture_read_lock(void) __acquires(RCU)
        return 0;
 }
 
-static void rcu_read_delay(struct rcu_random_state *rrsp)
+static void rcu_read_delay(struct torture_random_state *rrsp)
 {
        const unsigned long shortdelay_us = 200;
        const unsigned long longdelay_ms = 50;
@@ -401,12 +376,13 @@ static void rcu_read_delay(struct rcu_random_state *rrsp)
         * period, and we want a long delay occasionally to trigger
         * force_quiescent_state. */
 
-       if (!(rcu_random(rrsp) % (nrealreaders * 2000 * longdelay_ms)))
+       if (!(torture_random(rrsp) % (nrealreaders * 2000 * longdelay_ms)))
                mdelay(longdelay_ms);
-       if (!(rcu_random(rrsp) % (nrealreaders * 2 * shortdelay_us)))
+       if (!(torture_random(rrsp) % (nrealreaders * 2 * shortdelay_us)))
                udelay(shortdelay_us);
 #ifdef CONFIG_PREEMPT
-       if (!preempt_count() && !(rcu_random(rrsp) % (nrealreaders * 20000)))
+       if (!preempt_count() &&
+           !(torture_random(rrsp) % (nrealreaders * 20000)))
                preempt_schedule();  /* No QS if preempt_disable() in effect */
 #endif
 }
@@ -530,7 +506,7 @@ static int srcu_torture_read_lock(void) __acquires(&srcu_ctl)
        return srcu_read_lock(&srcu_ctl);
 }
 
-static void srcu_read_delay(struct rcu_random_state *rrsp)
+static void srcu_read_delay(struct torture_random_state *rrsp)
 {
        long delay;
        const long uspertick = 1000000 / HZ;
@@ -538,7 +514,8 @@ static void srcu_read_delay(struct rcu_random_state *rrsp)
 
        /* We want there to be long-running readers, but not all the time. */
 
-       delay = rcu_random(rrsp) % (nrealreaders * 2 * longdelay * uspertick);
+       delay = torture_random(rrsp) %
+               (nrealreaders * 2 * longdelay * uspertick);
        if (!delay)
                schedule_timeout_interruptible(longdelay);
        else
@@ -802,7 +779,7 @@ rcu_torture_writer(void *arg)
        struct rcu_torture *rp;
        struct rcu_torture *rp1;
        struct rcu_torture *old_rp;
-       static DEFINE_RCU_RANDOM(rand);
+       static DEFINE_TORTURE_RANDOM(rand);
 
        VERBOSE_PRINTK_STRING("rcu_torture_writer task started");
        set_user_nice(current, 19);
@@ -813,7 +790,7 @@ rcu_torture_writer(void *arg)
                if (rp == NULL)
                        continue;
                rp->rtort_pipe_count = 0;
-               udelay(rcu_random(&rand) & 0x3ff);
+               udelay(torture_random(&rand) & 0x3ff);
                old_rp = rcu_dereference_check(rcu_torture_current,
                                               current == writer_task);
                rp->rtort_mbtest = 1;
@@ -826,7 +803,7 @@ rcu_torture_writer(void *arg)
                        atomic_inc(&rcu_torture_wcount[i]);
                        old_rp->rtort_pipe_count++;
                        if (gp_normal == gp_exp)
-                               exp = !!(rcu_random(&rand) & 0x80);
+                               exp = !!(torture_random(&rand) & 0x80);
                        else
                                exp = gp_exp;
                        if (!exp) {
@@ -868,19 +845,19 @@ rcu_torture_writer(void *arg)
 static int
 rcu_torture_fakewriter(void *arg)
 {
-       DEFINE_RCU_RANDOM(rand);
+       DEFINE_TORTURE_RANDOM(rand);
 
        VERBOSE_PRINTK_STRING("rcu_torture_fakewriter task started");
        set_user_nice(current, 19);
 
        do {
-               schedule_timeout_uninterruptible(1 + rcu_random(&rand)%10);
-               udelay(rcu_random(&rand) & 0x3ff);
+               schedule_timeout_uninterruptible(1 + torture_random(&rand)%10);
+               udelay(torture_random(&rand) & 0x3ff);
                if (cur_ops->cb_barrier != NULL &&
-                   rcu_random(&rand) % (nfakewriters * 8) == 0) {
+                   torture_random(&rand) % (nfakewriters * 8) == 0) {
                        cur_ops->cb_barrier();
                } else if (gp_normal == gp_exp) {
-                       if (rcu_random(&rand) & 0x80)
+                       if (torture_random(&rand) & 0x80)
                                cur_ops->sync();
                        else
                                cur_ops->exp_sync();
@@ -921,7 +898,7 @@ static void rcu_torture_timer(unsigned long unused)
        int idx;
        int completed;
        int completed_end;
-       static DEFINE_RCU_RANDOM(rand);
+       static DEFINE_TORTURE_RANDOM(rand);
        static DEFINE_SPINLOCK(rand_lock);
        struct rcu_torture *p;
        int pipe_count;
@@ -980,7 +957,7 @@ rcu_torture_reader(void *arg)
        int completed;
        int completed_end;
        int idx;
-       DEFINE_RCU_RANDOM(rand);
+       DEFINE_TORTURE_RANDOM(rand);
        struct rcu_torture *p;
        int pipe_count;
        struct timer_list t;
@@ -1389,7 +1366,7 @@ rcu_torture_onoff(void *arg)
        int cpu;
        unsigned long delta;
        int maxcpu = -1;
-       DEFINE_RCU_RANDOM(rand);
+       DEFINE_TORTURE_RANDOM(rand);
        int ret;
        unsigned long starttime;
 
@@ -1403,7 +1380,7 @@ rcu_torture_onoff(void *arg)
                VERBOSE_PRINTK_STRING("rcu_torture_onoff end holdoff");
        }
        while (!kthread_should_stop()) {
-               cpu = (rcu_random(&rand) >> 4) % (maxcpu + 1);
+               cpu = (torture_random(&rand) >> 4) % (maxcpu + 1);
                if (cpu_online(cpu) && cpu_is_hotpluggable(cpu)) {
                        if (verbose)
                                pr_alert("%s" TORTURE_FLAG
diff --git a/kernel/torture.c b/kernel/torture.c
new file mode 100644 (file)
index 0000000..c82c70f
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Common functions for in-kernel torture tests.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can access it online at
+ * http://www.gnu.org/licenses/gpl-2.0.html.
+ *
+ * Copyright (C) IBM Corporation, 2014
+ *
+ * Author: Paul E. McKenney <paulmck@us.ibm.com>
+ *     Based on kernel/rcu/torture.c.
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kthread.h>
+#include <linux/err.h>
+#include <linux/spinlock.h>
+#include <linux/smp.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/atomic.h>
+#include <linux/bitops.h>
+#include <linux/completion.h>
+#include <linux/moduleparam.h>
+#include <linux/percpu.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/freezer.h>
+#include <linux/cpu.h>
+#include <linux/delay.h>
+#include <linux/stat.h>
+#include <linux/slab.h>
+#include <linux/trace_clock.h>
+#include <asm/byteorder.h>
+#include <linux/torture.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Paul E. McKenney <paulmck@us.ibm.com>");
+
+#define TORTURE_RANDOM_MULT    39916801  /* prime */
+#define TORTURE_RANDOM_ADD     479001701 /* prime */
+#define TORTURE_RANDOM_REFRESH 10000
+
+/*
+ * Crude but fast random-number generator.  Uses a linear congruential
+ * generator, with occasional help from cpu_clock().
+ */
+unsigned long
+torture_random(struct torture_random_state *trsp)
+{
+       if (--trsp->trs_count < 0) {
+               trsp->trs_state += (unsigned long)local_clock();
+               trsp->trs_count = TORTURE_RANDOM_REFRESH;
+       }
+       trsp->trs_state = trsp->trs_state * TORTURE_RANDOM_MULT +
+               TORTURE_RANDOM_ADD;
+       return swahw32(trsp->trs_state);
+}
+EXPORT_SYMBOL_GPL(torture_random);
index a48abeac753f39ef520fbe1bc5243cb494c47621..2bfb4e5cdf8cf325f9acb0e7aacc8f3e2a8c021c 100644 (file)
@@ -1141,9 +1141,14 @@ config SPARSE_RCU_POINTER
 
         Say N if you are unsure.
 
+config TORTURE_TEST
+       tristate
+       default n
+
 config RCU_TORTURE_TEST
        tristate "torture tests for RCU"
        depends on DEBUG_KERNEL
+       select TORTURE_TEST
        default n
        help
          This option provides a kernel module that runs torture tests