aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul E. McKenney <paulmck@linux.vnet.ibm.com>2013-04-23 20:05:42 -0400
committerPaul E. McKenney <paulmck@linux.vnet.ibm.com>2013-08-20 14:37:54 -0400
commitd2818df168b2c80c7449e47bd349094c308fa323 (patch)
treed27801819b2b0e37d19a3acbbae54901b576288c
parentf7f7bac9cb1c50783f15937a11743655a5756a36 (diff)
rcu: Add duplicate-callback tests to rcutorture
This commit adds a object_debug option to rcutorture to allow the debug-object-based checks for duplicate call_rcu() invocations to be deterministically tested. Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com> Cc: Sedat Dilek <sedat.dilek@gmail.com> Cc: Davidlohr Bueso <davidlohr.bueso@hp.com> Cc: Rik van Riel <riel@surriel.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Linus Torvalds <torvalds@linux-foundation.org> Tested-by: Sedat Dilek <sedat.dilek@gmail.com> [ paulmck: Banish mid-function ifdef, more or less per Josh Triplett. ] Reviewed-by: Josh Triplett <josh@joshtriplett.org> [ paulmck: Improve duplicate-callback test, per Lai Jiangshan. ]
-rw-r--r--kernel/rcutorture.c61
1 files changed, 61 insertions, 0 deletions
diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c
index 3d936f0fbcd8..c898f14a5b7d 100644
--- a/kernel/rcutorture.c
+++ b/kernel/rcutorture.c
@@ -66,6 +66,7 @@ static int fqs_duration; /* Duration of bursts (us), 0 to disable. */
66static int fqs_holdoff; /* Hold time within burst (us). */ 66static int fqs_holdoff; /* Hold time within burst (us). */
67static int fqs_stutter = 3; /* Wait time between bursts (s). */ 67static int fqs_stutter = 3; /* Wait time between bursts (s). */
68static int n_barrier_cbs; /* Number of callbacks to test RCU barriers. */ 68static int n_barrier_cbs; /* Number of callbacks to test RCU barriers. */
69static int object_debug; /* Test object-debug double call_rcu()?. */
69static int onoff_interval; /* Wait time between CPU hotplugs, 0=disable. */ 70static int onoff_interval; /* Wait time between CPU hotplugs, 0=disable. */
70static int onoff_holdoff; /* Seconds after boot before CPU hotplugs. */ 71static int onoff_holdoff; /* Seconds after boot before CPU hotplugs. */
71static int shutdown_secs; /* Shutdown time (s). <=0 for no shutdown. */ 72static int shutdown_secs; /* Shutdown time (s). <=0 for no shutdown. */
@@ -100,6 +101,8 @@ module_param(fqs_stutter, int, 0444);
100MODULE_PARM_DESC(fqs_stutter, "Wait time between fqs bursts (s)"); 101MODULE_PARM_DESC(fqs_stutter, "Wait time between fqs bursts (s)");
101module_param(n_barrier_cbs, int, 0444); 102module_param(n_barrier_cbs, int, 0444);
102MODULE_PARM_DESC(n_barrier_cbs, "# of callbacks/kthreads for barrier testing"); 103MODULE_PARM_DESC(n_barrier_cbs, "# of callbacks/kthreads for barrier testing");
104module_param(object_debug, int, 0444);
105MODULE_PARM_DESC(object_debug, "Enable debug-object double call_rcu() testing");
103module_param(onoff_interval, int, 0444); 106module_param(onoff_interval, int, 0444);
104MODULE_PARM_DESC(onoff_interval, "Time between CPU hotplugs (s), 0=disable"); 107MODULE_PARM_DESC(onoff_interval, "Time between CPU hotplugs (s), 0=disable");
105module_param(onoff_holdoff, int, 0444); 108module_param(onoff_holdoff, int, 0444);
@@ -1934,6 +1937,62 @@ rcu_torture_cleanup(void)
1934 rcu_torture_print_module_parms(cur_ops, "End of test: SUCCESS"); 1937 rcu_torture_print_module_parms(cur_ops, "End of test: SUCCESS");
1935} 1938}
1936 1939
1940#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
1941static void rcu_torture_leak_cb(struct rcu_head *rhp)
1942{
1943}
1944
1945static void rcu_torture_err_cb(struct rcu_head *rhp)
1946{
1947 /*
1948 * This -might- happen due to race conditions, but is unlikely.
1949 * The scenario that leads to this happening is that the
1950 * first of the pair of duplicate callbacks is queued,
1951 * someone else starts a grace period that includes that
1952 * callback, then the second of the pair must wait for the
1953 * next grace period. Unlikely, but can happen. If it
1954 * does happen, the debug-objects subsystem won't have splatted.
1955 */
1956 pr_alert("rcutorture: duplicated callback was invoked.\n");
1957}
1958#endif /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
1959
1960/*
1961 * Verify that double-free causes debug-objects to complain, but only
1962 * if CONFIG_DEBUG_OBJECTS_RCU_HEAD=y. Otherwise, say that the test
1963 * cannot be carried out.
1964 */
1965static void rcu_test_debug_objects(void)
1966{
1967#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
1968 struct rcu_head rh1;
1969 struct rcu_head rh2;
1970
1971 init_rcu_head_on_stack(&rh1);
1972 init_rcu_head_on_stack(&rh2);
1973 pr_alert("rcutorture: WARN: Duplicate call_rcu() test starting.\n");
1974
1975 /* Try to queue the rh2 pair of callbacks for the same grace period. */
1976 preempt_disable(); /* Prevent preemption from interrupting test. */
1977 rcu_read_lock(); /* Make it impossible to finish a grace period. */
1978 call_rcu(&rh1, rcu_torture_leak_cb); /* Start grace period. */
1979 local_irq_disable(); /* Make it harder to start a new grace period. */
1980 call_rcu(&rh2, rcu_torture_leak_cb);
1981 call_rcu(&rh2, rcu_torture_err_cb); /* Duplicate callback. */
1982 local_irq_enable();
1983 rcu_read_unlock();
1984 preempt_enable();
1985
1986 /* Wait for them all to get done so we can safely return. */
1987 rcu_barrier();
1988 pr_alert("rcutorture: WARN: Duplicate call_rcu() test complete.\n");
1989 destroy_rcu_head_on_stack(&rh1);
1990 destroy_rcu_head_on_stack(&rh2);
1991#else /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
1992 pr_alert("rcutorture: !CONFIG_DEBUG_OBJECTS_RCU_HEAD, not testing duplicate call_rcu()\n");
1993#endif /* #else #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
1994}
1995
1937static int __init 1996static int __init
1938rcu_torture_init(void) 1997rcu_torture_init(void)
1939{ 1998{
@@ -2163,6 +2222,8 @@ rcu_torture_init(void)
2163 firsterr = retval; 2222 firsterr = retval;
2164 goto unwind; 2223 goto unwind;
2165 } 2224 }
2225 if (object_debug)
2226 rcu_test_debug_objects();
2166 rcutorture_record_test_transition(); 2227 rcutorture_record_test_transition();
2167 mutex_unlock(&fullstop_mutex); 2228 mutex_unlock(&fullstop_mutex);
2168 return 0; 2229 return 0;