Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Paul E. McKenney and committed by
Ingo Molnar
0729fbf3 9a131501

+84 -13
+14 -9
Documentation/RCU/torture.txt
··· 30 30 31 31 This module has the following parameters: 32 32 33 - nreaders This is the number of RCU reading threads supported. 34 - The default is twice the number of CPUs. Why twice? 35 - To properly exercise RCU implementations with preemptible 36 - read-side critical sections. 33 + irqreaders Says to invoke RCU readers from irq level. This is currently 34 + done via timers. Defaults to "1" for variants of RCU that 35 + permit this. (Or, more accurately, variants of RCU that do 36 + -not- permit this know to ignore this variable.) 37 37 38 38 nfakewriters This is the number of RCU fake writer threads to run. Fake 39 39 writer threads repeatedly use the synchronous "wait for ··· 44 44 to trigger special cases caused by multiple writers, such as 45 45 the synchronize_srcu() early return optimization. 46 46 47 + nreaders This is the number of RCU reading threads supported. 48 + The default is twice the number of CPUs. Why twice? 49 + To properly exercise RCU implementations with preemptible 50 + read-side critical sections. 51 + 52 + shuffle_interval 53 + The number of seconds to keep the test threads affinitied 54 + to a particular subset of the CPUs, defaults to 3 seconds. 55 + Used in conjunction with test_no_idle_hz. 56 + 47 57 stat_interval The number of seconds between output of torture 48 58 statistics (via printk()). Regardless of the interval, 49 59 statistics are printed when the module is unloaded. 50 60 Setting the interval to zero causes the statistics to 51 61 be printed -only- when the module is unloaded, and this 52 62 is the default. 53 - 54 - shuffle_interval 55 - The number of seconds to keep the test threads affinitied 56 - to a particular subset of the CPUs, defaults to 3 seconds. 57 - Used in conjunction with test_no_idle_hz. 58 63 59 64 stutter The length of time to run the test before pausing for this 60 65 same period of time. Defaults to "stutter=5", so as
+70 -4
kernel/rcutorture.c
··· 59 59 static int test_no_idle_hz; /* Test RCU's support for tickless idle CPUs. */ 60 60 static int shuffle_interval = 3; /* Interval between shuffles (in sec)*/ 61 61 static int stutter = 5; /* Start/stop testing interval (in sec) */ 62 + static int irqreader = 1; /* RCU readers from irq (timers). */ 62 63 static char *torture_type = "rcu"; /* What RCU implementation to torture. */ 63 64 64 65 module_param(nreaders, int, 0444); ··· 76 75 MODULE_PARM_DESC(shuffle_interval, "Number of seconds between shuffles"); 77 76 module_param(stutter, int, 0444); 78 77 MODULE_PARM_DESC(stutter, "Number of seconds to run/halt test"); 78 + module_param(irqreader, int, 0444); 79 + MODULE_PARM_DESC(irqreader, "Allow RCU readers from irq handlers"); 79 80 module_param(torture_type, charp, 0444); 80 81 MODULE_PARM_DESC(torture_type, "Type of RCU to torture (rcu, rcu_bh, srcu)"); 81 82 ··· 124 121 static atomic_t n_rcu_torture_free; 125 122 static atomic_t n_rcu_torture_mberror; 126 123 static atomic_t n_rcu_torture_error; 124 + static long n_rcu_torture_timers = 0; 127 125 static struct list_head rcu_torture_removed; 128 126 129 127 static int stutter_pause_test = 0; ··· 221 217 void (*sync)(void); 222 218 void (*cb_barrier)(void); 223 219 int (*stats)(char *page); 220 + int irqcapable; 224 221 char *name; 225 222 }; 226 223 static struct rcu_torture_ops *cur_ops = NULL; ··· 296 291 .sync = synchronize_rcu, 297 292 .cb_barrier = rcu_barrier, 298 293 .stats = NULL, 294 + .irqcapable = 1, 299 295 .name = "rcu" 300 296 }; 301 297 ··· 337 331 .sync = synchronize_rcu, 338 332 .cb_barrier = NULL, 339 333 .stats = NULL, 334 + .irqcapable = 1, 340 335 .name = "rcu_sync" 341 336 }; 342 337 ··· 399 392 .sync = rcu_bh_torture_synchronize, 400 393 .cb_barrier = rcu_barrier_bh, 401 394 .stats = NULL, 395 + .irqcapable = 1, 402 396 .name = "rcu_bh" 403 397 }; 404 398 ··· 414 406 .sync = rcu_bh_torture_synchronize, 415 407 .cb_barrier = NULL, 416 408 .stats = NULL, 409 + .irqcapable = 1, 417 410 .name = "rcu_bh_sync" 418 411 }; 419 412 ··· 541 532 .sync = sched_torture_synchronize, 542 533 .cb_barrier = rcu_barrier_sched, 543 534 .stats = NULL, 535 + .irqcapable = 1, 544 536 .name = "sched" 545 537 }; 546 538 ··· 630 620 } 631 621 632 622 /* 623 + * RCU torture reader from timer handler. Dereferences rcu_torture_current, 624 + * incrementing the corresponding element of the pipeline array. The 625 + * counter in the element should never be greater than 1, otherwise, the 626 + * RCU implementation is broken. 627 + */ 628 + static void rcu_torture_timer(unsigned long unused) 629 + { 630 + int idx; 631 + int completed; 632 + static DEFINE_RCU_RANDOM(rand); 633 + static DEFINE_SPINLOCK(rand_lock); 634 + struct rcu_torture *p; 635 + int pipe_count; 636 + 637 + idx = cur_ops->readlock(); 638 + completed = cur_ops->completed(); 639 + p = rcu_dereference(rcu_torture_current); 640 + if (p == NULL) { 641 + /* Leave because rcu_torture_writer is not yet underway */ 642 + cur_ops->readunlock(idx); 643 + return; 644 + } 645 + if (p->rtort_mbtest == 0) 646 + atomic_inc(&n_rcu_torture_mberror); 647 + spin_lock(&rand_lock); 648 + cur_ops->readdelay(&rand); 649 + n_rcu_torture_timers++; 650 + spin_unlock(&rand_lock); 651 + preempt_disable(); 652 + pipe_count = p->rtort_pipe_count; 653 + if (pipe_count > RCU_TORTURE_PIPE_LEN) { 654 + /* Should not happen, but... */ 655 + pipe_count = RCU_TORTURE_PIPE_LEN; 656 + } 657 + ++__get_cpu_var(rcu_torture_count)[pipe_count]; 658 + completed = cur_ops->completed() - completed; 659 + if (completed > RCU_TORTURE_PIPE_LEN) { 660 + /* Should not happen, but... */ 661 + completed = RCU_TORTURE_PIPE_LEN; 662 + } 663 + ++__get_cpu_var(rcu_torture_batch)[completed]; 664 + preempt_enable(); 665 + cur_ops->readunlock(idx); 666 + } 667 + 668 + /* 633 669 * RCU torture reader kthread. Repeatedly dereferences rcu_torture_current, 634 670 * incrementing the corresponding element of the pipeline array. The 635 671 * counter in the element should never be greater than 1, otherwise, the ··· 689 633 DEFINE_RCU_RANDOM(rand); 690 634 struct rcu_torture *p; 691 635 int pipe_count; 636 + struct timer_list t; 692 637 693 638 VERBOSE_PRINTK_STRING("rcu_torture_reader task started"); 694 639 set_user_nice(current, 19); 640 + if (irqreader && cur_ops->irqcapable) 641 + setup_timer_on_stack(&t, rcu_torture_timer, 0); 695 642 696 643 do { 644 + if (irqreader && cur_ops->irqcapable) { 645 + if (!timer_pending(&t)) 646 + mod_timer(&t, 1); 647 + } 697 648 idx = cur_ops->readlock(); 698 649 completed = cur_ops->completed(); 699 650 p = rcu_dereference(rcu_torture_current); ··· 732 669 rcu_stutter_wait(); 733 670 } while (!kthread_should_stop() && !fullstop); 734 671 VERBOSE_PRINTK_STRING("rcu_torture_reader task stopping"); 672 + if (irqreader && cur_ops->irqcapable) 673 + del_timer_sync(&t); 735 674 while (!kthread_should_stop()) 736 675 schedule_timeout_uninterruptible(1); 737 676 return 0; ··· 764 699 cnt += sprintf(&page[cnt], "%s%s ", torture_type, TORTURE_FLAG); 765 700 cnt += sprintf(&page[cnt], 766 701 "rtc: %p ver: %ld tfle: %d rta: %d rtaf: %d rtf: %d " 767 - "rtmbe: %d", 702 + "rtmbe: %d nt: %ld", 768 703 rcu_torture_current, 769 704 rcu_torture_current_version, 770 705 list_empty(&rcu_torture_freelist), 771 706 atomic_read(&n_rcu_torture_alloc), 772 707 atomic_read(&n_rcu_torture_alloc_fail), 773 708 atomic_read(&n_rcu_torture_free), 774 - atomic_read(&n_rcu_torture_mberror)); 709 + atomic_read(&n_rcu_torture_mberror), 710 + n_rcu_torture_timers); 775 711 if (atomic_read(&n_rcu_torture_mberror) != 0) 776 712 cnt += sprintf(&page[cnt], " !!!"); 777 713 cnt += sprintf(&page[cnt], "\n%s%s ", torture_type, TORTURE_FLAG); ··· 928 862 printk(KERN_ALERT "%s" TORTURE_FLAG 929 863 "--- %s: nreaders=%d nfakewriters=%d " 930 864 "stat_interval=%d verbose=%d test_no_idle_hz=%d " 931 - "shuffle_interval=%d stutter=%d\n", 865 + "shuffle_interval=%d stutter=%d irqreader=%d\n", 932 866 torture_type, tag, nrealreaders, nfakewriters, 933 867 stat_interval, verbose, test_no_idle_hz, shuffle_interval, 934 - stutter); 868 + stutter, irqreader); 935 869 } 936 870 937 871 static void