diff options
author | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2013-04-23 20:05:42 -0400 |
---|---|---|
committer | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2013-08-20 14:37:54 -0400 |
commit | d2818df168b2c80c7449e47bd349094c308fa323 (patch) | |
tree | d27801819b2b0e37d19a3acbbae54901b576288c | |
parent | f7f7bac9cb1c50783f15937a11743655a5756a36 (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.c | 61 |
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. */ | |||
66 | static int fqs_holdoff; /* Hold time within burst (us). */ | 66 | static int fqs_holdoff; /* Hold time within burst (us). */ |
67 | static int fqs_stutter = 3; /* Wait time between bursts (s). */ | 67 | static int fqs_stutter = 3; /* Wait time between bursts (s). */ |
68 | static int n_barrier_cbs; /* Number of callbacks to test RCU barriers. */ | 68 | static int n_barrier_cbs; /* Number of callbacks to test RCU barriers. */ |
69 | static int object_debug; /* Test object-debug double call_rcu()?. */ | ||
69 | static int onoff_interval; /* Wait time between CPU hotplugs, 0=disable. */ | 70 | static int onoff_interval; /* Wait time between CPU hotplugs, 0=disable. */ |
70 | static int onoff_holdoff; /* Seconds after boot before CPU hotplugs. */ | 71 | static int onoff_holdoff; /* Seconds after boot before CPU hotplugs. */ |
71 | static int shutdown_secs; /* Shutdown time (s). <=0 for no shutdown. */ | 72 | static int shutdown_secs; /* Shutdown time (s). <=0 for no shutdown. */ |
@@ -100,6 +101,8 @@ module_param(fqs_stutter, int, 0444); | |||
100 | MODULE_PARM_DESC(fqs_stutter, "Wait time between fqs bursts (s)"); | 101 | MODULE_PARM_DESC(fqs_stutter, "Wait time between fqs bursts (s)"); |
101 | module_param(n_barrier_cbs, int, 0444); | 102 | module_param(n_barrier_cbs, int, 0444); |
102 | MODULE_PARM_DESC(n_barrier_cbs, "# of callbacks/kthreads for barrier testing"); | 103 | MODULE_PARM_DESC(n_barrier_cbs, "# of callbacks/kthreads for barrier testing"); |
104 | module_param(object_debug, int, 0444); | ||
105 | MODULE_PARM_DESC(object_debug, "Enable debug-object double call_rcu() testing"); | ||
103 | module_param(onoff_interval, int, 0444); | 106 | module_param(onoff_interval, int, 0444); |
104 | MODULE_PARM_DESC(onoff_interval, "Time between CPU hotplugs (s), 0=disable"); | 107 | MODULE_PARM_DESC(onoff_interval, "Time between CPU hotplugs (s), 0=disable"); |
105 | module_param(onoff_holdoff, int, 0444); | 108 | module_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 | ||
1941 | static void rcu_torture_leak_cb(struct rcu_head *rhp) | ||
1942 | { | ||
1943 | } | ||
1944 | |||
1945 | static 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 | */ | ||
1965 | static 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 | |||
1937 | static int __init | 1996 | static int __init |
1938 | rcu_torture_init(void) | 1997 | rcu_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; |