aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/rcutorture.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/rcutorture.c')
-rw-r--r--kernel/rcutorture.c109
1 files changed, 104 insertions, 5 deletions
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) {