aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/rcutorture.c
diff options
context:
space:
mode:
authorPaul E. McKenney <paulmck@linux.vnet.ibm.com>2008-06-25 15:24:52 -0400
committerIngo Molnar <mingo@elte.hu>2008-06-26 03:24:33 -0400
commit0729fbf3bc70870370b4f43d652f05a468dc68b8 (patch)
tree92557b04b368fac084f59d8397c32c5461ac26fd /kernel/rcutorture.c
parent9a13150109fb418c50fa400c012f90d0ce6f67c3 (diff)
rcu: make rcutorture even more vicious: invoke RCU readers from irq handlers (timers)
This patch allows torturing RCU from irq handlers (timers, in this case). A new module parameter irqreader enables such additional torturing, and is enabled by default. Variants of RCU that do not tolerate readers being called from irq handlers (e.g., SRCU) ignore irqreader. Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Cc: josh@freedesktop.org Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: dino@in.ibm.com Cc: akpm@linux-foundation.org Cc: torvalds@linux-foundation.org Cc: vegard.nossum@gmail.com Cc: adobriyan@gmail.com Cc: oleg@tv-sign.ru Cc: bunk@kernel.org Cc: rjw@sisk.pl Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/rcutorture.c')
-rw-r--r--kernel/rcutorture.c74
1 files changed, 70 insertions, 4 deletions
diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c
index 5e954edf0ed5..90b5b123f7a1 100644
--- a/kernel/rcutorture.c
+++ b/kernel/rcutorture.c
@@ -59,6 +59,7 @@ static int verbose; /* Print more debug info. */
59static int test_no_idle_hz; /* Test RCU's support for tickless idle CPUs. */ 59static int test_no_idle_hz; /* Test RCU's support for tickless idle CPUs. */
60static int shuffle_interval = 3; /* Interval between shuffles (in sec)*/ 60static int shuffle_interval = 3; /* Interval between shuffles (in sec)*/
61static int stutter = 5; /* Start/stop testing interval (in sec) */ 61static int stutter = 5; /* Start/stop testing interval (in sec) */
62static int irqreader = 1; /* RCU readers from irq (timers). */
62static char *torture_type = "rcu"; /* What RCU implementation to torture. */ 63static char *torture_type = "rcu"; /* What RCU implementation to torture. */
63 64
64module_param(nreaders, int, 0444); 65module_param(nreaders, int, 0444);
@@ -75,6 +76,8 @@ module_param(shuffle_interval, int, 0444);
75MODULE_PARM_DESC(shuffle_interval, "Number of seconds between shuffles"); 76MODULE_PARM_DESC(shuffle_interval, "Number of seconds between shuffles");
76module_param(stutter, int, 0444); 77module_param(stutter, int, 0444);
77MODULE_PARM_DESC(stutter, "Number of seconds to run/halt test"); 78MODULE_PARM_DESC(stutter, "Number of seconds to run/halt test");
79module_param(irqreader, int, 0444);
80MODULE_PARM_DESC(irqreader, "Allow RCU readers from irq handlers");
78module_param(torture_type, charp, 0444); 81module_param(torture_type, charp, 0444);
79MODULE_PARM_DESC(torture_type, "Type of RCU to torture (rcu, rcu_bh, srcu)"); 82MODULE_PARM_DESC(torture_type, "Type of RCU to torture (rcu, rcu_bh, srcu)");
80 83
@@ -121,6 +124,7 @@ static atomic_t n_rcu_torture_alloc_fail;
121static atomic_t n_rcu_torture_free; 124static atomic_t n_rcu_torture_free;
122static atomic_t n_rcu_torture_mberror; 125static atomic_t n_rcu_torture_mberror;
123static atomic_t n_rcu_torture_error; 126static atomic_t n_rcu_torture_error;
127static long n_rcu_torture_timers = 0;
124static struct list_head rcu_torture_removed; 128static struct list_head rcu_torture_removed;
125 129
126static int stutter_pause_test = 0; 130static int stutter_pause_test = 0;
@@ -217,6 +221,7 @@ struct rcu_torture_ops {
217 void (*sync)(void); 221 void (*sync)(void);
218 void (*cb_barrier)(void); 222 void (*cb_barrier)(void);
219 int (*stats)(char *page); 223 int (*stats)(char *page);
224 int irqcapable;
220 char *name; 225 char *name;
221}; 226};
222static struct rcu_torture_ops *cur_ops = NULL; 227static struct rcu_torture_ops *cur_ops = NULL;
@@ -291,6 +296,7 @@ static struct rcu_torture_ops rcu_ops = {
291 .sync = synchronize_rcu, 296 .sync = synchronize_rcu,
292 .cb_barrier = rcu_barrier, 297 .cb_barrier = rcu_barrier,
293 .stats = NULL, 298 .stats = NULL,
299 .irqcapable = 1,
294 .name = "rcu" 300 .name = "rcu"
295}; 301};
296 302
@@ -331,6 +337,7 @@ static struct rcu_torture_ops rcu_sync_ops = {
331 .sync = synchronize_rcu, 337 .sync = synchronize_rcu,
332 .cb_barrier = NULL, 338 .cb_barrier = NULL,
333 .stats = NULL, 339 .stats = NULL,
340 .irqcapable = 1,
334 .name = "rcu_sync" 341 .name = "rcu_sync"
335}; 342};
336 343
@@ -392,6 +399,7 @@ static struct rcu_torture_ops rcu_bh_ops = {
392 .sync = rcu_bh_torture_synchronize, 399 .sync = rcu_bh_torture_synchronize,
393 .cb_barrier = rcu_barrier_bh, 400 .cb_barrier = rcu_barrier_bh,
394 .stats = NULL, 401 .stats = NULL,
402 .irqcapable = 1,
395 .name = "rcu_bh" 403 .name = "rcu_bh"
396}; 404};
397 405
@@ -406,6 +414,7 @@ static struct rcu_torture_ops rcu_bh_sync_ops = {
406 .sync = rcu_bh_torture_synchronize, 414 .sync = rcu_bh_torture_synchronize,
407 .cb_barrier = NULL, 415 .cb_barrier = NULL,
408 .stats = NULL, 416 .stats = NULL,
417 .irqcapable = 1,
409 .name = "rcu_bh_sync" 418 .name = "rcu_bh_sync"
410}; 419};
411 420
@@ -532,6 +541,7 @@ static struct rcu_torture_ops sched_ops = {
532 .sync = sched_torture_synchronize, 541 .sync = sched_torture_synchronize,
533 .cb_barrier = rcu_barrier_sched, 542 .cb_barrier = rcu_barrier_sched,
534 .stats = NULL, 543 .stats = NULL,
544 .irqcapable = 1,
535 .name = "sched" 545 .name = "sched"
536}; 546};
537 547
@@ -620,6 +630,52 @@ rcu_torture_fakewriter(void *arg)
620} 630}
621 631
622/* 632/*
633 * RCU torture reader from timer handler. Dereferences rcu_torture_current,
634 * incrementing the corresponding element of the pipeline array. The
635 * counter in the element should never be greater than 1, otherwise, the
636 * RCU implementation is broken.
637 */
638static void rcu_torture_timer(unsigned long unused)
639{
640 int idx;
641 int completed;
642 static DEFINE_RCU_RANDOM(rand);
643 static DEFINE_SPINLOCK(rand_lock);
644 struct rcu_torture *p;
645 int pipe_count;
646
647 idx = cur_ops->readlock();
648 completed = cur_ops->completed();
649 p = rcu_dereference(rcu_torture_current);
650 if (p == NULL) {
651 /* Leave because rcu_torture_writer is not yet underway */
652 cur_ops->readunlock(idx);
653 return;
654 }
655 if (p->rtort_mbtest == 0)
656 atomic_inc(&n_rcu_torture_mberror);
657 spin_lock(&rand_lock);
658 cur_ops->readdelay(&rand);
659 n_rcu_torture_timers++;
660 spin_unlock(&rand_lock);
661 preempt_disable();
662 pipe_count = p->rtort_pipe_count;
663 if (pipe_count > RCU_TORTURE_PIPE_LEN) {
664 /* Should not happen, but... */
665 pipe_count = RCU_TORTURE_PIPE_LEN;
666 }
667 ++__get_cpu_var(rcu_torture_count)[pipe_count];
668 completed = cur_ops->completed() - completed;
669 if (completed > RCU_TORTURE_PIPE_LEN) {
670 /* Should not happen, but... */
671 completed = RCU_TORTURE_PIPE_LEN;
672 }
673 ++__get_cpu_var(rcu_torture_batch)[completed];
674 preempt_enable();
675 cur_ops->readunlock(idx);
676}
677
678/*
623 * RCU torture reader kthread. Repeatedly dereferences rcu_torture_current, 679 * RCU torture reader kthread. Repeatedly dereferences rcu_torture_current,
624 * incrementing the corresponding element of the pipeline array. The 680 * incrementing the corresponding element of the pipeline array. The
625 * counter in the element should never be greater than 1, otherwise, the 681 * counter in the element should never be greater than 1, otherwise, the
@@ -633,11 +689,18 @@ rcu_torture_reader(void *arg)
633 DEFINE_RCU_RANDOM(rand); 689 DEFINE_RCU_RANDOM(rand);
634 struct rcu_torture *p; 690 struct rcu_torture *p;
635 int pipe_count; 691 int pipe_count;
692 struct timer_list t;
636 693
637 VERBOSE_PRINTK_STRING("rcu_torture_reader task started"); 694 VERBOSE_PRINTK_STRING("rcu_torture_reader task started");
638 set_user_nice(current, 19); 695 set_user_nice(current, 19);
696 if (irqreader && cur_ops->irqcapable)
697 setup_timer_on_stack(&t, rcu_torture_timer, 0);
639 698
640 do { 699 do {
700 if (irqreader && cur_ops->irqcapable) {
701 if (!timer_pending(&t))
702 mod_timer(&t, 1);
703 }
641 idx = cur_ops->readlock(); 704 idx = cur_ops->readlock();
642 completed = cur_ops->completed(); 705 completed = cur_ops->completed();
643 p = rcu_dereference(rcu_torture_current); 706 p = rcu_dereference(rcu_torture_current);
@@ -669,6 +732,8 @@ rcu_torture_reader(void *arg)
669 rcu_stutter_wait(); 732 rcu_stutter_wait();
670 } while (!kthread_should_stop() && !fullstop); 733 } while (!kthread_should_stop() && !fullstop);
671 VERBOSE_PRINTK_STRING("rcu_torture_reader task stopping"); 734 VERBOSE_PRINTK_STRING("rcu_torture_reader task stopping");
735 if (irqreader && cur_ops->irqcapable)
736 del_timer_sync(&t);
672 while (!kthread_should_stop()) 737 while (!kthread_should_stop())
673 schedule_timeout_uninterruptible(1); 738 schedule_timeout_uninterruptible(1);
674 return 0; 739 return 0;
@@ -699,14 +764,15 @@ rcu_torture_printk(char *page)
699 cnt += sprintf(&page[cnt], "%s%s ", torture_type, TORTURE_FLAG); 764 cnt += sprintf(&page[cnt], "%s%s ", torture_type, TORTURE_FLAG);
700 cnt += sprintf(&page[cnt], 765 cnt += sprintf(&page[cnt],
701 "rtc: %p ver: %ld tfle: %d rta: %d rtaf: %d rtf: %d " 766 "rtc: %p ver: %ld tfle: %d rta: %d rtaf: %d rtf: %d "
702 "rtmbe: %d", 767 "rtmbe: %d nt: %ld",
703 rcu_torture_current, 768 rcu_torture_current,
704 rcu_torture_current_version, 769 rcu_torture_current_version,
705 list_empty(&rcu_torture_freelist), 770 list_empty(&rcu_torture_freelist),
706 atomic_read(&n_rcu_torture_alloc), 771 atomic_read(&n_rcu_torture_alloc),
707 atomic_read(&n_rcu_torture_alloc_fail), 772 atomic_read(&n_rcu_torture_alloc_fail),
708 atomic_read(&n_rcu_torture_free), 773 atomic_read(&n_rcu_torture_free),
709 atomic_read(&n_rcu_torture_mberror)); 774 atomic_read(&n_rcu_torture_mberror),
775 n_rcu_torture_timers);
710 if (atomic_read(&n_rcu_torture_mberror) != 0) 776 if (atomic_read(&n_rcu_torture_mberror) != 0)
711 cnt += sprintf(&page[cnt], " !!!"); 777 cnt += sprintf(&page[cnt], " !!!");
712 cnt += sprintf(&page[cnt], "\n%s%s ", torture_type, TORTURE_FLAG); 778 cnt += sprintf(&page[cnt], "\n%s%s ", torture_type, TORTURE_FLAG);
@@ -862,10 +928,10 @@ rcu_torture_print_module_parms(char *tag)
862 printk(KERN_ALERT "%s" TORTURE_FLAG 928 printk(KERN_ALERT "%s" TORTURE_FLAG
863 "--- %s: nreaders=%d nfakewriters=%d " 929 "--- %s: nreaders=%d nfakewriters=%d "
864 "stat_interval=%d verbose=%d test_no_idle_hz=%d " 930 "stat_interval=%d verbose=%d test_no_idle_hz=%d "
865 "shuffle_interval=%d stutter=%d\n", 931 "shuffle_interval=%d stutter=%d irqreader=%d\n",
866 torture_type, tag, nrealreaders, nfakewriters, 932 torture_type, tag, nrealreaders, nfakewriters,
867 stat_interval, verbose, test_no_idle_hz, shuffle_interval, 933 stat_interval, verbose, test_no_idle_hz, shuffle_interval,
868 stutter); 934 stutter, irqreader);
869} 935}
870 936
871static void 937static void