diff options
author | Paul E. McKenney <paul.mckenney@linaro.org> | 2011-04-04 00:33:51 -0400 |
---|---|---|
committer | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2011-05-06 02:16:56 -0400 |
commit | 4a29865689dbb87a02e3b0fff4a4ae5041273173 (patch) | |
tree | 72c9f1641a9fb05e3ae4d8cc068f62f9c566bae9 | |
parent | d71df90eadfc35aa549ff9a850842673febca71f (diff) |
rcu: make rcutorture version numbers available through debugfs
It is not possible to accurately correlate rcutorture output with that
of debugfs. This patch therefore adds a debugfs file that prints out
the rcutorture version number, permitting easy correlation.
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>
-rw-r--r-- | include/linux/rcupdate.h | 13 | ||||
-rw-r--r-- | include/linux/rcutree.h | 3 | ||||
-rw-r--r-- | kernel/rcutorture.c | 8 | ||||
-rw-r--r-- | kernel/rcutree.c | 37 | ||||
-rw-r--r-- | kernel/rcutree_trace.c | 28 |
5 files changed, 85 insertions, 4 deletions
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index ff422d2b7f90..9e169c2ba91f 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h | |||
@@ -47,6 +47,18 @@ | |||
47 | extern int rcutorture_runnable; /* for sysctl */ | 47 | extern int rcutorture_runnable; /* for sysctl */ |
48 | #endif /* #ifdef CONFIG_RCU_TORTURE_TEST */ | 48 | #endif /* #ifdef CONFIG_RCU_TORTURE_TEST */ |
49 | 49 | ||
50 | #if defined(CONFIG_TREE_RCU) || defined(CONFIG_TREE_PREEMPT_RCU) | ||
51 | extern void rcutorture_record_test_transition(void); | ||
52 | extern void rcutorture_record_progress(unsigned long vernum); | ||
53 | #else | ||
54 | static inline void rcutorture_record_test_transition(void) | ||
55 | { | ||
56 | } | ||
57 | static inline void rcutorture_record_progress(unsigned long vernum) | ||
58 | { | ||
59 | } | ||
60 | #endif | ||
61 | |||
50 | #define UINT_CMP_GE(a, b) (UINT_MAX / 2 >= (a) - (b)) | 62 | #define UINT_CMP_GE(a, b) (UINT_MAX / 2 >= (a) - (b)) |
51 | #define UINT_CMP_LT(a, b) (UINT_MAX / 2 < (a) - (b)) | 63 | #define UINT_CMP_LT(a, b) (UINT_MAX / 2 < (a) - (b)) |
52 | #define ULONG_CMP_GE(a, b) (ULONG_MAX / 2 >= (a) - (b)) | 64 | #define ULONG_CMP_GE(a, b) (ULONG_MAX / 2 >= (a) - (b)) |
@@ -68,7 +80,6 @@ extern void call_rcu_sched(struct rcu_head *head, | |||
68 | extern void synchronize_sched(void); | 80 | extern void synchronize_sched(void); |
69 | extern void rcu_barrier_bh(void); | 81 | extern void rcu_barrier_bh(void); |
70 | extern void rcu_barrier_sched(void); | 82 | extern void rcu_barrier_sched(void); |
71 | extern int sched_expedited_torture_stats(char *page); | ||
72 | 83 | ||
73 | static inline void __rcu_read_lock_bh(void) | 84 | static inline void __rcu_read_lock_bh(void) |
74 | { | 85 | { |
diff --git a/include/linux/rcutree.h b/include/linux/rcutree.h index 3a933482734a..284dad10c55b 100644 --- a/include/linux/rcutree.h +++ b/include/linux/rcutree.h | |||
@@ -58,9 +58,12 @@ static inline void synchronize_rcu_bh_expedited(void) | |||
58 | 58 | ||
59 | extern void rcu_barrier(void); | 59 | extern void rcu_barrier(void); |
60 | 60 | ||
61 | extern unsigned long rcutorture_testseq; | ||
62 | extern unsigned long rcutorture_vernum; | ||
61 | extern long rcu_batches_completed(void); | 63 | extern long rcu_batches_completed(void); |
62 | extern long rcu_batches_completed_bh(void); | 64 | extern long rcu_batches_completed_bh(void); |
63 | extern long rcu_batches_completed_sched(void); | 65 | extern long rcu_batches_completed_sched(void); |
66 | |||
64 | extern void rcu_force_quiescent_state(void); | 67 | extern void rcu_force_quiescent_state(void); |
65 | extern void rcu_bh_force_quiescent_state(void); | 68 | extern void rcu_bh_force_quiescent_state(void); |
66 | extern void rcu_sched_force_quiescent_state(void); | 69 | extern void rcu_sched_force_quiescent_state(void); |
diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c index 22b0e74e7d99..c2f58ec24751 100644 --- a/kernel/rcutorture.c +++ b/kernel/rcutorture.c | |||
@@ -131,7 +131,7 @@ struct rcu_torture { | |||
131 | 131 | ||
132 | static LIST_HEAD(rcu_torture_freelist); | 132 | static LIST_HEAD(rcu_torture_freelist); |
133 | static struct rcu_torture __rcu *rcu_torture_current; | 133 | static struct rcu_torture __rcu *rcu_torture_current; |
134 | static long rcu_torture_current_version; | 134 | static unsigned long rcu_torture_current_version; |
135 | static struct rcu_torture rcu_tortures[10 * RCU_TORTURE_PIPE_LEN]; | 135 | static struct rcu_torture rcu_tortures[10 * RCU_TORTURE_PIPE_LEN]; |
136 | static DEFINE_SPINLOCK(rcu_torture_lock); | 136 | static DEFINE_SPINLOCK(rcu_torture_lock); |
137 | static DEFINE_PER_CPU(long [RCU_TORTURE_PIPE_LEN + 1], rcu_torture_count) = | 137 | static DEFINE_PER_CPU(long [RCU_TORTURE_PIPE_LEN + 1], rcu_torture_count) = |
@@ -884,7 +884,7 @@ rcu_torture_writer(void *arg) | |||
884 | old_rp->rtort_pipe_count++; | 884 | old_rp->rtort_pipe_count++; |
885 | cur_ops->deferred_free(old_rp); | 885 | cur_ops->deferred_free(old_rp); |
886 | } | 886 | } |
887 | rcu_torture_current_version++; | 887 | rcutorture_record_progress(++rcu_torture_current_version); |
888 | oldbatch = cur_ops->completed(); | 888 | oldbatch = cur_ops->completed(); |
889 | rcu_stutter_wait("rcu_torture_writer"); | 889 | rcu_stutter_wait("rcu_torture_writer"); |
890 | } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP); | 890 | } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP); |
@@ -1064,7 +1064,7 @@ rcu_torture_printk(char *page) | |||
1064 | } | 1064 | } |
1065 | cnt += sprintf(&page[cnt], "%s%s ", torture_type, TORTURE_FLAG); | 1065 | cnt += sprintf(&page[cnt], "%s%s ", torture_type, TORTURE_FLAG); |
1066 | cnt += sprintf(&page[cnt], | 1066 | cnt += sprintf(&page[cnt], |
1067 | "rtc: %p ver: %ld tfle: %d rta: %d rtaf: %d rtf: %d " | 1067 | "rtc: %p ver: %lu tfle: %d rta: %d rtaf: %d rtf: %d " |
1068 | "rtmbe: %d rtbke: %ld rtbre: %ld " | 1068 | "rtmbe: %d rtbke: %ld rtbre: %ld " |
1069 | "rtbf: %ld rtb: %ld nt: %ld", | 1069 | "rtbf: %ld rtb: %ld nt: %ld", |
1070 | rcu_torture_current, | 1070 | rcu_torture_current, |
@@ -1325,6 +1325,7 @@ rcu_torture_cleanup(void) | |||
1325 | int i; | 1325 | int i; |
1326 | 1326 | ||
1327 | mutex_lock(&fullstop_mutex); | 1327 | mutex_lock(&fullstop_mutex); |
1328 | rcutorture_record_test_transition(); | ||
1328 | if (fullstop == FULLSTOP_SHUTDOWN) { | 1329 | if (fullstop == FULLSTOP_SHUTDOWN) { |
1329 | printk(KERN_WARNING /* but going down anyway, so... */ | 1330 | printk(KERN_WARNING /* but going down anyway, so... */ |
1330 | "Concurrent 'rmmod rcutorture' and shutdown illegal!\n"); | 1331 | "Concurrent 'rmmod rcutorture' and shutdown illegal!\n"); |
@@ -1616,6 +1617,7 @@ rcu_torture_init(void) | |||
1616 | } | 1617 | } |
1617 | } | 1618 | } |
1618 | register_reboot_notifier(&rcutorture_shutdown_nb); | 1619 | register_reboot_notifier(&rcutorture_shutdown_nb); |
1620 | rcutorture_record_test_transition(); | ||
1619 | mutex_unlock(&fullstop_mutex); | 1621 | mutex_unlock(&fullstop_mutex); |
1620 | return 0; | 1622 | return 0; |
1621 | 1623 | ||
diff --git a/kernel/rcutree.c b/kernel/rcutree.c index d8917401cbbc..bb84deca3319 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c | |||
@@ -102,6 +102,18 @@ static void invoke_rcu_cpu_kthread(void); | |||
102 | #define RCU_KTHREAD_PRIO 1 /* RT priority for per-CPU kthreads. */ | 102 | #define RCU_KTHREAD_PRIO 1 /* RT priority for per-CPU kthreads. */ |
103 | 103 | ||
104 | /* | 104 | /* |
105 | * Track the rcutorture test sequence number and the update version | ||
106 | * number within a given test. The rcutorture_testseq is incremented | ||
107 | * on every rcutorture module load and unload, so has an odd value | ||
108 | * when a test is running. The rcutorture_vernum is set to zero | ||
109 | * when rcutorture starts and is incremented on each rcutorture update. | ||
110 | * These variables enable correlating rcutorture output with the | ||
111 | * RCU tracing information. | ||
112 | */ | ||
113 | unsigned long rcutorture_testseq; | ||
114 | unsigned long rcutorture_vernum; | ||
115 | |||
116 | /* | ||
105 | * Return true if an RCU grace period is in progress. The ACCESS_ONCE()s | 117 | * Return true if an RCU grace period is in progress. The ACCESS_ONCE()s |
106 | * permit this function to be invoked without holding the root rcu_node | 118 | * permit this function to be invoked without holding the root rcu_node |
107 | * structure's ->lock, but of course results can be subject to change. | 119 | * structure's ->lock, but of course results can be subject to change. |
@@ -193,6 +205,31 @@ void rcu_bh_force_quiescent_state(void) | |||
193 | EXPORT_SYMBOL_GPL(rcu_bh_force_quiescent_state); | 205 | EXPORT_SYMBOL_GPL(rcu_bh_force_quiescent_state); |
194 | 206 | ||
195 | /* | 207 | /* |
208 | * Record the number of times rcutorture tests have been initiated and | ||
209 | * terminated. This information allows the debugfs tracing stats to be | ||
210 | * correlated to the rcutorture messages, even when the rcutorture module | ||
211 | * is being repeatedly loaded and unloaded. In other words, we cannot | ||
212 | * store this state in rcutorture itself. | ||
213 | */ | ||
214 | void rcutorture_record_test_transition(void) | ||
215 | { | ||
216 | rcutorture_testseq++; | ||
217 | rcutorture_vernum = 0; | ||
218 | } | ||
219 | EXPORT_SYMBOL_GPL(rcutorture_record_test_transition); | ||
220 | |||
221 | /* | ||
222 | * Record the number of writer passes through the current rcutorture test. | ||
223 | * This is also used to correlate debugfs tracing stats with the rcutorture | ||
224 | * messages. | ||
225 | */ | ||
226 | void rcutorture_record_progress(unsigned long vernum) | ||
227 | { | ||
228 | rcutorture_vernum++; | ||
229 | } | ||
230 | EXPORT_SYMBOL_GPL(rcutorture_record_progress); | ||
231 | |||
232 | /* | ||
196 | * Force a quiescent state for RCU-sched. | 233 | * Force a quiescent state for RCU-sched. |
197 | */ | 234 | */ |
198 | void rcu_sched_force_quiescent_state(void) | 235 | void rcu_sched_force_quiescent_state(void) |
diff --git a/kernel/rcutree_trace.c b/kernel/rcutree_trace.c index fc40e89a028c..3baa235786b5 100644 --- a/kernel/rcutree_trace.c +++ b/kernel/rcutree_trace.c | |||
@@ -394,6 +394,29 @@ static const struct file_operations rcu_pending_fops = { | |||
394 | .release = single_release, | 394 | .release = single_release, |
395 | }; | 395 | }; |
396 | 396 | ||
397 | static int show_rcutorture(struct seq_file *m, void *unused) | ||
398 | { | ||
399 | seq_printf(m, "rcutorture test sequence: %lu %s\n", | ||
400 | rcutorture_testseq >> 1, | ||
401 | (rcutorture_testseq & 0x1) ? "(test in progress)" : ""); | ||
402 | seq_printf(m, "rcutorture update version number: %lu\n", | ||
403 | rcutorture_vernum); | ||
404 | return 0; | ||
405 | } | ||
406 | |||
407 | static int rcutorture_open(struct inode *inode, struct file *file) | ||
408 | { | ||
409 | return single_open(file, show_rcutorture, NULL); | ||
410 | } | ||
411 | |||
412 | static const struct file_operations rcutorture_fops = { | ||
413 | .owner = THIS_MODULE, | ||
414 | .open = rcutorture_open, | ||
415 | .read = seq_read, | ||
416 | .llseek = seq_lseek, | ||
417 | .release = single_release, | ||
418 | }; | ||
419 | |||
397 | static struct dentry *rcudir; | 420 | static struct dentry *rcudir; |
398 | 421 | ||
399 | static int __init rcutree_trace_init(void) | 422 | static int __init rcutree_trace_init(void) |
@@ -430,6 +453,11 @@ static int __init rcutree_trace_init(void) | |||
430 | NULL, &rcu_pending_fops); | 453 | NULL, &rcu_pending_fops); |
431 | if (!retval) | 454 | if (!retval) |
432 | goto free_out; | 455 | goto free_out; |
456 | |||
457 | retval = debugfs_create_file("rcutorture", 0444, rcudir, | ||
458 | NULL, &rcutorture_fops); | ||
459 | if (!retval) | ||
460 | goto free_out; | ||
433 | return 0; | 461 | return 0; |
434 | free_out: | 462 | free_out: |
435 | debugfs_remove_recursive(rcudir); | 463 | debugfs_remove_recursive(rcudir); |