aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/RCU/torture.txt9
-rw-r--r--kernel/rcutorture.c109
2 files changed, 113 insertions, 5 deletions
diff --git a/Documentation/RCU/torture.txt b/Documentation/RCU/torture.txt
index 2174badd31e0..2180ef93accc 100644
--- a/Documentation/RCU/torture.txt
+++ b/Documentation/RCU/torture.txt
@@ -28,6 +28,15 @@ nreaders This is the number of RCU reading threads supported.
28 To properly exercise RCU implementations with preemptible 28 To properly exercise RCU implementations with preemptible
29 read-side critical sections. 29 read-side critical sections.
30 30
31nfakewriters This is the number of RCU fake writer threads to run. Fake
32 writer threads repeatedly use the synchronous "wait for
33 current readers" function of the interface selected by
34 torture_type, with a delay between calls to allow for various
35 different numbers of writers running in parallel.
36 nfakewriters defaults to 4, which provides enough parallelism
37 to trigger special cases caused by multiple writers, such as
38 the synchronize_srcu() early return optimization.
39
31stat_interval The number of seconds between output of torture 40stat_interval The number of seconds between output of torture
32 statistics (via printk()). Regardless of the interval, 41 statistics (via printk()). Regardless of the interval,
33 statistics are printed when the module is unloaded. 42 statistics are printed when the module is unloaded.
diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c
index 43d6d4f9ef09..e0450210ce4d 100644
--- a/kernel/rcutorture.c
+++ b/kernel/rcutorture.c
@@ -15,9 +15,10 @@
15 * along with this program; if not, write to the Free Software 15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 * 17 *
18 * Copyright (C) IBM Corporation, 2005 18 * Copyright (C) IBM Corporation, 2005, 2006
19 * 19 *
20 * Authors: Paul E. McKenney <paulmck@us.ibm.com> 20 * Authors: Paul E. McKenney <paulmck@us.ibm.com>
21 * Josh Triplett <josh@freedesktop.org>
21 * 22 *
22 * See also: Documentation/RCU/torture.txt 23 * See also: Documentation/RCU/torture.txt
23 */ 24 */
@@ -47,9 +48,11 @@
47#include <linux/srcu.h> 48#include <linux/srcu.h>
48 49
49MODULE_LICENSE("GPL"); 50MODULE_LICENSE("GPL");
50MODULE_AUTHOR("Paul E. McKenney <paulmck@us.ibm.com>"); 51MODULE_AUTHOR("Paul E. McKenney <paulmck@us.ibm.com> and "
52 "Josh Triplett <josh@freedesktop.org>");
51 53
52static int nreaders = -1; /* # reader threads, defaults to 2*ncpus */ 54static int nreaders = -1; /* # reader threads, defaults to 2*ncpus */
55static int nfakewriters = 4; /* # fake writer threads */
53static int stat_interval; /* Interval between stats, in seconds. */ 56static int stat_interval; /* Interval between stats, in seconds. */
54 /* Defaults to "only at end of test". */ 57 /* Defaults to "only at end of test". */
55static int verbose; /* Print more debug info. */ 58static int verbose; /* Print more debug info. */
@@ -59,6 +62,8 @@ static char *torture_type = "rcu"; /* What to torture: rcu, rcu_bh, srcu. */
59 62
60module_param(nreaders, int, 0); 63module_param(nreaders, int, 0);
61MODULE_PARM_DESC(nreaders, "Number of RCU reader threads"); 64MODULE_PARM_DESC(nreaders, "Number of RCU reader threads");
65module_param(nfakewriters, int, 0);
66MODULE_PARM_DESC(nfakewriters, "Number of RCU fake writer threads");
62module_param(stat_interval, int, 0); 67module_param(stat_interval, int, 0);
63MODULE_PARM_DESC(stat_interval, "Number of seconds between stats printk()s"); 68MODULE_PARM_DESC(stat_interval, "Number of seconds between stats printk()s");
64module_param(verbose, bool, 0); 69module_param(verbose, bool, 0);
@@ -82,6 +87,7 @@ static char printk_buf[4096];
82 87
83static int nrealreaders; 88static int nrealreaders;
84static struct task_struct *writer_task; 89static struct task_struct *writer_task;
90static struct task_struct **fakewriter_tasks;
85static struct task_struct **reader_tasks; 91static struct task_struct **reader_tasks;
86static struct task_struct *stats_task; 92static struct task_struct *stats_task;
87static struct task_struct *shuffler_task; 93static struct task_struct *shuffler_task;
@@ -186,6 +192,7 @@ struct rcu_torture_ops {
186 void (*readunlock)(int idx); 192 void (*readunlock)(int idx);
187 int (*completed)(void); 193 int (*completed)(void);
188 void (*deferredfree)(struct rcu_torture *p); 194 void (*deferredfree)(struct rcu_torture *p);
195 void (*sync)(void);
189 int (*stats)(char *page); 196 int (*stats)(char *page);
190 char *name; 197 char *name;
191}; 198};
@@ -258,6 +265,7 @@ static struct rcu_torture_ops rcu_ops = {
258 .readunlock = rcu_torture_read_unlock, 265 .readunlock = rcu_torture_read_unlock,
259 .completed = rcu_torture_completed, 266 .completed = rcu_torture_completed,
260 .deferredfree = rcu_torture_deferred_free, 267 .deferredfree = rcu_torture_deferred_free,
268 .sync = synchronize_rcu,
261 .stats = NULL, 269 .stats = NULL,
262 .name = "rcu" 270 .name = "rcu"
263}; 271};
@@ -287,6 +295,28 @@ static void rcu_bh_torture_deferred_free(struct rcu_torture *p)
287 call_rcu_bh(&p->rtort_rcu, rcu_torture_cb); 295 call_rcu_bh(&p->rtort_rcu, rcu_torture_cb);
288} 296}
289 297
298struct rcu_bh_torture_synchronize {
299 struct rcu_head head;
300 struct completion completion;
301};
302
303static void rcu_bh_torture_wakeme_after_cb(struct rcu_head *head)
304{
305 struct rcu_bh_torture_synchronize *rcu;
306
307 rcu = container_of(head, struct rcu_bh_torture_synchronize, head);
308 complete(&rcu->completion);
309}
310
311static void rcu_bh_torture_synchronize(void)
312{
313 struct rcu_bh_torture_synchronize rcu;
314
315 init_completion(&rcu.completion);
316 call_rcu_bh(&rcu.head, rcu_bh_torture_wakeme_after_cb);
317 wait_for_completion(&rcu.completion);
318}
319
290static struct rcu_torture_ops rcu_bh_ops = { 320static struct rcu_torture_ops rcu_bh_ops = {
291 .init = NULL, 321 .init = NULL,
292 .cleanup = NULL, 322 .cleanup = NULL,
@@ -295,6 +325,7 @@ static struct rcu_torture_ops rcu_bh_ops = {
295 .readunlock = rcu_bh_torture_read_unlock, 325 .readunlock = rcu_bh_torture_read_unlock,
296 .completed = rcu_bh_torture_completed, 326 .completed = rcu_bh_torture_completed,
297 .deferredfree = rcu_bh_torture_deferred_free, 327 .deferredfree = rcu_bh_torture_deferred_free,
328 .sync = rcu_bh_torture_synchronize,
298 .stats = NULL, 329 .stats = NULL,
299 .name = "rcu_bh" 330 .name = "rcu_bh"
300}; 331};
@@ -367,6 +398,11 @@ static void srcu_torture_deferred_free(struct rcu_torture *p)
367 } 398 }
368} 399}
369 400
401static void srcu_torture_synchronize(void)
402{
403 synchronize_srcu(&srcu_ctl);
404}
405
370static int srcu_torture_stats(char *page) 406static int srcu_torture_stats(char *page)
371{ 407{
372 int cnt = 0; 408 int cnt = 0;
@@ -392,6 +428,7 @@ static struct rcu_torture_ops srcu_ops = {
392 .readunlock = srcu_torture_read_unlock, 428 .readunlock = srcu_torture_read_unlock,
393 .completed = srcu_torture_completed, 429 .completed = srcu_torture_completed,
394 .deferredfree = srcu_torture_deferred_free, 430 .deferredfree = srcu_torture_deferred_free,
431 .sync = srcu_torture_synchronize,
395 .stats = srcu_torture_stats, 432 .stats = srcu_torture_stats,
396 .name = "srcu" 433 .name = "srcu"
397}; 434};
@@ -444,6 +481,30 @@ rcu_torture_writer(void *arg)
444} 481}
445 482
446/* 483/*
484 * RCU torture fake writer kthread. Repeatedly calls sync, with a random
485 * delay between calls.
486 */
487static int
488rcu_torture_fakewriter(void *arg)
489{
490 DEFINE_RCU_RANDOM(rand);
491
492 VERBOSE_PRINTK_STRING("rcu_torture_fakewriter task started");
493 set_user_nice(current, 19);
494
495 do {
496 schedule_timeout_uninterruptible(1 + rcu_random(&rand)%10);
497 udelay(rcu_random(&rand) & 0x3ff);
498 cur_ops->sync();
499 } while (!kthread_should_stop() && !fullstop);
500
501 VERBOSE_PRINTK_STRING("rcu_torture_fakewriter task stopping");
502 while (!kthread_should_stop())
503 schedule_timeout_uninterruptible(1);
504 return 0;
505}
506
507/*
447 * RCU torture reader kthread. Repeatedly dereferences rcu_torture_current, 508 * RCU torture reader kthread. Repeatedly dereferences rcu_torture_current,
448 * incrementing the corresponding element of the pipeline array. The 509 * incrementing the corresponding element of the pipeline array. The
449 * counter in the element should never be greater than 1, otherwise, the 510 * counter in the element should never be greater than 1, otherwise, the
@@ -621,6 +682,12 @@ static void rcu_torture_shuffle_tasks(void)
621 set_cpus_allowed(reader_tasks[i], tmp_mask); 682 set_cpus_allowed(reader_tasks[i], tmp_mask);
622 } 683 }
623 684
685 if (fakewriter_tasks != NULL) {
686 for (i = 0; i < nfakewriters; i++)
687 if (fakewriter_tasks[i])
688 set_cpus_allowed(fakewriter_tasks[i], tmp_mask);
689 }
690
624 if (writer_task) 691 if (writer_task)
625 set_cpus_allowed(writer_task, tmp_mask); 692 set_cpus_allowed(writer_task, tmp_mask);
626 693
@@ -654,11 +721,12 @@ rcu_torture_shuffle(void *arg)
654static inline void 721static inline void
655rcu_torture_print_module_parms(char *tag) 722rcu_torture_print_module_parms(char *tag)
656{ 723{
657 printk(KERN_ALERT "%s" TORTURE_FLAG "--- %s: nreaders=%d " 724 printk(KERN_ALERT "%s" TORTURE_FLAG
725 "--- %s: nreaders=%d nfakewriters=%d "
658 "stat_interval=%d verbose=%d test_no_idle_hz=%d " 726 "stat_interval=%d verbose=%d test_no_idle_hz=%d "
659 "shuffle_interval = %d\n", 727 "shuffle_interval = %d\n",
660 torture_type, tag, nrealreaders, stat_interval, verbose, 728 torture_type, tag, nrealreaders, nfakewriters,
661 test_no_idle_hz, shuffle_interval); 729 stat_interval, verbose, test_no_idle_hz, shuffle_interval);
662} 730}
663 731
664static void 732static void
@@ -693,6 +761,19 @@ rcu_torture_cleanup(void)
693 } 761 }
694 rcu_torture_current = NULL; 762 rcu_torture_current = NULL;
695 763
764 if (fakewriter_tasks != NULL) {
765 for (i = 0; i < nfakewriters; i++) {
766 if (fakewriter_tasks[i] != NULL) {
767 VERBOSE_PRINTK_STRING(
768 "Stopping rcu_torture_fakewriter task");
769 kthread_stop(fakewriter_tasks[i]);
770 }
771 fakewriter_tasks[i] = NULL;
772 }
773 kfree(fakewriter_tasks);
774 fakewriter_tasks = NULL;
775 }
776
696 if (stats_task != NULL) { 777 if (stats_task != NULL) {
697 VERBOSE_PRINTK_STRING("Stopping rcu_torture_stats task"); 778 VERBOSE_PRINTK_STRING("Stopping rcu_torture_stats task");
698 kthread_stop(stats_task); 779 kthread_stop(stats_task);
@@ -780,6 +861,24 @@ rcu_torture_init(void)
780 writer_task = NULL; 861 writer_task = NULL;
781 goto unwind; 862 goto unwind;
782 } 863 }
864 fakewriter_tasks = kzalloc(nfakewriters * sizeof(fakewriter_tasks[0]),
865 GFP_KERNEL);
866 if (fakewriter_tasks == NULL) {
867 VERBOSE_PRINTK_ERRSTRING("out of memory");
868 firsterr = -ENOMEM;
869 goto unwind;
870 }
871 for (i = 0; i < nfakewriters; i++) {
872 VERBOSE_PRINTK_STRING("Creating rcu_torture_fakewriter task");
873 fakewriter_tasks[i] = kthread_run(rcu_torture_fakewriter, NULL,
874 "rcu_torture_fakewriter");
875 if (IS_ERR(fakewriter_tasks[i])) {
876 firsterr = PTR_ERR(fakewriter_tasks[i]);
877 VERBOSE_PRINTK_ERRSTRING("Failed to create fakewriter");
878 fakewriter_tasks[i] = NULL;
879 goto unwind;
880 }
881 }
783 reader_tasks = kzalloc(nrealreaders * sizeof(reader_tasks[0]), 882 reader_tasks = kzalloc(nrealreaders * sizeof(reader_tasks[0]),
784 GFP_KERNEL); 883 GFP_KERNEL);
785 if (reader_tasks == NULL) { 884 if (reader_tasks == NULL) {