diff options
author | Paul E. McKenney <paul.mckenney@linaro.org> | 2012-01-20 18:36:33 -0500 |
---|---|---|
committer | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2012-02-21 12:03:52 -0500 |
commit | c13f3757d0fcdcc2b7fc5d5e38da76b8913e6648 (patch) | |
tree | 7ae68a12459fc4f18b87fa1a44239e29f82cd244 | |
parent | 105617da8dc0ae3cf5f5a581330b1e4846fe87f2 (diff) |
rcu: Add CPU-stall capability to rcutorture
Add module parameters to rcutorture that induce a CPU stall.
The stall_cpu parameter specifies how long to stall in seconds,
defaulting to zero, which indicates no stalling is to be undertaken.
The stall_cpu_holdoff parameter specifies how many seconds after
insmod (or boot, if rcutorture is built into the kernel) that this
stall is to start. The default value for stall_cpu_holdoff is ten
seconds.
Signed-off-by: Paul E. McKenney <paul.mckenney@linaro.org>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
-rw-r--r-- | Documentation/RCU/torture.txt | 18 | ||||
-rw-r--r-- | kernel/rcutorture.c | 66 |
2 files changed, 84 insertions, 0 deletions
diff --git a/Documentation/RCU/torture.txt b/Documentation/RCU/torture.txt index d25be872ae33..375d3fb71437 100644 --- a/Documentation/RCU/torture.txt +++ b/Documentation/RCU/torture.txt | |||
@@ -86,6 +86,24 @@ shutdown_secs The number of seconds to run the test before terminating | |||
86 | zero, which disables test termination and system shutdown. | 86 | zero, which disables test termination and system shutdown. |
87 | This capability is useful for automated testing. | 87 | This capability is useful for automated testing. |
88 | 88 | ||
89 | stall_cpu The number of seconds that a CPU should be stalled while | ||
90 | within both an rcu_read_lock() and a preempt_disable(). | ||
91 | This stall happens only once per rcutorture run. | ||
92 | If you need multiple stalls, use modprobe and rmmod to | ||
93 | repeatedly run rcutorture. The default for stall_cpu | ||
94 | is zero, which prevents rcutorture from stalling a CPU. | ||
95 | |||
96 | Note that attempts to rmmod rcutorture while the stall | ||
97 | is ongoing will hang, so be careful what value you | ||
98 | choose for this module parameter! In addition, too-large | ||
99 | values for stall_cpu might well induce failures and | ||
100 | warnings in other parts of the kernel. You have been | ||
101 | warned! | ||
102 | |||
103 | stall_cpu_holdoff | ||
104 | The number of seconds to wait after rcutorture starts | ||
105 | before stalling a CPU. Defaults to 10 seconds. | ||
106 | |||
89 | stat_interval The number of seconds between output of torture | 107 | stat_interval The number of seconds between output of torture |
90 | statistics (via printk()). Regardless of the interval, | 108 | statistics (via printk()). Regardless of the interval, |
91 | statistics are printed when the module is unloaded. | 109 | statistics are printed when the module is unloaded. |
diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c index 2914cafe171b..5cfa23be43bd 100644 --- a/kernel/rcutorture.c +++ b/kernel/rcutorture.c | |||
@@ -67,6 +67,8 @@ static int fqs_stutter = 3; /* Wait time between bursts (s). */ | |||
67 | static int onoff_interval; /* Wait time between CPU hotplugs, 0=disable. */ | 67 | static int onoff_interval; /* Wait time between CPU hotplugs, 0=disable. */ |
68 | static int onoff_holdoff; /* Seconds after boot before CPU hotplugs. */ | 68 | static int onoff_holdoff; /* Seconds after boot before CPU hotplugs. */ |
69 | static int shutdown_secs; /* Shutdown time (s). <=0 for no shutdown. */ | 69 | static int shutdown_secs; /* Shutdown time (s). <=0 for no shutdown. */ |
70 | static int stall_cpu; /* CPU-stall duration (s). 0 for no stall. */ | ||
71 | static int stall_cpu_holdoff = 10; /* Time to wait until stall (s). */ | ||
70 | static int test_boost = 1; /* Test RCU prio boost: 0=no, 1=maybe, 2=yes. */ | 72 | static int test_boost = 1; /* Test RCU prio boost: 0=no, 1=maybe, 2=yes. */ |
71 | static int test_boost_interval = 7; /* Interval between boost tests, seconds. */ | 73 | static int test_boost_interval = 7; /* Interval between boost tests, seconds. */ |
72 | static int test_boost_duration = 4; /* Duration of each boost test, seconds. */ | 74 | static int test_boost_duration = 4; /* Duration of each boost test, seconds. */ |
@@ -100,6 +102,10 @@ module_param(onoff_holdoff, int, 0444); | |||
100 | MODULE_PARM_DESC(onoff_holdoff, "Time after boot before CPU hotplugs (s)"); | 102 | MODULE_PARM_DESC(onoff_holdoff, "Time after boot before CPU hotplugs (s)"); |
101 | module_param(shutdown_secs, int, 0444); | 103 | module_param(shutdown_secs, int, 0444); |
102 | MODULE_PARM_DESC(shutdown_secs, "Shutdown time (s), zero to disable."); | 104 | MODULE_PARM_DESC(shutdown_secs, "Shutdown time (s), zero to disable."); |
105 | module_param(stall_cpu, int, 0444); | ||
106 | MODULE_PARM_DESC(stall_cpu, "Stall duration (s), zero to disable."); | ||
107 | module_param(stall_cpu_holdoff, int, 0444); | ||
108 | MODULE_PARM_DESC(stall_cpu_holdoff, "Time to wait before starting stall (s)."); | ||
103 | module_param(test_boost, int, 0444); | 109 | module_param(test_boost, int, 0444); |
104 | MODULE_PARM_DESC(test_boost, "Test RCU prio boost: 0=no, 1=maybe, 2=yes."); | 110 | MODULE_PARM_DESC(test_boost, "Test RCU prio boost: 0=no, 1=maybe, 2=yes."); |
105 | module_param(test_boost_interval, int, 0444); | 111 | module_param(test_boost_interval, int, 0444); |
@@ -132,6 +138,7 @@ static struct task_struct *shutdown_task; | |||
132 | #ifdef CONFIG_HOTPLUG_CPU | 138 | #ifdef CONFIG_HOTPLUG_CPU |
133 | static struct task_struct *onoff_task; | 139 | static struct task_struct *onoff_task; |
134 | #endif /* #ifdef CONFIG_HOTPLUG_CPU */ | 140 | #endif /* #ifdef CONFIG_HOTPLUG_CPU */ |
141 | static struct task_struct *stall_task; | ||
135 | 142 | ||
136 | #define RCU_TORTURE_PIPE_LEN 10 | 143 | #define RCU_TORTURE_PIPE_LEN 10 |
137 | 144 | ||
@@ -1489,6 +1496,63 @@ static void rcu_torture_onoff_cleanup(void) | |||
1489 | 1496 | ||
1490 | #endif /* #else #ifdef CONFIG_HOTPLUG_CPU */ | 1497 | #endif /* #else #ifdef CONFIG_HOTPLUG_CPU */ |
1491 | 1498 | ||
1499 | /* | ||
1500 | * CPU-stall kthread. It waits as specified by stall_cpu_holdoff, then | ||
1501 | * induces a CPU stall for the time specified by stall_cpu. | ||
1502 | */ | ||
1503 | static int __cpuinit rcu_torture_stall(void *args) | ||
1504 | { | ||
1505 | unsigned long stop_at; | ||
1506 | |||
1507 | VERBOSE_PRINTK_STRING("rcu_torture_stall task started"); | ||
1508 | if (stall_cpu_holdoff > 0) { | ||
1509 | VERBOSE_PRINTK_STRING("rcu_torture_stall begin holdoff"); | ||
1510 | schedule_timeout_interruptible(stall_cpu_holdoff * HZ); | ||
1511 | VERBOSE_PRINTK_STRING("rcu_torture_stall end holdoff"); | ||
1512 | } | ||
1513 | if (!kthread_should_stop()) { | ||
1514 | stop_at = get_seconds() + stall_cpu; | ||
1515 | /* RCU CPU stall is expected behavior in following code. */ | ||
1516 | printk(KERN_ALERT "rcu_torture_stall start.\n"); | ||
1517 | rcu_read_lock(); | ||
1518 | preempt_disable(); | ||
1519 | while (ULONG_CMP_LT(get_seconds(), stop_at)) | ||
1520 | continue; /* Induce RCU CPU stall warning. */ | ||
1521 | preempt_enable(); | ||
1522 | rcu_read_unlock(); | ||
1523 | printk(KERN_ALERT "rcu_torture_stall end.\n"); | ||
1524 | } | ||
1525 | rcutorture_shutdown_absorb("rcu_torture_stall"); | ||
1526 | while (!kthread_should_stop()) | ||
1527 | schedule_timeout_interruptible(10 * HZ); | ||
1528 | return 0; | ||
1529 | } | ||
1530 | |||
1531 | /* Spawn CPU-stall kthread, if stall_cpu specified. */ | ||
1532 | static int __init rcu_torture_stall_init(void) | ||
1533 | { | ||
1534 | int ret; | ||
1535 | |||
1536 | if (stall_cpu <= 0) | ||
1537 | return 0; | ||
1538 | stall_task = kthread_run(rcu_torture_stall, NULL, "rcu_torture_stall"); | ||
1539 | if (IS_ERR(stall_task)) { | ||
1540 | ret = PTR_ERR(stall_task); | ||
1541 | stall_task = NULL; | ||
1542 | return ret; | ||
1543 | } | ||
1544 | return 0; | ||
1545 | } | ||
1546 | |||
1547 | /* Clean up after the CPU-stall kthread, if one was spawned. */ | ||
1548 | static void rcu_torture_stall_cleanup(void) | ||
1549 | { | ||
1550 | if (stall_task == NULL) | ||
1551 | return; | ||
1552 | VERBOSE_PRINTK_STRING("Stopping rcu_torture_stall_task."); | ||
1553 | kthread_stop(stall_task); | ||
1554 | } | ||
1555 | |||
1492 | static int rcutorture_cpu_notify(struct notifier_block *self, | 1556 | static int rcutorture_cpu_notify(struct notifier_block *self, |
1493 | unsigned long action, void *hcpu) | 1557 | unsigned long action, void *hcpu) |
1494 | { | 1558 | { |
@@ -1531,6 +1595,7 @@ rcu_torture_cleanup(void) | |||
1531 | fullstop = FULLSTOP_RMMOD; | 1595 | fullstop = FULLSTOP_RMMOD; |
1532 | mutex_unlock(&fullstop_mutex); | 1596 | mutex_unlock(&fullstop_mutex); |
1533 | unregister_reboot_notifier(&rcutorture_shutdown_nb); | 1597 | unregister_reboot_notifier(&rcutorture_shutdown_nb); |
1598 | rcu_torture_stall_cleanup(); | ||
1534 | if (stutter_task) { | 1599 | if (stutter_task) { |
1535 | VERBOSE_PRINTK_STRING("Stopping rcu_torture_stutter task"); | 1600 | VERBOSE_PRINTK_STRING("Stopping rcu_torture_stutter task"); |
1536 | kthread_stop(stutter_task); | 1601 | kthread_stop(stutter_task); |
@@ -1831,6 +1896,7 @@ rcu_torture_init(void) | |||
1831 | } | 1896 | } |
1832 | rcu_torture_onoff_init(); | 1897 | rcu_torture_onoff_init(); |
1833 | register_reboot_notifier(&rcutorture_shutdown_nb); | 1898 | register_reboot_notifier(&rcutorture_shutdown_nb); |
1899 | rcu_torture_stall_init(); | ||
1834 | rcutorture_record_test_transition(); | 1900 | rcutorture_record_test_transition(); |
1835 | mutex_unlock(&fullstop_mutex); | 1901 | mutex_unlock(&fullstop_mutex); |
1836 | return 0; | 1902 | return 0; |