aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-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