rcu: make rcutorture version numbers available through debugfs
authorPaul E. McKenney <paul.mckenney@linaro.org>
Mon, 4 Apr 2011 04:33:51 +0000 (21:33 -0700)
committerPaul E. McKenney <paulmck@linux.vnet.ibm.com>
Fri, 6 May 2011 06:16:56 +0000 (23:16 -0700)
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>
include/linux/rcupdate.h
include/linux/rcutree.h
kernel/rcutorture.c
kernel/rcutree.c
kernel/rcutree_trace.c

index ff422d2b7f9012661e36a89213159db7da309f4e..9e169c2ba91f9008b29ca31435a3127d2df7d508 100644 (file)
 extern int rcutorture_runnable; /* for sysctl */
 #endif /* #ifdef CONFIG_RCU_TORTURE_TEST */
 
+#if defined(CONFIG_TREE_RCU) || defined(CONFIG_TREE_PREEMPT_RCU)
+extern void rcutorture_record_test_transition(void);
+extern void rcutorture_record_progress(unsigned long vernum);
+#else
+static inline void rcutorture_record_test_transition(void)
+{
+}
+static inline void rcutorture_record_progress(unsigned long vernum)
+{
+}
+#endif
+
 #define UINT_CMP_GE(a, b)      (UINT_MAX / 2 >= (a) - (b))
 #define UINT_CMP_LT(a, b)      (UINT_MAX / 2 < (a) - (b))
 #define ULONG_CMP_GE(a, b)     (ULONG_MAX / 2 >= (a) - (b))
@@ -68,7 +80,6 @@ extern void call_rcu_sched(struct rcu_head *head,
 extern void synchronize_sched(void);
 extern void rcu_barrier_bh(void);
 extern void rcu_barrier_sched(void);
-extern int sched_expedited_torture_stats(char *page);
 
 static inline void __rcu_read_lock_bh(void)
 {
index 3a933482734aeccbafc7a0bb735be11ede47cbd2..284dad10c55bcc358d11dbea565e4853726ef5fc 100644 (file)
@@ -58,9 +58,12 @@ static inline void synchronize_rcu_bh_expedited(void)
 
 extern void rcu_barrier(void);
 
+extern unsigned long rcutorture_testseq;
+extern unsigned long rcutorture_vernum;
 extern long rcu_batches_completed(void);
 extern long rcu_batches_completed_bh(void);
 extern long rcu_batches_completed_sched(void);
+
 extern void rcu_force_quiescent_state(void);
 extern void rcu_bh_force_quiescent_state(void);
 extern void rcu_sched_force_quiescent_state(void);
index 22b0e74e7d9908d684cf27be1aba37d5bf3d7d97..c2f58ec2475121d574ed66d96a53a7db16792be2 100644 (file)
@@ -131,7 +131,7 @@ struct rcu_torture {
 
 static LIST_HEAD(rcu_torture_freelist);
 static struct rcu_torture __rcu *rcu_torture_current;
-static long rcu_torture_current_version;
+static unsigned long rcu_torture_current_version;
 static struct rcu_torture rcu_tortures[10 * RCU_TORTURE_PIPE_LEN];
 static DEFINE_SPINLOCK(rcu_torture_lock);
 static DEFINE_PER_CPU(long [RCU_TORTURE_PIPE_LEN + 1], rcu_torture_count) =
@@ -884,7 +884,7 @@ rcu_torture_writer(void *arg)
                        old_rp->rtort_pipe_count++;
                        cur_ops->deferred_free(old_rp);
                }
-               rcu_torture_current_version++;
+               rcutorture_record_progress(++rcu_torture_current_version);
                oldbatch = cur_ops->completed();
                rcu_stutter_wait("rcu_torture_writer");
        } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP);
