diff options
author | Paul E. McKenney <paul.mckenney@linaro.org> | 2011-10-02 10:44:32 -0400 |
---|---|---|
committer | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2011-12-11 13:31:26 -0500 |
commit | 91afaf300269aa99a4d646969b3258b74294ac4d (patch) | |
tree | b4d7dd5f5c9933be7873b206624f7b55eb25d906 /kernel | |
parent | a8eecf2248a45bf69f0625b23c003ad2ccd765ee (diff) |
rcu: Add failure tracing to rcutorture
Trace the rcutorture RCU accesses and dump the trace buffer when the
first failure is detected.
Signed-off-by: Paul E. McKenney <paul.mckenney@linaro.org>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Reviewed-by: Josh Triplett <josh@joshtriplett.org>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/rcupdate.c | 10 | ||||
-rw-r--r-- | kernel/rcutorture.c | 18 |
2 files changed, 28 insertions, 0 deletions
diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c index c5b98e565aee..92e771d7b44b 100644 --- a/kernel/rcupdate.c +++ b/kernel/rcupdate.c | |||
@@ -316,3 +316,13 @@ struct debug_obj_descr rcuhead_debug_descr = { | |||
316 | }; | 316 | }; |
317 | EXPORT_SYMBOL_GPL(rcuhead_debug_descr); | 317 | EXPORT_SYMBOL_GPL(rcuhead_debug_descr); |
318 | #endif /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */ | 318 | #endif /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */ |
319 | |||
320 | #if defined(CONFIG_TREE_RCU) || defined(CONFIG_TREE_PREEMPT_RCU) || defined(CONFIG_RCU_TRACE) | ||
321 | void do_trace_rcu_torture_read(char *rcutorturename, struct rcu_head *rhp) | ||
322 | { | ||
323 | trace_rcu_torture_read(rcutorturename, rhp); | ||
324 | } | ||
325 | EXPORT_SYMBOL_GPL(do_trace_rcu_torture_read); | ||
326 | #else | ||
327 | #define do_trace_rcu_torture_read(rcutorturename, rhp) do { } while (0) | ||
328 | #endif | ||
diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c index 764825c2685c..df35228e743b 100644 --- a/kernel/rcutorture.c +++ b/kernel/rcutorture.c | |||
@@ -913,6 +913,18 @@ rcu_torture_fakewriter(void *arg) | |||
913 | return 0; | 913 | return 0; |
914 | } | 914 | } |
915 | 915 | ||
916 | void rcutorture_trace_dump(void) | ||
917 | { | ||
918 | static atomic_t beenhere = ATOMIC_INIT(0); | ||
919 | |||
920 | if (atomic_read(&beenhere)) | ||
921 | return; | ||
922 | if (atomic_xchg(&beenhere, 1) != 0) | ||
923 | return; | ||
924 | do_trace_rcu_torture_read(cur_ops->name, (struct rcu_head *)~0UL); | ||
925 | ftrace_dump(DUMP_ALL); | ||
926 | } | ||
927 | |||
916 | /* | 928 | /* |
917 | * RCU torture reader from timer handler. Dereferences rcu_torture_current, | 929 | * RCU torture reader from timer handler. Dereferences rcu_torture_current, |
918 | * incrementing the corresponding element of the pipeline array. The | 930 | * incrementing the corresponding element of the pipeline array. The |
@@ -934,6 +946,7 @@ static void rcu_torture_timer(unsigned long unused) | |||
934 | rcu_read_lock_bh_held() || | 946 | rcu_read_lock_bh_held() || |
935 | rcu_read_lock_sched_held() || | 947 | rcu_read_lock_sched_held() || |
936 | srcu_read_lock_held(&srcu_ctl)); | 948 | srcu_read_lock_held(&srcu_ctl)); |
949 | do_trace_rcu_torture_read(cur_ops->name, &p->rtort_rcu); | ||
937 | if (p == NULL) { | 950 | if (p == NULL) { |
938 | /* Leave because rcu_torture_writer is not yet underway */ | 951 | /* Leave because rcu_torture_writer is not yet underway */ |
939 | cur_ops->readunlock(idx); | 952 | cur_ops->readunlock(idx); |
@@ -951,6 +964,8 @@ static void rcu_torture_timer(unsigned long unused) | |||
951 | /* Should not happen, but... */ | 964 | /* Should not happen, but... */ |
952 | pipe_count = RCU_TORTURE_PIPE_LEN; | 965 | pipe_count = RCU_TORTURE_PIPE_LEN; |
953 | } | 966 | } |
967 | if (pipe_count > 1) | ||
968 | rcutorture_trace_dump(); | ||
954 | __this_cpu_inc(rcu_torture_count[pipe_count]); | 969 | __this_cpu_inc(rcu_torture_count[pipe_count]); |
955 | completed = cur_ops->completed() - completed; | 970 | completed = cur_ops->completed() - completed; |
956 | if (completed > RCU_TORTURE_PIPE_LEN) { | 971 | if (completed > RCU_TORTURE_PIPE_LEN) { |
@@ -994,6 +1009,7 @@ rcu_torture_reader(void *arg) | |||
994 | rcu_read_lock_bh_held() || | 1009 | rcu_read_lock_bh_held() || |
995 | rcu_read_lock_sched_held() || | 1010 | rcu_read_lock_sched_held() || |
996 | srcu_read_lock_held(&srcu_ctl)); | 1011 | srcu_read_lock_held(&srcu_ctl)); |
1012 | do_trace_rcu_torture_read(cur_ops->name, &p->rtort_rcu); | ||
997 | if (p == NULL) { | 1013 | if (p == NULL) { |
998 | /* Wait for rcu_torture_writer to get underway */ | 1014 | /* Wait for rcu_torture_writer to get underway */ |
999 | cur_ops->readunlock(idx); | 1015 | cur_ops->readunlock(idx); |
@@ -1009,6 +1025,8 @@ rcu_torture_reader(void *arg) | |||
1009 | /* Should not happen, but... */ | 1025 | /* Should not happen, but... */ |
1010 | pipe_count = RCU_TORTURE_PIPE_LEN; | 1026 | pipe_count = RCU_TORTURE_PIPE_LEN; |
1011 | } | 1027 | } |
1028 | if (pipe_count > 1) | ||
1029 | rcutorture_trace_dump(); | ||
1012 | __this_cpu_inc(rcu_torture_count[pipe_count]); | 1030 | __this_cpu_inc(rcu_torture_count[pipe_count]); |
1013 | completed = cur_ops->completed() - completed; | 1031 | completed = cur_ops->completed() - completed; |
1014 | if (completed > RCU_TORTURE_PIPE_LEN) { | 1032 | if (completed > RCU_TORTURE_PIPE_LEN) { |