aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/rcutorture.c
diff options
context:
space:
mode:
authorPaul E. McKenney <paul.mckenney@linaro.org>2012-05-28 22:21:41 -0400
committerPaul E. McKenney <paulmck@linux.vnet.ibm.com>2012-07-02 15:34:03 -0400
commitc6ebcbb60c8c68a88160fe54302e851700d1362c (patch)
treed95b0c10d7107d3d34a108aa75222820157fd599 /kernel/rcutorture.c
parente3f8d3788ed7cf55946030dc9b76e73edb111602 (diff)
rcu: Fix bug in rcu_barrier() torture test
The child threads in the rcu_torture_barrier_cbs() are improperly synchronized, which can cause the rcu_barrier() tests to hang. The failure mode is as follows: 1. CPU 0 running in rcu_torture_barrier() sets barrier_cbs_count to n_barrier_cbs. 2. CPU 1 running in rcu_torture_barrier_cbs() wakes up, posts its RCU callback, and atomically decrements barrier_cbs_count. Because barrier_cbs_count is not zero, it does not do the wake_up(). 3. CPU 2 running in rcu_torture_barrier_cbs() wakes up, but finds that barrier_cbs_count is not equal to n_barrier_cbs, and so returns to sleep. 4. The value of barrier_cbs_count therefore never reaches zero, which causes the test to hang. This commit therefore uses a phase variable to coordinate the test, preventing this scenario from occurring. 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.c9
1 files changed, 7 insertions, 2 deletions
diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c
index 7b6935e0cee3..f7fe73e59c9f 100644
--- a/kernel/rcutorture.c
+++ b/kernel/rcutorture.c
@@ -206,6 +206,7 @@ static unsigned long boost_starttime; /* jiffies of next boost test start. */
206DEFINE_MUTEX(boost_mutex); /* protect setting boost_starttime */ 206DEFINE_MUTEX(boost_mutex); /* protect setting boost_starttime */
207 /* and boost task create/destroy. */ 207 /* and boost task create/destroy. */
208static atomic_t barrier_cbs_count; /* Barrier callbacks registered. */ 208static atomic_t barrier_cbs_count; /* Barrier callbacks registered. */
209static bool barrier_phase; /* Test phase. */
209static atomic_t barrier_cbs_invoked; /* Barrier callbacks invoked. */ 210static atomic_t barrier_cbs_invoked; /* Barrier callbacks invoked. */
210static wait_queue_head_t *barrier_cbs_wq; /* Coordinate barrier testing. */ 211static wait_queue_head_t *barrier_cbs_wq; /* Coordinate barrier testing. */
211static DECLARE_WAIT_QUEUE_HEAD(barrier_wq); 212static DECLARE_WAIT_QUEUE_HEAD(barrier_wq);
@@ -1642,6 +1643,7 @@ void rcu_torture_barrier_cbf(struct rcu_head *rcu)
1642static int rcu_torture_barrier_cbs(void *arg) 1643static int rcu_torture_barrier_cbs(void *arg)
1643{ 1644{
1644 long myid = (long)arg; 1645 long myid = (long)arg;
1646 bool lastphase = 0;
1645 struct rcu_head rcu; 1647 struct rcu_head rcu;
1646 1648
1647 init_rcu_head_on_stack(&rcu); 1649 init_rcu_head_on_stack(&rcu);
@@ -1649,9 +1651,11 @@ static int rcu_torture_barrier_cbs(void *arg)
1649 set_user_nice(current, 19); 1651 set_user_nice(current, 19);
1650 do { 1652 do {
1651 wait_event(barrier_cbs_wq[myid], 1653 wait_event(barrier_cbs_wq[myid],
1652 atomic_read(&barrier_cbs_count) == n_barrier_cbs || 1654 barrier_phase != lastphase ||
1653 kthread_should_stop() || 1655 kthread_should_stop() ||
1654 fullstop != FULLSTOP_DONTSTOP); 1656 fullstop != FULLSTOP_DONTSTOP);
1657 lastphase = barrier_phase;
1658 smp_mb(); /* ensure barrier_phase load before ->call(). */
1655 if (kthread_should_stop() || fullstop != FULLSTOP_DONTSTOP) 1659 if (kthread_should_stop() || fullstop != FULLSTOP_DONTSTOP)
1656 break; 1660 break;
1657 cur_ops->call(&rcu, rcu_torture_barrier_cbf); 1661 cur_ops->call(&rcu, rcu_torture_barrier_cbf);
@@ -1676,7 +1680,8 @@ static int rcu_torture_barrier(void *arg)
1676 do { 1680 do {
1677 atomic_set(&barrier_cbs_invoked, 0); 1681 atomic_set(&barrier_cbs_invoked, 0);
1678 atomic_set(&barrier_cbs_count, n_barrier_cbs); 1682 atomic_set(&barrier_cbs_count, n_barrier_cbs);
1679 /* wake_up() path contains the required barriers. */ 1683 smp_mb(); /* Ensure barrier_phase after prior assignments. */
1684 barrier_phase = !barrier_phase;
1680 for (i = 0; i < n_barrier_cbs; i++) 1685 for (i = 0; i < n_barrier_cbs; i++)
1681 wake_up(&barrier_cbs_wq[i]); 1686 wake_up(&barrier_cbs_wq[i]);
1682 wait_event(barrier_wq, 1687 wait_event(barrier_wq,