diff options
author | Paul E. McKenney <paul.mckenney@linaro.org> | 2012-02-20 20:51:45 -0500 |
---|---|---|
committer | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2012-04-30 13:48:18 -0400 |
commit | fae4b54f28f034d228fa3bfc98858c698b64e89c (patch) | |
tree | 1259258956ba9d30eba6360083214e145ec19813 /kernel/rcutorture.c | |
parent | 37e377d2823e03528cb64f435d7c0e30b1c668eb (diff) |
rcu: Introduce rcutorture testing for rcu_barrier()
Although rcutorture does invoke rcu_barrier() and friends, it cannot
really be called a torture test given that it invokes them only once
at the end of the test. This commit therefore introduces heavy-duty
rcutorture testing for rcu_barrier(), which may be carried out
concurrently with normal rcutorture testing.
Signed-off-by: Paul E. McKenney <paul.mckenney@linaro.org>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Diffstat (limited to 'kernel/rcutorture.c')
-rw-r--r-- | kernel/rcutorture.c | 194 |
1 files changed, 186 insertions, 8 deletions
diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c index 1463a0636443..8cd262b41499 100644 --- a/kernel/rcutorture.c +++ b/kernel/rcutorture.c | |||
@@ -64,6 +64,7 @@ static int irqreader = 1; /* RCU readers from irq (timers). */ | |||
64 | static int fqs_duration; /* Duration of bursts (us), 0 to disable. */ | 64 | 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 n_barrier_cbs; /* Number of callbacks to test RCU barriers. */ | ||
67 | static int onoff_interval; /* Wait time between CPU hotplugs, 0=disable. */ | 68 | static int onoff_interval; /* Wait time between CPU hotplugs, 0=disable. */ |
68 | static int onoff_holdoff; /* Seconds after boot before CPU hotplugs. */ | 69 | static int onoff_holdoff; /* Seconds after boot before CPU hotplugs. */ |
69 | static int shutdown_secs; /* Shutdown time (s). <=0 for no shutdown. */ | 70 | static int shutdown_secs; /* Shutdown time (s). <=0 for no shutdown. */ |
@@ -96,6 +97,8 @@ module_param(fqs_holdoff, int, 0444); | |||
96 | MODULE_PARM_DESC(fqs_holdoff, "Holdoff time within fqs bursts (us)"); | 97 | MODULE_PARM_DESC(fqs_holdoff, "Holdoff time within fqs bursts (us)"); |
97 | module_param(fqs_stutter, int, 0444); | 98 | module_param(fqs_stutter, int, 0444); |
98 | MODULE_PARM_DESC(fqs_stutter, "Wait time between fqs bursts (s)"); | 99 | MODULE_PARM_DESC(fqs_stutter, "Wait time between fqs bursts (s)"); |
100 | module_param(n_barrier_cbs, int, 0444); | ||
101 | MODULE_PARM_DESC(n_barrier_cbs, "# of callbacks/kthreads for barrier testing"); | ||
99 | module_param(onoff_interval, int, 0444); | 102 | module_param(onoff_interval, int, 0444); |
100 | MODULE_PARM_DESC(onoff_interval, "Time between CPU hotplugs (s), 0=disable"); | 103 | MODULE_PARM_DESC(onoff_interval, "Time between CPU hotplugs (s), 0=disable"); |
101 | module_param(onoff_holdoff, int, 0444); | 104 | module_param(onoff_holdoff, int, 0444); |
@@ -139,6 +142,8 @@ static struct task_struct *shutdown_task; | |||
139 | static struct task_struct *onoff_task; | 142 | static struct task_struct *onoff_task; |
140 | #endif /* #ifdef CONFIG_HOTPLUG_CPU */ | 143 | #endif /* #ifdef CONFIG_HOTPLUG_CPU */ |
141 | static struct task_struct *stall_task; | 144 | static struct task_struct *stall_task; |
145 | static struct task_struct **barrier_cbs_tasks; | ||
146 | static struct task_struct *barrier_task; | ||
142 | 147 | ||
143 | #define RCU_TORTURE_PIPE_LEN 10 | 148 | #define RCU_TORTURE_PIPE_LEN 10 |
144 | 149 | ||
@@ -164,6 +169,7 @@ static atomic_t n_rcu_torture_alloc_fail; | |||
164 | static atomic_t n_rcu_torture_free; | 169 | static atomic_t n_rcu_torture_free; |
165 | static atomic_t n_rcu_torture_mberror; | 170 | static atomic_t n_rcu_torture_mberror; |
166 | static atomic_t n_rcu_torture_error; | 171 | static atomic_t n_rcu_torture_error; |
172 | static long n_rcu_torture_barrier_error; | ||
167 | static long n_rcu_torture_boost_ktrerror; | 173 | static long n_rcu_torture_boost_ktrerror; |
168 | static long n_rcu_torture_boost_rterror; | 174 | static long n_rcu_torture_boost_rterror; |
169 | static long n_rcu_torture_boost_failure; | 175 | static long n_rcu_torture_boost_failure; |
@@ -173,6 +179,8 @@ static long n_offline_attempts; | |||
173 | static long n_offline_successes; | 179 | static long n_offline_successes; |
174 | static long n_online_attempts; | 180 | static long n_online_attempts; |
175 | static long n_online_successes; | 181 | static long n_online_successes; |
182 | static long n_barrier_attempts; | ||
183 | static long n_barrier_successes; | ||
176 | static struct list_head rcu_torture_removed; | 184 | static struct list_head rcu_torture_removed; |
177 | static cpumask_var_t shuffle_tmp_mask; | 185 | static cpumask_var_t shuffle_tmp_mask; |
178 | 186 | ||
@@ -197,6 +205,10 @@ static unsigned long shutdown_time; /* jiffies to system shutdown. */ | |||
197 | static unsigned long boost_starttime; /* jiffies of next boost test start. */ | 205 | static unsigned long boost_starttime; /* jiffies of next boost test start. */ |
198 | DEFINE_MUTEX(boost_mutex); /* protect setting boost_starttime */ | 206 | DEFINE_MUTEX(boost_mutex); /* protect setting boost_starttime */ |
199 | /* and boost task create/destroy. */ | 207 | /* and boost task create/destroy. */ |
208 | static atomic_t barrier_cbs_count; /* Barrier callbacks registered. */ | ||
209 | static atomic_t barrier_cbs_invoked; /* Barrier callbacks invoked. */ | ||
210 | static wait_queue_head_t *barrier_cbs_wq; /* Coordinate barrier testing. */ | ||
211 | static DECLARE_WAIT_QUEUE_HEAD(barrier_wq); | ||
200 | 212 | ||
201 | /* Mediate rmmod and system shutdown. Concurrent rmmod & shutdown illegal! */ | 213 | /* Mediate rmmod and system shutdown. Concurrent rmmod & shutdown illegal! */ |
202 | 214 | ||
@@ -327,6 +339,7 @@ struct rcu_torture_ops { | |||
327 | int (*completed)(void); | 339 | int (*completed)(void); |
328 | void (*deferred_free)(struct rcu_torture *p); | 340 | void (*deferred_free)(struct rcu_torture *p); |
329 | void (*sync)(void); | 341 | void (*sync)(void); |
342 | void (*call)(struct rcu_head *head, void (*func)(struct rcu_head *rcu)); | ||
330 | void (*cb_barrier)(void); | 343 | void (*cb_barrier)(void); |
331 | void (*fqs)(void); | 344 | void (*fqs)(void); |
332 | int (*stats)(char *page); | 345 | int (*stats)(char *page); |
@@ -417,6 +430,7 @@ static struct rcu_torture_ops rcu_ops = { | |||
417 | .completed = rcu_torture_completed, | 430 | .completed = rcu_torture_completed, |
418 | .deferred_free = rcu_torture_deferred_free, | 431 | .deferred_free = rcu_torture_deferred_free, |
419 | .sync = synchronize_rcu, | 432 | .sync = synchronize_rcu, |
433 | .call = call_rcu, | ||
420 | .cb_barrier = rcu_barrier, | 434 | .cb_barrier = rcu_barrier, |
421 | .fqs = rcu_force_quiescent_state, | 435 | .fqs = rcu_force_quiescent_state, |
422 | .stats = NULL, | 436 | .stats = NULL, |
@@ -460,6 +474,7 @@ static struct rcu_torture_ops rcu_sync_ops = { | |||
460 | .completed = rcu_torture_completed, | 474 | .completed = rcu_torture_completed, |
461 | .deferred_free = rcu_sync_torture_deferred_free, | 475 | .deferred_free = rcu_sync_torture_deferred_free, |
462 | .sync = synchronize_rcu, | 476 | .sync = synchronize_rcu, |
477 | .call = NULL, | ||
463 | .cb_barrier = NULL, | 478 | .cb_barrier = NULL, |
464 | .fqs = rcu_force_quiescent_state, | 479 | .fqs = rcu_force_quiescent_state, |
465 | .stats = NULL, | 480 | .stats = NULL, |
@@ -477,6 +492,7 @@ static struct rcu_torture_ops rcu_expedited_ops = { | |||
477 | .completed = rcu_no_completed, | 492 | .completed = rcu_no_completed, |
478 | .deferred_free = rcu_sync_torture_deferred_free, | 493 | .deferred_free = rcu_sync_torture_deferred_free, |
479 | .sync = synchronize_rcu_expedited, | 494 | .sync = synchronize_rcu_expedited, |
495 | .call = NULL, | ||
480 | .cb_barrier = NULL, | 496 | .cb_barrier = NULL, |
481 | .fqs = rcu_force_quiescent_state, | 497 | .fqs = rcu_force_quiescent_state, |
482 | .stats = NULL, | 498 | .stats = NULL, |
@@ -519,6 +535,7 @@ static struct rcu_torture_ops rcu_bh_ops = { | |||
519 | .completed = rcu_bh_torture_completed, | 535 | .completed = rcu_bh_torture_completed, |
520 | .deferred_free = rcu_bh_torture_deferred_free, | 536 | .deferred_free = rcu_bh_torture_deferred_free, |
521 | .sync = synchronize_rcu_bh, | 537 | .sync = synchronize_rcu_bh, |
538 | .call = call_rcu_bh, | ||
522 | .cb_barrier = rcu_barrier_bh, | 539 | .cb_barrier = rcu_barrier_bh, |
523 | .fqs = rcu_bh_force_quiescent_state, | 540 | .fqs = rcu_bh_force_quiescent_state, |
524 | .stats = NULL, | 541 | .stats = NULL, |
@@ -535,6 +552,7 @@ static struct rcu_torture_ops rcu_bh_sync_ops = { | |||
535 | .completed = rcu_bh_torture_completed, | 552 | .completed = rcu_bh_torture_completed, |
536 | .deferred_free = rcu_sync_torture_deferred_free, | 553 | .deferred_free = rcu_sync_torture_deferred_free, |
537 | .sync = synchronize_rcu_bh, | 554 | .sync = synchronize_rcu_bh, |
555 | .call = NULL, | ||
538 | .cb_barrier = NULL, | 556 | .cb_barrier = NULL, |
539 | .fqs = rcu_bh_force_quiescent_state, | 557 | .fqs = rcu_bh_force_quiescent_state, |
540 | .stats = NULL, | 558 | .stats = NULL, |
@@ -551,6 +569,7 @@ static struct rcu_torture_ops rcu_bh_expedited_ops = { | |||
551 | .completed = rcu_bh_torture_completed, | 569 | .completed = rcu_bh_torture_completed, |
552 | .deferred_free = rcu_sync_torture_deferred_free, | 570 | .deferred_free = rcu_sync_torture_deferred_free, |
553 | .sync = synchronize_rcu_bh_expedited, | 571 | .sync = synchronize_rcu_bh_expedited, |
572 | .call = NULL, | ||
554 | .cb_barrier = NULL, | 573 | .cb_barrier = NULL, |
555 | .fqs = rcu_bh_force_quiescent_state, | 574 | .fqs = rcu_bh_force_quiescent_state, |
556 | .stats = NULL, | 575 | .stats = NULL, |
@@ -637,6 +656,7 @@ static struct rcu_torture_ops srcu_ops = { | |||
637 | .completed = srcu_torture_completed, | 656 | .completed = srcu_torture_completed, |
638 | .deferred_free = rcu_sync_torture_deferred_free, | 657 | .deferred_free = rcu_sync_torture_deferred_free, |
639 | .sync = srcu_torture_synchronize, | 658 | .sync = srcu_torture_synchronize, |
659 | .call = NULL, | ||
640 | .cb_barrier = NULL, | 660 | .cb_barrier = NULL, |
641 | .stats = srcu_torture_stats, | 661 | .stats = srcu_torture_stats, |
642 | .name = "srcu" | 662 | .name = "srcu" |
@@ -661,6 +681,7 @@ static struct rcu_torture_ops srcu_raw_ops = { | |||
661 | .completed = srcu_torture_completed, | 681 | .completed = srcu_torture_completed, |
662 | .deferred_free = rcu_sync_torture_deferred_free, | 682 | .deferred_free = rcu_sync_torture_deferred_free, |
663 | .sync = srcu_torture_synchronize, | 683 | .sync = srcu_torture_synchronize, |
684 | .call = NULL, | ||
664 | .cb_barrier = NULL, | 685 | .cb_barrier = NULL, |
665 | .stats = srcu_torture_stats, | 686 | .stats = srcu_torture_stats, |
666 | .name = "srcu_raw" | 687 | .name = "srcu_raw" |
@@ -680,6 +701,7 @@ static struct rcu_torture_ops srcu_expedited_ops = { | |||
680 | .completed = srcu_torture_completed, | 701 | .completed = srcu_torture_completed, |
681 | .deferred_free = rcu_sync_torture_deferred_free, | 702 | .deferred_free = rcu_sync_torture_deferred_free, |
682 | .sync = srcu_torture_synchronize_expedited, | 703 | .sync = srcu_torture_synchronize_expedited, |
704 | .call = NULL, | ||
683 | .cb_barrier = NULL, | 705 | .cb_barrier = NULL, |
684 | .stats = srcu_torture_stats, | 706 | .stats = srcu_torture_stats, |
685 | .name = "srcu_expedited" | 707 | .name = "srcu_expedited" |
@@ -1129,7 +1151,8 @@ rcu_torture_printk(char *page) | |||
1129 | "rtc: %p ver: %lu tfle: %d rta: %d rtaf: %d rtf: %d " | 1151 | "rtc: %p ver: %lu tfle: %d rta: %d rtaf: %d rtf: %d " |
1130 | "rtmbe: %d rtbke: %ld rtbre: %ld " | 1152 | "rtmbe: %d rtbke: %ld rtbre: %ld " |
1131 | "rtbf: %ld rtb: %ld nt: %ld " | 1153 | "rtbf: %ld rtb: %ld nt: %ld " |
1132 | "onoff: %ld/%ld:%ld/%ld", | 1154 | "onoff: %ld/%ld:%ld/%ld " |
1155 | "barrier: %ld/%ld:%ld", | ||
1133 | rcu_torture_current, | 1156 | rcu_torture_current, |
1134 | rcu_torture_current_version, | 1157 | rcu_torture_current_version, |
1135 | list_empty(&rcu_torture_freelist), | 1158 | list_empty(&rcu_torture_freelist), |
@@ -1145,14 +1168,17 @@ rcu_torture_printk(char *page) | |||
1145 | n_online_successes, | 1168 | n_online_successes, |
1146 | n_online_attempts, | 1169 | n_online_attempts, |
1147 | n_offline_successes, | 1170 | n_offline_successes, |
1148 | n_offline_attempts); | 1171 | n_offline_attempts, |
1172 | n_barrier_successes, | ||
1173 | n_barrier_attempts, | ||
1174 | n_rcu_torture_barrier_error); | ||
1175 | cnt += sprintf(&page[cnt], "\n%s%s ", torture_type, TORTURE_FLAG); | ||
1149 | if (atomic_read(&n_rcu_torture_mberror) != 0 || | 1176 | if (atomic_read(&n_rcu_torture_mberror) != 0 || |
1177 | n_rcu_torture_barrier_error != 0 || | ||
1150 | n_rcu_torture_boost_ktrerror != 0 || | 1178 | n_rcu_torture_boost_ktrerror != 0 || |
1151 | n_rcu_torture_boost_rterror != 0 || | 1179 | n_rcu_torture_boost_rterror != 0 || |
1152 | n_rcu_torture_boost_failure != 0) | 1180 | n_rcu_torture_boost_failure != 0 || |
1153 | cnt += sprintf(&page[cnt], " !!!"); | 1181 | i > 1) { |
1154 | cnt += sprintf(&page[cnt], "\n%s%s ", torture_type, TORTURE_FLAG); | ||
1155 | if (i > 1) { | ||
1156 | cnt += sprintf(&page[cnt], "!!! "); | 1182 | cnt += sprintf(&page[cnt], "!!! "); |
1157 | atomic_inc(&n_rcu_torture_error); | 1183 | atomic_inc(&n_rcu_torture_error); |
1158 | WARN_ON_ONCE(1); | 1184 | WARN_ON_ONCE(1); |
@@ -1560,6 +1586,151 @@ static void rcu_torture_stall_cleanup(void) | |||
1560 | stall_task = NULL; | 1586 | stall_task = NULL; |
1561 | } | 1587 | } |
1562 | 1588 | ||
1589 | /* Callback function for RCU barrier testing. */ | ||
1590 | void rcu_torture_barrier_cbf(struct rcu_head *rcu) | ||
1591 | { | ||
1592 | atomic_inc(&barrier_cbs_invoked); | ||
1593 | } | ||
1594 | |||
1595 | /* kthread function to register callbacks used to test RCU barriers. */ | ||
1596 | static int rcu_torture_barrier_cbs(void *arg) | ||
1597 | { | ||
1598 | long myid = (long)arg; | ||
1599 | struct rcu_head rcu; | ||
1600 | |||
1601 | init_rcu_head_on_stack(&rcu); | ||
1602 | VERBOSE_PRINTK_STRING("rcu_torture_barrier_cbs task started"); | ||
1603 | set_user_nice(current, 19); | ||
1604 | do { | ||
1605 | wait_event(barrier_cbs_wq[myid], | ||
1606 | atomic_read(&barrier_cbs_count) == n_barrier_cbs || | ||
1607 | kthread_should_stop() || | ||
1608 | fullstop != FULLSTOP_DONTSTOP); | ||
1609 | if (kthread_should_stop() || fullstop != FULLSTOP_DONTSTOP) | ||
1610 | break; | ||
1611 | cur_ops->call(&rcu, rcu_torture_barrier_cbf); | ||
1612 | if (atomic_dec_and_test(&barrier_cbs_count)) | ||
1613 | wake_up(&barrier_wq); | ||
1614 | } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP); | ||
1615 | VERBOSE_PRINTK_STRING("rcu_torture_barrier_cbs task stopping"); | ||
1616 | rcutorture_shutdown_absorb("rcu_torture_barrier_cbs"); | ||
1617 | while (!kthread_should_stop()) | ||
1618 | schedule_timeout_interruptible(1); | ||
1619 | cur_ops->cb_barrier(); | ||
1620 | destroy_rcu_head_on_stack(&rcu); | ||
1621 | return 0; | ||
1622 | } | ||
1623 | |||
1624 | /* kthread function to drive and coordinate RCU barrier testing. */ | ||
1625 | static int rcu_torture_barrier(void *arg) | ||
1626 | { | ||
1627 | int i; | ||
1628 | |||
1629 | VERBOSE_PRINTK_STRING("rcu_torture_barrier task starting"); | ||
1630 | do { | ||
1631 | atomic_set(&barrier_cbs_invoked, 0); | ||
1632 | atomic_set(&barrier_cbs_count, n_barrier_cbs); | ||
1633 | /* wake_up() path contains the required barriers. */ | ||
1634 | for (i = 0; i < n_barrier_cbs; i++) | ||
1635 | wake_up(&barrier_cbs_wq[i]); | ||
1636 | wait_event(barrier_wq, | ||
1637 | atomic_read(&barrier_cbs_count) == 0 || | ||
1638 | kthread_should_stop() || | ||
1639 | fullstop != FULLSTOP_DONTSTOP); | ||
1640 | if (kthread_should_stop() || fullstop != FULLSTOP_DONTSTOP) | ||
1641 | break; | ||
1642 | n_barrier_attempts++; | ||
1643 | cur_ops->cb_barrier(); | ||
1644 | if (atomic_read(&barrier_cbs_invoked) != n_barrier_cbs) { | ||
1645 | n_rcu_torture_barrier_error++; | ||
1646 | WARN_ON_ONCE(1); | ||
1647 | } | ||
1648 | n_barrier_successes++; | ||
1649 | schedule_timeout_interruptible(HZ / 10); | ||
1650 | } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP); | ||
1651 | VERBOSE_PRINTK_STRING("rcu_torture_barrier task stopping"); | ||
1652 | rcutorture_shutdown_absorb("rcu_torture_barrier_cbs"); | ||
1653 | while (!kthread_should_stop()) | ||
1654 | schedule_timeout_interruptible(1); | ||
1655 | return 0; | ||
1656 | } | ||
1657 | |||
1658 | /* Initialize RCU barrier testing. */ | ||
1659 | static int rcu_torture_barrier_init(void) | ||
1660 | { | ||
1661 | int i; | ||
1662 | int ret; | ||
1663 | |||
1664 | if (n_barrier_cbs == 0) | ||
1665 | return 0; | ||
1666 | if (cur_ops->call == NULL || cur_ops->cb_barrier == NULL) { | ||
1667 | printk(KERN_ALERT "%s" TORTURE_FLAG | ||
1668 | " Call or barrier ops missing for %s,\n", | ||
1669 | torture_type, cur_ops->name); | ||
1670 | printk(KERN_ALERT "%s" TORTURE_FLAG | ||
1671 | " RCU barrier testing omitted from run.\n", | ||
1672 | torture_type); | ||
1673 | return 0; | ||
1674 | } | ||
1675 | atomic_set(&barrier_cbs_count, 0); | ||
1676 | atomic_set(&barrier_cbs_invoked, 0); | ||
1677 | barrier_cbs_tasks = | ||
1678 | kzalloc(n_barrier_cbs * sizeof(barrier_cbs_tasks[0]), | ||
1679 | GFP_KERNEL); | ||
1680 | barrier_cbs_wq = | ||
1681 | kzalloc(n_barrier_cbs * sizeof(barrier_cbs_wq[0]), | ||
1682 | GFP_KERNEL); | ||
1683 | if (barrier_cbs_tasks == NULL || barrier_cbs_wq == 0) | ||
1684 | return -ENOMEM; | ||
1685 | for (i = 0; i < n_barrier_cbs; i++) { | ||
1686 | init_waitqueue_head(&barrier_cbs_wq[i]); | ||
1687 | barrier_cbs_tasks[i] = kthread_run(rcu_torture_barrier_cbs, | ||
1688 | (void *)i, | ||
1689 | "rcu_torture_barrier_cbs"); | ||
1690 | if (IS_ERR(barrier_cbs_tasks[i])) { | ||
1691 | ret = PTR_ERR(barrier_cbs_tasks[i]); | ||
1692 | VERBOSE_PRINTK_ERRSTRING("Failed to create rcu_torture_barrier_cbs"); | ||
1693 | barrier_cbs_tasks[i] = NULL; | ||
1694 | return ret; | ||
1695 | } | ||
1696 | } | ||
1697 | barrier_task = kthread_run(rcu_torture_barrier, NULL, | ||
1698 | "rcu_torture_barrier"); | ||
1699 | if (IS_ERR(barrier_task)) { | ||
1700 | ret = PTR_ERR(barrier_task); | ||
1701 | VERBOSE_PRINTK_ERRSTRING("Failed to create rcu_torture_barrier"); | ||
1702 | barrier_task = NULL; | ||
1703 | } | ||
1704 | return 0; | ||
1705 | } | ||
1706 | |||
1707 | /* Clean up after RCU barrier testing. */ | ||
1708 | static void rcu_torture_barrier_cleanup(void) | ||
1709 | { | ||
1710 | int i; | ||
1711 | |||
1712 | if (barrier_task != NULL) { | ||
1713 | VERBOSE_PRINTK_STRING("Stopping rcu_torture_barrier task"); | ||
1714 | kthread_stop(barrier_task); | ||
1715 | barrier_task = NULL; | ||
1716 | } | ||
1717 | if (barrier_cbs_tasks != NULL) { | ||
1718 | for (i = 0; i < n_barrier_cbs; i++) { | ||
1719 | if (barrier_cbs_tasks[i] != NULL) { | ||
1720 | VERBOSE_PRINTK_STRING("Stopping rcu_torture_barrier_cbs task"); | ||
1721 | kthread_stop(barrier_cbs_tasks[i]); | ||
1722 | barrier_cbs_tasks[i] = NULL; | ||
1723 | } | ||
1724 | } | ||
1725 | kfree(barrier_cbs_tasks); | ||
1726 | barrier_cbs_tasks = NULL; | ||
1727 | } | ||
1728 | if (barrier_cbs_wq != NULL) { | ||
1729 | kfree(barrier_cbs_wq); | ||
1730 | barrier_cbs_wq = NULL; | ||
1731 | } | ||
1732 | } | ||
1733 | |||
1563 | static int rcutorture_cpu_notify(struct notifier_block *self, | 1734 | static int rcutorture_cpu_notify(struct notifier_block *self, |
1564 | unsigned long action, void *hcpu) | 1735 | unsigned long action, void *hcpu) |
1565 | { | 1736 | { |
@@ -1602,6 +1773,7 @@ rcu_torture_cleanup(void) | |||
1602 | fullstop = FULLSTOP_RMMOD; | 1773 | fullstop = FULLSTOP_RMMOD; |
1603 | mutex_unlock(&fullstop_mutex); | 1774 | mutex_unlock(&fullstop_mutex); |
1604 | unregister_reboot_notifier(&rcutorture_shutdown_nb); | 1775 | unregister_reboot_notifier(&rcutorture_shutdown_nb); |
1776 | rcu_torture_barrier_cleanup(); | ||
1605 | rcu_torture_stall_cleanup(); | 1777 | rcu_torture_stall_cleanup(); |
1606 | if (stutter_task) { | 1778 | if (stutter_task) { |
1607 | VERBOSE_PRINTK_STRING("Stopping rcu_torture_stutter task"); | 1779 | VERBOSE_PRINTK_STRING("Stopping rcu_torture_stutter task"); |
@@ -1681,7 +1853,7 @@ rcu_torture_cleanup(void) | |||
1681 | 1853 | ||
1682 | if (cur_ops->cleanup) | 1854 | if (cur_ops->cleanup) |
1683 | cur_ops->cleanup(); | 1855 | cur_ops->cleanup(); |
1684 | if (atomic_read(&n_rcu_torture_error)) | 1856 | if (atomic_read(&n_rcu_torture_error) || n_rcu_torture_barrier_error) |
1685 | rcu_torture_print_module_parms(cur_ops, "End of test: FAILURE"); | 1857 | rcu_torture_print_module_parms(cur_ops, "End of test: FAILURE"); |
1686 | else if (n_online_successes != n_online_attempts || | 1858 | else if (n_online_successes != n_online_attempts || |
1687 | n_offline_successes != n_offline_attempts) | 1859 | n_offline_successes != n_offline_attempts) |
@@ -1697,6 +1869,7 @@ rcu_torture_init(void) | |||
1697 | int i; | 1869 | int i; |
1698 | int cpu; | 1870 | int cpu; |
1699 | int firsterr = 0; | 1871 | int firsterr = 0; |
1872 | int retval; | ||
1700 | static struct rcu_torture_ops *torture_ops[] = | 1873 | static struct rcu_torture_ops *torture_ops[] = |
1701 | { &rcu_ops, &rcu_sync_ops, &rcu_expedited_ops, | 1874 | { &rcu_ops, &rcu_sync_ops, &rcu_expedited_ops, |
1702 | &rcu_bh_ops, &rcu_bh_sync_ops, &rcu_bh_expedited_ops, | 1875 | &rcu_bh_ops, &rcu_bh_sync_ops, &rcu_bh_expedited_ops, |
@@ -1754,6 +1927,7 @@ rcu_torture_init(void) | |||
1754 | atomic_set(&n_rcu_torture_free, 0); | 1927 | atomic_set(&n_rcu_torture_free, 0); |
1755 | atomic_set(&n_rcu_torture_mberror, 0); | 1928 | atomic_set(&n_rcu_torture_mberror, 0); |
1756 | atomic_set(&n_rcu_torture_error, 0); | 1929 | atomic_set(&n_rcu_torture_error, 0); |
1930 | n_rcu_torture_barrier_error = 0; | ||
1757 | n_rcu_torture_boost_ktrerror = 0; | 1931 | n_rcu_torture_boost_ktrerror = 0; |
1758 | n_rcu_torture_boost_rterror = 0; | 1932 | n_rcu_torture_boost_rterror = 0; |
1759 | n_rcu_torture_boost_failure = 0; | 1933 | n_rcu_torture_boost_failure = 0; |
@@ -1877,7 +2051,6 @@ rcu_torture_init(void) | |||
1877 | test_boost_duration = 2; | 2051 | test_boost_duration = 2; |
1878 | if ((test_boost == 1 && cur_ops->can_boost) || | 2052 | if ((test_boost == 1 && cur_ops->can_boost) || |
1879 | test_boost == 2) { | 2053 | test_boost == 2) { |
1880 | int retval; | ||
1881 | 2054 | ||
1882 | boost_starttime = jiffies + test_boost_interval * HZ; | 2055 | boost_starttime = jiffies + test_boost_interval * HZ; |
1883 | register_cpu_notifier(&rcutorture_cpu_nb); | 2056 | register_cpu_notifier(&rcutorture_cpu_nb); |
@@ -1913,6 +2086,11 @@ rcu_torture_init(void) | |||
1913 | firsterr = i; | 2086 | firsterr = i; |
1914 | goto unwind; | 2087 | goto unwind; |
1915 | } | 2088 | } |
2089 | retval = rcu_torture_barrier_init(); | ||
2090 | if (retval != 0) { | ||
2091 | firsterr = retval; | ||
2092 | goto unwind; | ||
2093 | } | ||
1916 | rcutorture_record_test_transition(); | 2094 | rcutorture_record_test_transition(); |
1917 | mutex_unlock(&fullstop_mutex); | 2095 | mutex_unlock(&fullstop_mutex); |
1918 | return 0; | 2096 | return 0; |