aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/torture.h7
-rw-r--r--kernel/rcu/rcutorture.c69
-rw-r--r--kernel/torture.c87
3 files changed, 104 insertions, 59 deletions
diff --git a/include/linux/torture.h b/include/linux/torture.h
index 0259db38bfb0..203f127d9ddf 100644
--- a/include/linux/torture.h
+++ b/include/linux/torture.h
@@ -75,8 +75,13 @@ int torture_shuffle_init(long shuffint);
75/* Shutdown task absorption, for when the tasks cannot safely be killed. */ 75/* Shutdown task absorption, for when the tasks cannot safely be killed. */
76void torture_shutdown_absorb(const char *title); 76void torture_shutdown_absorb(const char *title);
77 77
78/* Task stuttering, which forces load/no-load transitions. */
79void stutter_wait(const char *title);
80int torture_stutter_init(int s);
81void torture_stutter_cleanup(void);
82
78/* Initialization and cleanup. */ 83/* Initialization and cleanup. */
79void torture_init_begin(char *ttype, bool v); 84void torture_init_begin(char *ttype, bool v, int *runnable);
80void torture_init_end(void); 85void torture_init_end(void);
81bool torture_cleanup(void); 86bool torture_cleanup(void);
82bool torture_must_stop(void); 87bool torture_must_stop(void);
diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c
index 9357c88cc8cc..4329ad14f8dc 100644
--- a/kernel/rcu/rcutorture.c
+++ b/kernel/rcu/rcutorture.c
@@ -103,7 +103,6 @@ static struct task_struct *writer_task;
103static struct task_struct **fakewriter_tasks; 103static struct task_struct **fakewriter_tasks;
104static struct task_struct **reader_tasks; 104static struct task_struct **reader_tasks;
105static struct task_struct *stats_task; 105static struct task_struct *stats_task;
106static struct task_struct *stutter_task;
107static struct task_struct *fqs_task; 106static struct task_struct *fqs_task;
108static struct task_struct *boost_tasks[NR_CPUS]; 107static struct task_struct *boost_tasks[NR_CPUS];
109static struct task_struct *shutdown_task; 108static struct task_struct *shutdown_task;
@@ -145,8 +144,6 @@ static long n_barrier_attempts;
145static long n_barrier_successes; 144static long n_barrier_successes;
146static struct list_head rcu_torture_removed; 145static struct list_head rcu_torture_removed;
147 146
148static int stutter_pause_test;
149
150#if defined(MODULE) || defined(CONFIG_RCU_TORTURE_TEST_RUNNABLE) 147#if defined(MODULE) || defined(CONFIG_RCU_TORTURE_TEST_RUNNABLE)
151#define RCUTORTURE_RUNNABLE_INIT 1 148#define RCUTORTURE_RUNNABLE_INIT 1
152#else 149#else
@@ -222,18 +219,6 @@ rcu_torture_free(struct rcu_torture *p)
222 spin_unlock_bh(&rcu_torture_lock); 219 spin_unlock_bh(&rcu_torture_lock);
223} 220}
224 221
225static void
226rcu_stutter_wait(const char *title)
227{
228 while (stutter_pause_test || !rcutorture_runnable) {
229 if (rcutorture_runnable)
230 schedule_timeout_interruptible(1);
231 else
232 schedule_timeout_interruptible(round_jiffies_relative(HZ));
233 torture_shutdown_absorb(title);
234 }
235}
236
237/* 222/*
238 * Operations vector for selecting different types of tests. 223 * Operations vector for selecting different types of tests.
239 */ 224 */
@@ -571,7 +556,7 @@ static int rcu_torture_boost(void *arg)
571 oldstarttime = boost_starttime; 556 oldstarttime = boost_starttime;
572 while (ULONG_CMP_LT(jiffies, oldstarttime)) { 557 while (ULONG_CMP_LT(jiffies, oldstarttime)) {
573 schedule_timeout_interruptible(oldstarttime - jiffies); 558 schedule_timeout_interruptible(oldstarttime - jiffies);
574 rcu_stutter_wait("rcu_torture_boost"); 559 stutter_wait("rcu_torture_boost");
575 if (torture_must_stop()) 560 if (torture_must_stop())
576 goto checkwait; 561 goto checkwait;
577 } 562 }
@@ -593,7 +578,7 @@ static int rcu_torture_boost(void *arg)
593 call_rcu_time = jiffies; 578 call_rcu_time = jiffies;
594 } 579 }
595 cond_resched(); 580 cond_resched();
596 rcu_stutter_wait("rcu_torture_boost"); 581 stutter_wait("rcu_torture_boost");
597 if (torture_must_stop()) 582 if (torture_must_stop())
598 goto checkwait; 583 goto checkwait;
599 } 584 }
@@ -618,7 +603,7 @@ static int rcu_torture_boost(void *arg)
618 } 603 }
619 604
620 /* Go do the stutter. */ 605 /* Go do the stutter. */
621checkwait: rcu_stutter_wait("rcu_torture_boost"); 606checkwait: stutter_wait("rcu_torture_boost");
622 } while (!torture_must_stop()); 607 } while (!torture_must_stop());
623 608
624 /* Clean up and exit. */ 609 /* Clean up and exit. */
@@ -656,7 +641,7 @@ rcu_torture_fqs(void *arg)
656 udelay(fqs_holdoff); 641 udelay(fqs_holdoff);
657 fqs_burst_remaining -= fqs_holdoff; 642 fqs_burst_remaining -= fqs_holdoff;
658 } 643 }
659 rcu_stutter_wait("rcu_torture_fqs"); 644 stutter_wait("rcu_torture_fqs");
660 } while (!torture_must_stop()); 645 } while (!torture_must_stop());
661 VERBOSE_TOROUT_STRING("rcu_torture_fqs task stopping"); 646 VERBOSE_TOROUT_STRING("rcu_torture_fqs task stopping");
662 torture_shutdown_absorb("rcu_torture_fqs"); 647 torture_shutdown_absorb("rcu_torture_fqs");
@@ -728,7 +713,7 @@ rcu_torture_writer(void *arg)
728 } 713 }
729 } 714 }
730 rcutorture_record_progress(++rcu_torture_current_version); 715 rcutorture_record_progress(++rcu_torture_current_version);
731 rcu_stutter_wait("rcu_torture_writer"); 716 stutter_wait("rcu_torture_writer");
732 } while (!torture_must_stop()); 717 } while (!torture_must_stop());
733 VERBOSE_TOROUT_STRING("rcu_torture_writer task stopping"); 718 VERBOSE_TOROUT_STRING("rcu_torture_writer task stopping");
734 torture_shutdown_absorb("rcu_torture_writer"); 719 torture_shutdown_absorb("rcu_torture_writer");
@@ -765,7 +750,7 @@ rcu_torture_fakewriter(void *arg)
765 } else { 750 } else {
766 cur_ops->exp_sync(); 751 cur_ops->exp_sync();
767 } 752 }
768 rcu_stutter_wait("rcu_torture_fakewriter"); 753 stutter_wait("rcu_torture_fakewriter");
769 } while (!torture_must_stop()); 754 } while (!torture_must_stop());
770 755
771 VERBOSE_TOROUT_STRING("rcu_torture_fakewriter task stopping"); 756 VERBOSE_TOROUT_STRING("rcu_torture_fakewriter task stopping");
@@ -910,7 +895,7 @@ rcu_torture_reader(void *arg)
910 preempt_enable(); 895 preempt_enable();
911 cur_ops->readunlock(idx); 896 cur_ops->readunlock(idx);
912 schedule(); 897 schedule();
913 rcu_stutter_wait("rcu_torture_reader"); 898 stutter_wait("rcu_torture_reader");
914 } while (!torture_must_stop()); 899 } while (!torture_must_stop());
915 VERBOSE_TOROUT_STRING("rcu_torture_reader task stopping"); 900 VERBOSE_TOROUT_STRING("rcu_torture_reader task stopping");
916 torture_shutdown_absorb("rcu_torture_reader"); 901 torture_shutdown_absorb("rcu_torture_reader");
@@ -1034,25 +1019,6 @@ rcu_torture_stats(void *arg)
1034 return 0; 1019 return 0;
1035} 1020}
1036 1021
1037/* Cause the rcutorture test to "stutter", starting and stopping all
1038 * threads periodically.
1039 */
1040static int
1041rcu_torture_stutter(void *arg)
1042{
1043 VERBOSE_TOROUT_STRING("rcu_torture_stutter task started");
1044 do {
1045 schedule_timeout_interruptible(stutter * HZ);
1046 stutter_pause_test = 1;
1047 if (!kthread_should_stop())
1048 schedule_timeout_interruptible(stutter * HZ);
1049 stutter_pause_test = 0;
1050 torture_shutdown_absorb("rcu_torture_stutter");
1051 } while (!kthread_should_stop());
1052 VERBOSE_TOROUT_STRING("rcu_torture_stutter task stopping");
1053 return 0;
1054}
1055
1056static inline void 1022static inline void
1057rcu_torture_print_module_parms(struct rcu_torture_ops *cur_ops, const char *tag) 1023rcu_torture_print_module_parms(struct rcu_torture_ops *cur_ops, const char *tag)
1058{ 1024{
@@ -1403,11 +1369,7 @@ rcu_torture_cleanup(void)
1403 1369
1404 rcu_torture_barrier_cleanup(); 1370 rcu_torture_barrier_cleanup();
1405 rcu_torture_stall_cleanup(); 1371 rcu_torture_stall_cleanup();
1406 if (stutter_task) { 1372 torture_stutter_cleanup();
1407 VERBOSE_TOROUT_STRING("Stopping rcu_torture_stutter task");
1408 kthread_stop(stutter_task);
1409 }
1410 stutter_task = NULL;
1411 1373
1412 if (writer_task) { 1374 if (writer_task) {
1413 VERBOSE_TOROUT_STRING("Stopping rcu_torture_writer task"); 1375 VERBOSE_TOROUT_STRING("Stopping rcu_torture_writer task");
@@ -1548,7 +1510,7 @@ rcu_torture_init(void)
1548 &rcu_ops, &rcu_bh_ops, &srcu_ops, &sched_ops, 1510 &rcu_ops, &rcu_bh_ops, &srcu_ops, &sched_ops,
1549 }; 1511 };
1550 1512
1551 torture_init_begin(torture_type, verbose); 1513 torture_init_begin(torture_type, verbose, &rcutorture_runnable);
1552 1514
1553 /* Process args and tell the world that the torturer is on the job. */ 1515 /* Process args and tell the world that the torturer is on the job. */
1554 for (i = 0; i < ARRAY_SIZE(torture_ops); i++) { 1516 for (i = 0; i < ARRAY_SIZE(torture_ops); i++) {
@@ -1682,21 +1644,14 @@ rcu_torture_init(void)
1682 if (stutter < 0) 1644 if (stutter < 0)
1683 stutter = 0; 1645 stutter = 0;
1684 if (stutter) { 1646 if (stutter) {
1685 /* Create the stutter thread */ 1647 firsterr = torture_stutter_init(stutter * HZ);
1686 stutter_task = kthread_run(rcu_torture_stutter, NULL, 1648 if (firsterr)
1687 "rcu_torture_stutter");
1688 if (IS_ERR(stutter_task)) {
1689 firsterr = PTR_ERR(stutter_task);
1690 VERBOSE_TOROUT_ERRSTRING("Failed to create stutter");
1691 stutter_task = NULL;
1692 goto unwind; 1649 goto unwind;
1693 }
1694 torture_shuffle_task_register(stutter_task);
1695 } 1650 }
1696 if (fqs_duration < 0) 1651 if (fqs_duration < 0)
1697 fqs_duration = 0; 1652 fqs_duration = 0;
1698 if (fqs_duration) { 1653 if (fqs_duration) {
1699 /* Create the stutter thread */ 1654 /* Create the fqs thread */
1700 fqs_task = kthread_run(rcu_torture_fqs, NULL, 1655 fqs_task = kthread_run(rcu_torture_fqs, NULL,
1701 "rcu_torture_fqs"); 1656 "rcu_torture_fqs");
1702 if (IS_ERR(fqs_task)) { 1657 if (IS_ERR(fqs_task)) {
diff --git a/kernel/torture.c b/kernel/torture.c
index d51de3029a5c..b30c2ee78580 100644
--- a/kernel/torture.c
+++ b/kernel/torture.c
@@ -58,6 +58,7 @@ static bool verbose;
58#define FULLSTOP_RMMOD 2 /* Normal rmmod of torture. */ 58#define FULLSTOP_RMMOD 2 /* Normal rmmod of torture. */
59static int fullstop = FULLSTOP_RMMOD; 59static int fullstop = FULLSTOP_RMMOD;
60static DEFINE_MUTEX(fullstop_mutex); 60static DEFINE_MUTEX(fullstop_mutex);
61static int *torture_runnable;
61 62
62#ifdef CONFIG_HOTPLUG_CPU 63#ifdef CONFIG_HOTPLUG_CPU
63 64
@@ -453,16 +454,100 @@ static struct notifier_block torture_shutdown_nb = {
453}; 454};
454 455
455/* 456/*
457 * Variables for stuttering, which means to periodically pause and
458 * restart testing in order to catch bugs that appear when load is
459 * suddenly applied to or removed from the system.
460 */
461static struct task_struct *stutter_task;
462static int stutter_pause_test;
463static int stutter;
464
465/*
466 * Block until the stutter interval ends. This must be called periodically
467 * by all running kthreads that need to be subject to stuttering.
468 */
469void stutter_wait(const char *title)
470{
471 while (ACCESS_ONCE(stutter_pause_test) ||
472 (torture_runnable && !ACCESS_ONCE(*torture_runnable))) {
473 if (stutter_pause_test)
474 schedule_timeout_interruptible(1);
475 else
476 schedule_timeout_interruptible(round_jiffies_relative(HZ));
477 torture_shutdown_absorb(title);
478 }
479}
480EXPORT_SYMBOL_GPL(stutter_wait);
481
482/*
483 * Cause the torture test to "stutter", starting and stopping all
484 * threads periodically.
485 */
486static int torture_stutter(void *arg)
487{
488 VERBOSE_TOROUT_STRING("torture_stutter task started");
489 do {
490 if (!torture_must_stop()) {
491 schedule_timeout_interruptible(stutter);
492 ACCESS_ONCE(stutter_pause_test) = 1;
493 }
494 if (!torture_must_stop())
495 schedule_timeout_interruptible(stutter);
496 ACCESS_ONCE(stutter_pause_test) = 0;
497 torture_shutdown_absorb("torture_stutter");
498 } while (!torture_must_stop());
499 VERBOSE_TOROUT_STRING("torture_stutter task stopping");
500 return 0;
501}
502
503/*
504 * Initialize and kick off the torture_stutter kthread.
505 */
506int torture_stutter_init(int s)
507{
508 int ret;
509
510 stutter = s;
511 stutter_task = kthread_run(torture_stutter, NULL, "torture_stutter");
512 if (IS_ERR(stutter_task)) {
513 ret = PTR_ERR(stutter_task);
514 VERBOSE_TOROUT_ERRSTRING("Failed to create stutter");
515 stutter_task = NULL;
516 return ret;
517 }
518 torture_shuffle_task_register(stutter_task);
519 return 0;
520}
521EXPORT_SYMBOL_GPL(torture_stutter_init);
522
523/*
524 * Cleanup after the torture_stutter kthread.
525 */
526void torture_stutter_cleanup(void)
527{
528 if (!stutter_task)
529 return;
530 VERBOSE_TOROUT_STRING("Stopping torture_stutter task");
531 kthread_stop(stutter_task);
532 stutter_task = NULL;
533}
534EXPORT_SYMBOL_GPL(torture_stutter_cleanup);
535
536/*
456 * Initialize torture module. Please note that this is -not- invoked via 537 * Initialize torture module. Please note that this is -not- invoked via
457 * the usual module_init() mechanism, but rather by an explicit call from 538 * the usual module_init() mechanism, but rather by an explicit call from
458 * the client torture module. This call must be paired with a later 539 * the client torture module. This call must be paired with a later
459 * torture_init_end(). 540 * torture_init_end().
541 *
542 * The runnable parameter points to a flag that controls whether or not
543 * the test is currently runnable. If there is no such flag, pass in NULL.
460 */ 544 */
461void __init torture_init_begin(char *ttype, bool v) 545void __init torture_init_begin(char *ttype, bool v, int *runnable)
462{ 546{
463 mutex_lock(&fullstop_mutex); 547 mutex_lock(&fullstop_mutex);
464 torture_type = ttype; 548 torture_type = ttype;
465 verbose = v; 549 verbose = v;
550 torture_runnable = runnable;
466 fullstop = FULLSTOP_DONTSTOP; 551 fullstop = FULLSTOP_DONTSTOP;
467 552
468} 553}