@@ -1064,7 +1064,7 @@ rcu_torture_printk(char *page)
        }
        cnt += sprintf(&page[cnt], "%s%s ", torture_type, TORTURE_FLAG);
        cnt += sprintf(&page[cnt],
-                      "rtc: %p ver: %ld tfle: %d rta: %d rtaf: %d rtf: %d "
+                      "rtc: %p ver: %lu tfle: %d rta: %d rtaf: %d rtf: %d "
                       "rtmbe: %d rtbke: %ld rtbre: %ld "
                       "rtbf: %ld rtb: %ld nt: %ld",
                       rcu_torture_current,
@@ -1325,6 +1325,7 @@ rcu_torture_cleanup(void)
        int i;
 
        mutex_lock(&fullstop_mutex);
+       rcutorture_record_test_transition();
        if (fullstop == FULLSTOP_SHUTDOWN) {
                printk(KERN_WARNING /* but going down anyway, so... */
                       "Concurrent 'rmmod rcutorture' and shutdown illegal!\n");
@@ -1616,6 +1617,7 @@ rcu_torture_init(void)
                }
        }
        register_reboot_notifier(&rcutorture_shutdown_nb);
+       rcutorture_record_test_transition();
        mutex_unlock(&fullstop_mutex);
        return 0;
 
index d8917401cbbc65c205e8c5969e410bf0d747a1f9..bb84deca3319bc114845cfbf88518f89bd1556d9 100644 (file)
@@ -101,6 +101,18 @@ static void invoke_rcu_cpu_kthread(void);
 
 #define RCU_KTHREAD_PRIO 1     /* RT priority for per-CPU kthreads. */
 
+/*
+ * Track the rcutorture test sequence number and the update version
+ * number within a given test.  The rcutorture_testseq is incremented
+ * on every rcutorture module load and unload, so has an odd value
+ * when a test is running.  The rcutorture_vernum is set to zero
+ * when rcutorture starts and is incremented on each rcutorture update.
+ * These variables enable correlating rcutorture output with the
+ * RCU tracing information.
+ */
+unsigned long rcutorture_testseq;
+unsigned long rcutorture_vernum;
+
 /*
  * Return true if an RCU grace period is in progress.  The ACCESS_ONCE()s
  * permit this function to be invoked without holding the root rcu_node
@@ -192,6 +204,31 @@ void rcu_bh_force_quiescent_state(void)
 }
 EXPORT_SYMBOL_GPL(rcu_bh_force_quiescent_state);
 
+/*
+ * Record the number of times rcutorture tests have been initiated and
+ * terminated.  This information allows the debugfs tracing stats to be
+ * correlated to the rcutorture messages, even when the rcutorture module
+ * is being repeatedly loaded and unloaded.  In other words, we cannot
+ * store this state in rcutorture itself.
+ */
+void rcutorture_record_test_transition(void)
+{
+       rcutorture_testseq++;
+       rcutorture_vernum = 0;
+}
+EXPORT_SYMBOL_GPL(rcutorture_record_test_transition);
+
+/*
+ * Record the number of writer passes through the current rcutorture test.
+ * This is also used to correlate debugfs tracing stats with the rcutorture
+ * messages.
+ */
+void rcutorture_record_progress(unsigned long vernum)
+{
+       rcutorture_vernum++;
+}
+EXPORT_SYMBOL_GPL(rcutorture_record_progress);
+
 /*
  * Force a quiescent state for RCU-sched.
  */
index fc40e89a028ca0a2781996f51277227a7499355e..3baa235786b568e0e6334be907a41fa10f9182ec 100644 (file)
@@ -394,6 +394,29 @@ static const struct file_operations rcu_pending_fops = {
        .release = single_release,
 };
 
+static int show_rcutorture(struct seq_file *m, void *unused)
+{
+       seq_printf(m, "rcutorture test sequence: %lu %s\n",
+                  rcutorture_testseq >> 1,
+                  (rcutorture_testseq & 0x1) ? "(test in progress)" : "");
+       seq_printf(m, "rcutorture update version number: %lu\n",
+                  rcutorture_vernum);
+       return 0;
+}
+
+static int rcutorture_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, show_rcutorture, NULL);
+}
+
+static const struct file_operations rcutorture_fops = {
+       .owner = THIS_MODULE,
+       .open = rcutorture_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+};
+
 static struct dentry *rcudir;
 
 static int __init rcutree_trace_init(void)
@@ -430,6 +453,11 @@ static int __init rcutree_trace_init(void)
                                                NULL, &rcu_pending_fops);
        if (!retval)
                goto free_out;
+
+       retval = debugfs_create_file("rcutorture", 0444, rcudir,
+                                               NULL, &rcutorture_fops);
+       if (!retval)
+               goto free_out;
        return 0;
 free_out:
        debugfs_remove_recursive(rcudir);