aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/rcu
diff options
context:
space:
mode:
authorPaul E. McKenney <paulmck@linux.vnet.ibm.com>2014-08-19 00:12:17 -0400
committerPaul E. McKenney <paulmck@linux.vnet.ibm.com>2014-09-07 19:24:48 -0400
commit38706bc5a29a73645e512c06ffb759fb56259d83 (patch)
tree1bdc7a71e1f1b0b7be46c139c2673bb05dd90cb4 /kernel/rcu
parenteea203fea3484598280a07fe503e025e886297fb (diff)
rcutorture: Add callback-flood test
Although RCU is designed to handle arbitrary floods of callbacks, this capability is not routinely tested. This commit therefore adds a cbflood capability in which kthreads repeatedly registers large numbers of callbacks. One such kthread is created for each four CPUs (rounding up), and the test may be controlled by several cbflood_* kernel boot parameters, which control the number of bursts per flood, the number of callbacks per burst, the time between bursts, and the time between floods. The default values are large enough to exercise RCU's emergency responses to callback flooding. Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Cc: David Miller <davem@davemloft.net> Reviewed-by: Pranith Kumar <bobby.prani@gmail.com>
Diffstat (limited to 'kernel/rcu')
-rw-r--r--kernel/rcu/rcutorture.c86
1 files changed, 85 insertions, 1 deletions
diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c
index ff4f0c756dee..0bcd53adac73 100644
--- a/kernel/rcu/rcutorture.c
+++ b/kernel/rcu/rcutorture.c
@@ -49,11 +49,19 @@
49#include <linux/trace_clock.h> 49#include <linux/trace_clock.h>
50#include <asm/byteorder.h> 50#include <asm/byteorder.h>
51#include <linux/torture.h> 51#include <linux/torture.h>
52#include <linux/vmalloc.h>
52 53
53MODULE_LICENSE("GPL"); 54MODULE_LICENSE("GPL");
54MODULE_AUTHOR("Paul E. McKenney <paulmck@us.ibm.com> and Josh Triplett <josh@joshtriplett.org>"); 55MODULE_AUTHOR("Paul E. McKenney <paulmck@us.ibm.com> and Josh Triplett <josh@joshtriplett.org>");
55 56
56 57
58torture_param(int, cbflood_inter_holdoff, HZ,
59 "Holdoff between floods (jiffies)");
60torture_param(int, cbflood_intra_holdoff, 1,
61 "Holdoff between bursts (jiffies)");
62torture_param(int, cbflood_n_burst, 3, "# bursts in flood, zero to disable");
63torture_param(int, cbflood_n_per_burst, 20000,
64 "# callbacks per burst in flood");
57torture_param(int, fqs_duration, 0, 65torture_param(int, fqs_duration, 0,
58 "Duration of fqs bursts (us), 0 to disable"); 66 "Duration of fqs bursts (us), 0 to disable");
59torture_param(int, fqs_holdoff, 0, "Holdoff time within fqs bursts (us)"); 67torture_param(int, fqs_holdoff, 0, "Holdoff time within fqs bursts (us)");
@@ -96,10 +104,12 @@ module_param(torture_type, charp, 0444);
96MODULE_PARM_DESC(torture_type, "Type of RCU to torture (rcu, rcu_bh, ...)"); 104MODULE_PARM_DESC(torture_type, "Type of RCU to torture (rcu, rcu_bh, ...)");
97 105
98static int nrealreaders; 106static int nrealreaders;
107static int ncbflooders;
99static struct task_struct *writer_task; 108static struct task_struct *writer_task;
100static struct task_struct **fakewriter_tasks; 109static struct task_struct **fakewriter_tasks;
101static struct task_struct **reader_tasks; 110static struct task_struct **reader_tasks;
102static struct task_struct *stats_task; 111static struct task_struct *stats_task;
112static struct task_struct **cbflood_task;
103static struct task_struct *fqs_task; 113static struct task_struct *fqs_task;
104static struct task_struct *boost_tasks[NR_CPUS]; 114static struct task_struct *boost_tasks[NR_CPUS];
105static struct task_struct *stall_task; 115static struct task_struct *stall_task;
@@ -138,6 +148,7 @@ static long n_rcu_torture_boosts;
138static long n_rcu_torture_timers; 148static long n_rcu_torture_timers;
139static long n_barrier_attempts; 149static long n_barrier_attempts;
140static long n_barrier_successes; 150static long n_barrier_successes;
151static atomic_long_t n_cbfloods;
141static struct list_head rcu_torture_removed; 152static struct list_head rcu_torture_removed;
142 153
143static int rcu_torture_writer_state; 154static int rcu_torture_writer_state;
@@ -707,6 +718,58 @@ checkwait: stutter_wait("rcu_torture_boost");
707 return 0; 718 return 0;
708} 719}
709 720
721static void rcu_torture_cbflood_cb(struct rcu_head *rhp)
722{
723}
724
725/*
726 * RCU torture callback-flood kthread. Repeatedly induces bursts of calls
727 * to call_rcu() or analogous, increasing the probability of occurrence
728 * of callback-overflow corner cases.
729 */
730static int
731rcu_torture_cbflood(void *arg)
732{
733 int err = 1;
734 int i;
735 int j;
736 struct rcu_head *rhp;
737
738 if (cbflood_n_per_burst > 0 &&
739 cbflood_inter_holdoff > 0 &&
740 cbflood_intra_holdoff > 0 &&
741 cur_ops->call &&
742 cur_ops->cb_barrier) {
743 rhp = vmalloc(sizeof(*rhp) *
744 cbflood_n_burst * cbflood_n_per_burst);
745 err = !rhp;
746 }
747 if (err) {
748 VERBOSE_TOROUT_STRING("rcu_torture_cbflood disabled: Bad args or OOM");
749 while (!torture_must_stop())
750 schedule_timeout_interruptible(HZ);
751 return 0;
752 }
753 VERBOSE_TOROUT_STRING("rcu_torture_cbflood task started");
754 do {
755 schedule_timeout_interruptible(cbflood_inter_holdoff);
756 atomic_long_inc(&n_cbfloods);
757 WARN_ON(signal_pending(current));
758 for (i = 0; i < cbflood_n_burst; i++) {
759 for (j = 0; j < cbflood_n_per_burst; j++) {
760 cur_ops->call(&rhp[i * cbflood_n_per_burst + j],
761 rcu_torture_cbflood_cb);
762 }
763 schedule_timeout_interruptible(cbflood_intra_holdoff);
764 WARN_ON(signal_pending(current));
765 }
766 cur_ops->cb_barrier();
767 stutter_wait("rcu_torture_cbflood");
768 } while (!torture_must_stop());
769 torture_kthread_stopping("rcu_torture_cbflood");
770 return 0;
771}
772
710/* 773/*
711 * RCU torture force-quiescent-state kthread. Repeatedly induces 774 * RCU torture force-quiescent-state kthread. Repeatedly induces
712 * bursts of calls to force_quiescent_state(), increasing the probability 775 * bursts of calls to force_quiescent_state(), increasing the probability
@@ -1075,10 +1138,11 @@ rcu_torture_stats_print(void)
1075 n_rcu_torture_boosts, 1138 n_rcu_torture_boosts,
1076 n_rcu_torture_timers); 1139 n_rcu_torture_timers);
1077 torture_onoff_stats(); 1140 torture_onoff_stats();
1078 pr_cont("barrier: %ld/%ld:%ld\n", 1141 pr_cont("barrier: %ld/%ld:%ld ",
1079 n_barrier_successes, 1142 n_barrier_successes,
1080 n_barrier_attempts, 1143 n_barrier_attempts,
1081 n_rcu_torture_barrier_error); 1144 n_rcu_torture_barrier_error);
1145 pr_cont("cbflood: %ld\n", atomic_long_read(&n_cbfloods));
1082 1146
1083 pr_alert("%s%s ", torture_type, TORTURE_FLAG); 1147 pr_alert("%s%s ", torture_type, TORTURE_FLAG);
1084 if (atomic_read(&n_rcu_torture_mberror) != 0 || 1148 if (atomic_read(&n_rcu_torture_mberror) != 0 ||
@@ -1432,6 +1496,8 @@ rcu_torture_cleanup(void)
1432 1496
1433 torture_stop_kthread(rcu_torture_stats, stats_task); 1497 torture_stop_kthread(rcu_torture_stats, stats_task);
1434 torture_stop_kthread(rcu_torture_fqs, fqs_task); 1498 torture_stop_kthread(rcu_torture_fqs, fqs_task);
1499 for (i = 0; i < ncbflooders; i++)
1500 torture_stop_kthread(rcu_torture_cbflood, cbflood_task[i]);
1435 if ((test_boost == 1 && cur_ops->can_boost) || 1501 if ((test_boost == 1 && cur_ops->can_boost) ||
1436 test_boost == 2) { 1502 test_boost == 2) {
1437 unregister_cpu_notifier(&rcutorture_cpu_nb); 1503 unregister_cpu_notifier(&rcutorture_cpu_nb);
@@ -1678,6 +1744,24 @@ rcu_torture_init(void)
1678 goto unwind; 1744 goto unwind;
1679 if (object_debug) 1745 if (object_debug)
1680 rcu_test_debug_objects(); 1746 rcu_test_debug_objects();
1747 if (cbflood_n_burst > 0) {
1748 /* Create the cbflood threads */
1749 ncbflooders = (num_online_cpus() + 3) / 4;
1750 cbflood_task = kcalloc(ncbflooders, sizeof(*cbflood_task),
1751 GFP_KERNEL);
1752 if (!cbflood_task) {
1753 VERBOSE_TOROUT_ERRSTRING("out of memory");
1754 firsterr = -ENOMEM;
1755 goto unwind;
1756 }
1757 for (i = 0; i < ncbflooders; i++) {
1758 firsterr = torture_create_kthread(rcu_torture_cbflood,
1759 NULL,
1760 cbflood_task[i]);
1761 if (firsterr)
1762 goto unwind;
1763 }
1764 }
1681 rcutorture_record_test_transition(); 1765 rcutorture_record_test_transition();
1682 torture_init_end(); 1766 torture_init_end();
1683 return 0; 1767 return 0;