diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-19 20:12:34 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-20 13:10:18 -0400 |
commit | 5928a2b60cfdbad730f93696acab142d0b607280 (patch) | |
tree | 49bb21c9219673e61bad7a7c9202c7f25f5fe1be /kernel/rcutorture.c | |
parent | 5ed59af85077d28875a3a137b21933aaf1b4cd50 (diff) | |
parent | bdd4431c8d071491a68a65d9457996f222b5ecd3 (diff) |
Merge branch 'core-rcu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull RCU changes for v3.4 from Ingo Molnar. The major features of this
series are:
- making RCU more aggressive about entering dyntick-idle mode in order
to improve energy efficiency
- converting a few more call_rcu()s to kfree_rcu()s
- applying a number of rcutree fixes and cleanups to rcutiny
- removing CONFIG_SMP #ifdefs from treercu
- allowing RCU CPU stall times to be set via sysfs
- adding CPU-stall capability to rcutorture
- adding more RCU-abuse diagnostics
- updating documentation
- fixing yet more issues located by the still-ongoing top-to-bottom
inspection of RCU, this time with a special focus on the CPU-hotplug
code path.
* 'core-rcu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (48 commits)
rcu: Stop spurious warnings from synchronize_sched_expedited
rcu: Hold off RCU_FAST_NO_HZ after timer posted
rcu: Eliminate softirq-mediated RCU_FAST_NO_HZ idle-entry loop
rcu: Add RCU_NONIDLE() for idle-loop RCU read-side critical sections
rcu: Allow nesting of rcu_idle_enter() and rcu_idle_exit()
rcu: Remove redundant check for rcu_head misalignment
PTR_ERR should be called before its argument is cleared.
rcu: Convert WARN_ON_ONCE() in rcu_lock_acquire() to lockdep
rcu: Trace only after NULL-pointer check
rcu: Call out dangers of expedited RCU primitives
rcu: Rework detection of use of RCU by offline CPUs
lockdep: Add CPU-idle/offline warning to lockdep-RCU splat
rcu: No interrupt disabling for rcu_prepare_for_idle()
rcu: Move synchronize_sched_expedited() to rcutree.c
rcu: Check for illegal use of RCU from offlined CPUs
rcu: Update stall-warning documentation
rcu: Add CPU-stall capability to rcutorture
rcu: Make documentation give more realistic rcutorture duration
rcutorture: Permit holding off CPU-hotplug operations during boot
rcu: Print scheduling-clock information on RCU CPU stall-warning messages
...
Diffstat (limited to 'kernel/rcutorture.c')
-rw-r--r-- | kernel/rcutorture.c | 91 |
1 files changed, 86 insertions, 5 deletions
diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c index a58ac285fc69..a89b381a8c6e 100644 --- a/kernel/rcutorture.c +++ b/kernel/rcutorture.c | |||
@@ -65,7 +65,10 @@ static int fqs_duration; /* Duration of bursts (us), 0 to disable. */ | |||
65 | static int fqs_holdoff; /* Hold time within burst (us). */ | 65 | static int fqs_holdoff; /* Hold time within burst (us). */ |
66 | static int fqs_stutter = 3; /* Wait time between bursts (s). */ | 66 | 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 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). */ | ||
69 | 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. */ |
70 | static int test_boost_interval = 7; /* Interval between boost tests, seconds. */ | 73 | static int test_boost_interval = 7; /* Interval between boost tests, seconds. */ |
71 | 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. */ |
@@ -95,8 +98,14 @@ module_param(fqs_stutter, int, 0444); | |||
95 | MODULE_PARM_DESC(fqs_stutter, "Wait time between fqs bursts (s)"); | 98 | MODULE_PARM_DESC(fqs_stutter, "Wait time between fqs bursts (s)"); |
96 | module_param(onoff_interval, int, 0444); | 99 | module_param(onoff_interval, int, 0444); |
97 | MODULE_PARM_DESC(onoff_interval, "Time between CPU hotplugs (s), 0=disable"); | 100 | MODULE_PARM_DESC(onoff_interval, "Time between CPU hotplugs (s), 0=disable"); |
101 | module_param(onoff_holdoff, int, 0444); | ||
102 | MODULE_PARM_DESC(onoff_holdoff, "Time after boot before CPU hotplugs (s)"); | ||
98 | module_param(shutdown_secs, int, 0444); | 103 | module_param(shutdown_secs, int, 0444); |
99 | 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)."); | ||
100 | module_param(test_boost, int, 0444); | 109 | module_param(test_boost, int, 0444); |
101 | 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."); |
102 | module_param(test_boost_interval, int, 0444); | 111 | module_param(test_boost_interval, int, 0444); |
@@ -129,6 +138,7 @@ static struct task_struct *shutdown_task; | |||
129 | #ifdef CONFIG_HOTPLUG_CPU | 138 | #ifdef CONFIG_HOTPLUG_CPU |
130 | static struct task_struct *onoff_task; | 139 | static struct task_struct *onoff_task; |
131 | #endif /* #ifdef CONFIG_HOTPLUG_CPU */ | 140 | #endif /* #ifdef CONFIG_HOTPLUG_CPU */ |
141 | static struct task_struct *stall_task; | ||
132 | 142 | ||
133 | #define RCU_TORTURE_PIPE_LEN 10 | 143 | #define RCU_TORTURE_PIPE_LEN 10 |
134 | 144 | ||
@@ -990,12 +1000,12 @@ static void rcu_torture_timer(unsigned long unused) | |||
990 | rcu_read_lock_bh_held() || | 1000 | rcu_read_lock_bh_held() || |
991 | rcu_read_lock_sched_held() || | 1001 | rcu_read_lock_sched_held() || |
992 | srcu_read_lock_held(&srcu_ctl)); | 1002 | srcu_read_lock_held(&srcu_ctl)); |
993 | do_trace_rcu_torture_read(cur_ops->name, &p->rtort_rcu); | ||
994 | if (p == NULL) { | 1003 | if (p == NULL) { |
995 | /* Leave because rcu_torture_writer is not yet underway */ | 1004 | /* Leave because rcu_torture_writer is not yet underway */ |
996 | cur_ops->readunlock(idx); | 1005 | cur_ops->readunlock(idx); |
997 | return; | 1006 | return; |
998 | } | 1007 | } |
1008 | do_trace_rcu_torture_read(cur_ops->name, &p->rtort_rcu); | ||
999 | if (p->rtort_mbtest == 0) | 1009 | if (p->rtort_mbtest == 0) |
1000 | atomic_inc(&n_rcu_torture_mberror); | 1010 | atomic_inc(&n_rcu_torture_mberror); |
1001 | spin_lock(&rand_lock); | 1011 | spin_lock(&rand_lock); |
@@ -1053,13 +1063,13 @@ rcu_torture_reader(void *arg) | |||
1053 | rcu_read_lock_bh_held() || | 1063 | rcu_read_lock_bh_held() || |
1054 | rcu_read_lock_sched_held() || | 1064 | rcu_read_lock_sched_held() || |
1055 | srcu_read_lock_held(&srcu_ctl)); | 1065 | srcu_read_lock_held(&srcu_ctl)); |
1056 | do_trace_rcu_torture_read(cur_ops->name, &p->rtort_rcu); | ||
1057 | if (p == NULL) { | 1066 | if (p == NULL) { |
1058 | /* Wait for rcu_torture_writer to get underway */ | 1067 | /* Wait for rcu_torture_writer to get underway */ |
1059 | cur_ops->readunlock(idx); | 1068 | cur_ops->readunlock(idx); |
1060 | schedule_timeout_interruptible(HZ); | 1069 | schedule_timeout_interruptible(HZ); |
1061 | continue; | 1070 | continue; |
1062 | } | 1071 | } |
1072 | do_trace_rcu_torture_read(cur_ops->name, &p->rtort_rcu); | ||
1063 | if (p->rtort_mbtest == 0) | 1073 | if (p->rtort_mbtest == 0) |
1064 | atomic_inc(&n_rcu_torture_mberror); | 1074 | atomic_inc(&n_rcu_torture_mberror); |
1065 | cur_ops->read_delay(&rand); | 1075 | cur_ops->read_delay(&rand); |
@@ -1300,13 +1310,13 @@ rcu_torture_print_module_parms(struct rcu_torture_ops *cur_ops, char *tag) | |||
1300 | "fqs_duration=%d fqs_holdoff=%d fqs_stutter=%d " | 1310 | "fqs_duration=%d fqs_holdoff=%d fqs_stutter=%d " |
1301 | "test_boost=%d/%d test_boost_interval=%d " | 1311 | "test_boost=%d/%d test_boost_interval=%d " |
1302 | "test_boost_duration=%d shutdown_secs=%d " | 1312 | "test_boost_duration=%d shutdown_secs=%d " |
1303 | "onoff_interval=%d\n", | 1313 | "onoff_interval=%d onoff_holdoff=%d\n", |
1304 | torture_type, tag, nrealreaders, nfakewriters, | 1314 | torture_type, tag, nrealreaders, nfakewriters, |
1305 | stat_interval, verbose, test_no_idle_hz, shuffle_interval, | 1315 | stat_interval, verbose, test_no_idle_hz, shuffle_interval, |
1306 | stutter, irqreader, fqs_duration, fqs_holdoff, fqs_stutter, | 1316 | stutter, irqreader, fqs_duration, fqs_holdoff, fqs_stutter, |
1307 | test_boost, cur_ops->can_boost, | 1317 | test_boost, cur_ops->can_boost, |
1308 | test_boost_interval, test_boost_duration, shutdown_secs, | 1318 | test_boost_interval, test_boost_duration, shutdown_secs, |
1309 | onoff_interval); | 1319 | onoff_interval, onoff_holdoff); |
1310 | } | 1320 | } |
1311 | 1321 | ||
1312 | static struct notifier_block rcutorture_shutdown_nb = { | 1322 | static struct notifier_block rcutorture_shutdown_nb = { |
@@ -1410,6 +1420,11 @@ rcu_torture_onoff(void *arg) | |||
1410 | for_each_online_cpu(cpu) | 1420 | for_each_online_cpu(cpu) |
1411 | maxcpu = cpu; | 1421 | maxcpu = cpu; |
1412 | WARN_ON(maxcpu < 0); | 1422 | WARN_ON(maxcpu < 0); |
1423 | if (onoff_holdoff > 0) { | ||
1424 | VERBOSE_PRINTK_STRING("rcu_torture_onoff begin holdoff"); | ||
1425 | schedule_timeout_interruptible(onoff_holdoff * HZ); | ||
1426 | VERBOSE_PRINTK_STRING("rcu_torture_onoff end holdoff"); | ||
1427 | } | ||
1413 | while (!kthread_should_stop()) { | 1428 | while (!kthread_should_stop()) { |
1414 | cpu = (rcu_random(&rand) >> 4) % (maxcpu + 1); | 1429 | cpu = (rcu_random(&rand) >> 4) % (maxcpu + 1); |
1415 | if (cpu_online(cpu) && cpu_is_hotpluggable(cpu)) { | 1430 | if (cpu_online(cpu) && cpu_is_hotpluggable(cpu)) { |
@@ -1450,12 +1465,15 @@ rcu_torture_onoff(void *arg) | |||
1450 | static int __cpuinit | 1465 | static int __cpuinit |
1451 | rcu_torture_onoff_init(void) | 1466 | rcu_torture_onoff_init(void) |
1452 | { | 1467 | { |
1468 | int ret; | ||
1469 | |||
1453 | if (onoff_interval <= 0) | 1470 | if (onoff_interval <= 0) |
1454 | return 0; | 1471 | return 0; |
1455 | onoff_task = kthread_run(rcu_torture_onoff, NULL, "rcu_torture_onoff"); | 1472 | onoff_task = kthread_run(rcu_torture_onoff, NULL, "rcu_torture_onoff"); |
1456 | if (IS_ERR(onoff_task)) { | 1473 | if (IS_ERR(onoff_task)) { |
1474 | ret = PTR_ERR(onoff_task); | ||
1457 | onoff_task = NULL; | 1475 | onoff_task = NULL; |
1458 | return PTR_ERR(onoff_task); | 1476 | return ret; |
1459 | } | 1477 | } |
1460 | return 0; | 1478 | return 0; |
1461 | } | 1479 | } |
@@ -1481,6 +1499,63 @@ static void rcu_torture_onoff_cleanup(void) | |||
1481 | 1499 | ||
1482 | #endif /* #else #ifdef CONFIG_HOTPLUG_CPU */ | 1500 | #endif /* #else #ifdef CONFIG_HOTPLUG_CPU */ |
1483 | 1501 | ||
1502 | /* | ||
1503 | * CPU-stall kthread. It waits as specified by stall_cpu_holdoff, then | ||
1504 | * induces a CPU stall for the time specified by stall_cpu. | ||
1505 | */ | ||
1506 | static int __cpuinit rcu_torture_stall(void *args) | ||
1507 | { | ||
1508 | unsigned long stop_at; | ||
1509 | |||
1510 | VERBOSE_PRINTK_STRING("rcu_torture_stall task started"); | ||
1511 | if (stall_cpu_holdoff > 0) { | ||
1512 | VERBOSE_PRINTK_STRING("rcu_torture_stall begin holdoff"); | ||
1513 | schedule_timeout_interruptible(stall_cpu_holdoff * HZ); | ||
1514 | VERBOSE_PRINTK_STRING("rcu_torture_stall end holdoff"); | ||
1515 | } | ||
1516 | if (!kthread_should_stop()) { | ||
1517 | stop_at = get_seconds() + stall_cpu; | ||
1518 | /* RCU CPU stall is expected behavior in following code. */ | ||
1519 | printk(KERN_ALERT "rcu_torture_stall start.\n"); | ||
1520 | rcu_read_lock(); | ||
1521 | preempt_disable(); | ||
1522 | while (ULONG_CMP_LT(get_seconds(), stop_at)) | ||
1523 | continue; /* Induce RCU CPU stall warning. */ | ||
1524 | preempt_enable(); | ||
1525 | rcu_read_unlock(); | ||
1526 | printk(KERN_ALERT "rcu_torture_stall end.\n"); | ||
1527 | } | ||
1528 | rcutorture_shutdown_absorb("rcu_torture_stall"); | ||
1529 | while (!kthread_should_stop()) | ||
1530 | schedule_timeout_interruptible(10 * HZ); | ||
1531 | return 0; | ||
1532 | } | ||
1533 | |||
1534 | /* Spawn CPU-stall kthread, if stall_cpu specified. */ | ||
1535 | static int __init rcu_torture_stall_init(void) | ||
1536 | { | ||
1537 | int ret; | ||
1538 | |||
1539 | if (stall_cpu <= 0) | ||
1540 | return 0; | ||
1541 | stall_task = kthread_run(rcu_torture_stall, NULL, "rcu_torture_stall"); | ||
1542 | if (IS_ERR(stall_task)) { | ||
1543 | ret = PTR_ERR(stall_task); | ||
1544 | stall_task = NULL; | ||
1545 | return ret; | ||
1546 | } | ||
1547 | return 0; | ||
1548 | } | ||
1549 | |||
1550 | /* Clean up after the CPU-stall kthread, if one was spawned. */ | ||
1551 | static void rcu_torture_stall_cleanup(void) | ||
1552 | { | ||
1553 | if (stall_task == NULL) | ||
1554 | return; | ||
1555 | VERBOSE_PRINTK_STRING("Stopping rcu_torture_stall_task."); | ||
1556 | kthread_stop(stall_task); | ||
1557 | } | ||
1558 | |||
1484 | static int rcutorture_cpu_notify(struct notifier_block *self, | 1559 | static int rcutorture_cpu_notify(struct notifier_block *self, |
1485 | unsigned long action, void *hcpu) | 1560 | unsigned long action, void *hcpu) |
1486 | { | 1561 | { |
@@ -1523,6 +1598,7 @@ rcu_torture_cleanup(void) | |||
1523 | fullstop = FULLSTOP_RMMOD; | 1598 | fullstop = FULLSTOP_RMMOD; |
1524 | mutex_unlock(&fullstop_mutex); | 1599 | mutex_unlock(&fullstop_mutex); |
1525 | unregister_reboot_notifier(&rcutorture_shutdown_nb); | 1600 | unregister_reboot_notifier(&rcutorture_shutdown_nb); |
1601 | rcu_torture_stall_cleanup(); | ||
1526 | if (stutter_task) { | 1602 | if (stutter_task) { |
1527 | VERBOSE_PRINTK_STRING("Stopping rcu_torture_stutter task"); | 1603 | VERBOSE_PRINTK_STRING("Stopping rcu_torture_stutter task"); |
1528 | kthread_stop(stutter_task); | 1604 | kthread_stop(stutter_task); |
@@ -1602,6 +1678,10 @@ rcu_torture_cleanup(void) | |||
1602 | cur_ops->cleanup(); | 1678 | cur_ops->cleanup(); |
1603 | if (atomic_read(&n_rcu_torture_error)) | 1679 | if (atomic_read(&n_rcu_torture_error)) |
1604 | rcu_torture_print_module_parms(cur_ops, "End of test: FAILURE"); | 1680 | rcu_torture_print_module_parms(cur_ops, "End of test: FAILURE"); |
1681 | else if (n_online_successes != n_online_attempts || | ||
1682 | n_offline_successes != n_offline_attempts) | ||
1683 | rcu_torture_print_module_parms(cur_ops, | ||
1684 | "End of test: RCU_HOTPLUG"); | ||
1605 | else | 1685 | else |
1606 | rcu_torture_print_module_parms(cur_ops, "End of test: SUCCESS"); | 1686 | rcu_torture_print_module_parms(cur_ops, "End of test: SUCCESS"); |
1607 | } | 1687 | } |
@@ -1819,6 +1899,7 @@ rcu_torture_init(void) | |||
1819 | } | 1899 | } |
1820 | rcu_torture_onoff_init(); | 1900 | rcu_torture_onoff_init(); |
1821 | register_reboot_notifier(&rcutorture_shutdown_nb); | 1901 | register_reboot_notifier(&rcutorture_shutdown_nb); |
1902 | rcu_torture_stall_init(); | ||
1822 | rcutorture_record_test_transition(); | 1903 | rcutorture_record_test_transition(); |
1823 | mutex_unlock(&fullstop_mutex); | 1904 | mutex_unlock(&fullstop_mutex); |
1824 | return 0; | 1905 | return 0; |