From: Paul E. McKenney Date: Wed, 24 Apr 2013 00:05:42 +0000 (-0700) Subject: rcu: Add duplicate-callback tests to rcutorture X-Git-Tag: next-20130607~35^2~4 X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=86cac1d6e1bf16b193be4f10e1fa4ad528ec3718;p=karo-tx-linux.git 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 Cc: Mathieu Desnoyers Cc: Sedat Dilek Cc: Davidlohr Bueso Cc: Rik van Riel Cc: Thomas Gleixner Cc: Linus Torvalds Tested-by: Sedat Dilek --- diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c index b1fa5510388d..193e17b77408 100644 --- a/kernel/rcutorture.c +++ b/kernel/rcutorture.c @@ -66,6 +66,7 @@ static int fqs_duration; /* Duration of bursts (us), 0 to disable. */ static int fqs_holdoff; /* Hold time within burst (us). */ static int fqs_stutter = 3; /* Wait time between bursts (s). */ static int n_barrier_cbs; /* Number of callbacks to test RCU barriers. */ +static int object_debug; /* Test object-debug double call_rcu()?. */ static int onoff_interval; /* Wait time between CPU hotplugs, 0=disable. */ static int onoff_holdoff; /* Seconds after boot before CPU hotplugs. */ static int shutdown_secs; /* Shutdown time (s). <=0 for no shutdown. */ @@ -100,6 +101,8 @@ module_param(fqs_stutter, int, 0444); MODULE_PARM_DESC(fqs_stutter, "Wait time between fqs bursts (s)"); module_param(n_barrier_cbs, int, 0444); MODULE_PARM_DESC(n_barrier_cbs, "# of callbacks/kthreads for barrier testing"); +module_param(object_debug, int, 0444); +MODULE_PARM_DESC(object_debug, "Enable debug-object double call_rcu() testing"); module_param(onoff_interval, int, 0444); MODULE_PARM_DESC(onoff_interval, "Time between CPU hotplugs (s), 0=disable"); module_param(onoff_holdoff, int, 0444); @@ -1934,6 +1937,18 @@ rcu_torture_cleanup(void) rcu_torture_print_module_parms(cur_ops, "End of test: SUCCESS"); } +#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD +static void rcu_torture_leak_cb(struct rcu_head *rhp) +{ +} + +static void rcu_torture_err_cb(struct rcu_head *rhp) +{ + /* This -might- happen due to race conditions, but is unlikely. */ + pr_alert("rcutorture: duplicated callback was invoked.\n"); +} +#endif /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */ + static int __init rcu_torture_init(void) { @@ -2163,6 +2178,28 @@ rcu_torture_init(void) firsterr = retval; goto unwind; } + if (object_debug) { +#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD + struct rcu_head rh1; + struct rcu_head rh2; + + init_rcu_head_on_stack(&rh1); + init_rcu_head_on_stack(&rh2); + pr_alert("rcutorture: WARN: Duplicate call_rcu() test starting.\n"); + local_irq_disable(); /* Make it hard to finish grace period. */ + call_rcu(&rh1, rcu_torture_leak_cb); /* start grace period. */ + call_rcu(&rh2, rcu_torture_err_cb); + call_rcu(&rh2, rcu_torture_err_cb); /* duplicate callback. */ + local_irq_enable(); + rcu_barrier(); + pr_alert("rcutorture: WARN: Duplicate call_rcu() test complete.\n"); + destroy_rcu_head_on_stack(&rh1); + destroy_rcu_head_on_stack(&rh2); +#else /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */ + pr_alert("rcutorture: !%s, not testing duplicate call_rcu()\n", + "CONFIG_DEBUG_OBJECTS_RCU_HEAD"); +#endif /* #else #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */ + } rcutorture_record_test_transition(); mutex_unlock(&fullstop_mutex); return 0;