aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorPaul E. McKenney <paulmck@linux.vnet.ibm.com>2013-12-11 16:59:10 -0500
committerIngo Molnar <mingo@kernel.org>2013-12-16 05:36:16 -0500
commit6303b9c87d52eaedc82968d3ff59c471e7682afc (patch)
treeffadb26316714834e26898f5fae6a9fa0f463934 /kernel
parent17eb88e068430014deb709e5af34197cdf2390c9 (diff)
rcu: Apply smp_mb__after_unlock_lock() to preserve grace periods
RCU must ensure that there is the equivalent of a full memory barrier between any memory access preceding grace period and any memory access following that same grace period, regardless of which CPU(s) happen to execute the two memory accesses. Therefore, downgrading UNLOCK+LOCK to no longer imply a full memory barrier requires some adjustments to RCU. This commit therefore adds smp_mb__after_unlock_lock() invocations as needed after the RCU lock acquisitions that need to be part of a full-memory-barrier UNLOCK+LOCK. Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Reviewed-by: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: <linux-arch@vger.kernel.org> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Andrew Morton <akpm@linux-foundation.org> Link: http://lkml.kernel.org/r/1386799151-2219-7-git-send-email-paulmck@linux.vnet.ibm.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/rcu/tree.c18
-rw-r--r--kernel/rcu/tree_plugin.h13
2 files changed, 30 insertions, 1 deletions
diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
index dd081987a8ec..a6205a05b5e4 100644
--- a/kernel/rcu/tree.c
+++ b/kernel/rcu/tree.c
@@ -1133,8 +1133,10 @@ rcu_start_future_gp(struct rcu_node *rnp, struct rcu_data *rdp)
1133 * hold it, acquire the root rcu_node structure's lock in order to 1133 * hold it, acquire the root rcu_node structure's lock in order to
1134 * start one (if needed). 1134 * start one (if needed).
1135 */ 1135 */
1136 if (rnp != rnp_root) 1136 if (rnp != rnp_root) {
1137 raw_spin_lock(&rnp_root->lock); 1137 raw_spin_lock(&rnp_root->lock);
1138 smp_mb__after_unlock_lock();
1139 }
1138 1140
1139 /* 1141 /*
1140 * Get a new grace-period number. If there really is no grace 1142 * Get a new grace-period number. If there really is no grace
@@ -1354,6 +1356,7 @@ static void note_gp_changes(struct rcu_state *rsp, struct rcu_data *rdp)
1354 local_irq_restore(flags); 1356 local_irq_restore(flags);
1355 return; 1357 return;
1356 } 1358 }
1359 smp_mb__after_unlock_lock();
1357 __note_gp_changes(rsp, rnp, rdp); 1360 __note_gp_changes(rsp, rnp, rdp);
1358 raw_spin_unlock_irqrestore(&rnp->lock, flags); 1361 raw_spin_unlock_irqrestore(&rnp->lock, flags);
1359} 1362}
@@ -1368,6 +1371,7 @@ static int rcu_gp_init(struct rcu_state *rsp)
1368 1371
1369 rcu_bind_gp_kthread(); 1372 rcu_bind_gp_kthread();
1370 raw_spin_lock_irq(&rnp->lock); 1373 raw_spin_lock_irq(&rnp->lock);
1374 smp_mb__after_unlock_lock();
1371 if (rsp->gp_flags == 0) { 1375 if (rsp->gp_flags == 0) {
1372 /* Spurious wakeup, tell caller to go back to sleep. */ 1376 /* Spurious wakeup, tell caller to go back to sleep. */
1373 raw_spin_unlock_irq(&rnp->lock); 1377 raw_spin_unlock_irq(&rnp->lock);
@@ -1409,6 +1413,7 @@ static int rcu_gp_init(struct rcu_state *rsp)
1409 */ 1413 */
1410 rcu_for_each_node_breadth_first(rsp, rnp) { 1414 rcu_for_each_node_breadth_first(rsp, rnp) {
1411 raw_spin_lock_irq(&rnp->lock); 1415 raw_spin_lock_irq(&rnp->lock);
1416 smp_mb__after_unlock_lock();
1412 rdp = this_cpu_ptr(rsp->rda); 1417 rdp = this_cpu_ptr(rsp->rda);
1413 rcu_preempt_check_blocked_tasks(rnp); 1418 rcu_preempt_check_blocked_tasks(rnp);
1414 rnp->qsmask = rnp->qsmaskinit; 1419 rnp->qsmask = rnp->qsmaskinit;
@@ -1463,6 +1468,7 @@ static int rcu_gp_fqs(struct rcu_state *rsp, int fqs_state_in)
1463 /* Clear flag to prevent immediate re-entry. */ 1468 /* Clear flag to prevent immediate re-entry. */
1464 if (ACCESS_ONCE(rsp->gp_flags) & RCU_GP_FLAG_FQS) { 1469 if (ACCESS_ONCE(rsp->gp_flags) & RCU_GP_FLAG_FQS) {
1465 raw_spin_lock_irq(&rnp->lock); 1470 raw_spin_lock_irq(&rnp->lock);
1471 smp_mb__after_unlock_lock();
1466 rsp->gp_flags &= ~RCU_GP_FLAG_FQS; 1472 rsp->gp_flags &= ~RCU_GP_FLAG_FQS;
1467 raw_spin_unlock_irq(&rnp->lock); 1473 raw_spin_unlock_irq(&rnp->lock);
1468 } 1474 }
@@ -1480,6 +1486,7 @@ static void rcu_gp_cleanup(struct rcu_state *rsp)
1480 struct rcu_node *rnp = rcu_get_root(rsp); 1486 struct rcu_node *rnp = rcu_get_root(rsp);
1481 1487
1482 raw_spin_lock_irq(&rnp->lock); 1488 raw_spin_lock_irq(&rnp->lock);
1489 smp_mb__after_unlock_lock();
1483 gp_duration = jiffies - rsp->gp_start; 1490 gp_duration = jiffies - rsp->gp_start;
1484 if (gp_duration > rsp->gp_max) 1491 if (gp_duration > rsp->gp_max)
1485 rsp->gp_max = gp_duration; 1492 rsp->gp_max = gp_duration;
@@ -1505,6 +1512,7 @@ static void rcu_gp_cleanup(struct rcu_state *rsp)
1505 */ 1512 */
1506 rcu_for_each_node_breadth_first(rsp, rnp) { 1513 rcu_for_each_node_breadth_first(rsp, rnp) {
1507 raw_spin_lock_irq(&rnp->lock); 1514 raw_spin_lock_irq(&rnp->lock);
1515 smp_mb__after_unlock_lock();
1508 ACCESS_ONCE(rnp->completed) = rsp->gpnum; 1516 ACCESS_ONCE(rnp->completed) = rsp->gpnum;
1509 rdp = this_cpu_ptr(rsp->rda); 1517 rdp = this_cpu_ptr(rsp->rda);
1510 if (rnp == rdp->mynode) 1518 if (rnp == rdp->mynode)
@@ -1515,6 +1523,7 @@ static void rcu_gp_cleanup(struct rcu_state *rsp)
1515 } 1523 }
1516 rnp = rcu_get_root(rsp); 1524 rnp = rcu_get_root(rsp);
1517 raw_spin_lock_irq(&rnp->lock); 1525 raw_spin_lock_irq(&rnp->lock);
1526 smp_mb__after_unlock_lock();
1518 rcu_nocb_gp_set(rnp, nocb); 1527 rcu_nocb_gp_set(rnp, nocb);
1519 1528
1520 rsp->completed = rsp->gpnum; /* Declare grace period done. */ 1529 rsp->completed = rsp->gpnum; /* Declare grace period done. */
@@ -1749,6 +1758,7 @@ rcu_report_qs_rnp(unsigned long mask, struct rcu_state *rsp,
1749 rnp_c = rnp; 1758 rnp_c = rnp;
1750 rnp = rnp->parent; 1759 rnp = rnp->parent;
1751 raw_spin_lock_irqsave(&rnp->lock, flags); 1760 raw_spin_lock_irqsave(&rnp->lock, flags);
1761 smp_mb__after_unlock_lock();
1752 WARN_ON_ONCE(rnp_c->qsmask); 1762 WARN_ON_ONCE(rnp_c->qsmask);
1753 } 1763 }
1754 1764
@@ -1778,6 +1788,7 @@ rcu_report_qs_rdp(int cpu, struct rcu_state *rsp, struct rcu_data *rdp)
1778 1788
1779 rnp = rdp->mynode; 1789 rnp = rdp->mynode;
1780 raw_spin_lock_irqsave(&rnp->lock, flags); 1790 raw_spin_lock_irqsave(&rnp->lock, flags);
1791 smp_mb__after_unlock_lock();
1781 if (rdp->passed_quiesce == 0 || rdp->gpnum != rnp->gpnum || 1792 if (rdp->passed_quiesce == 0 || rdp->gpnum != rnp->gpnum ||
1782 rnp->completed == rnp->gpnum) { 1793 rnp->completed == rnp->gpnum) {
1783 1794
@@ -1992,6 +2003,7 @@ static void rcu_cleanup_dead_cpu(int cpu, struct rcu_state *rsp)
1992 mask = rdp->grpmask; /* rnp->grplo is constant. */ 2003 mask = rdp->grpmask; /* rnp->grplo is constant. */
1993 do { 2004 do {
1994 raw_spin_lock(&rnp->lock); /* irqs already disabled. */ 2005 raw_spin_lock(&rnp->lock); /* irqs already disabled. */
2006 smp_mb__after_unlock_lock();
1995 rnp->qsmaskinit &= ~mask; 2007 rnp->qsmaskinit &= ~mask;
1996 if (rnp->qsmaskinit != 0) { 2008 if (rnp->qsmaskinit != 0) {
1997 if (rnp != rdp->mynode) 2009 if (rnp != rdp->mynode)
@@ -2202,6 +2214,7 @@ static void force_qs_rnp(struct rcu_state *rsp,
2202 cond_resched(); 2214 cond_resched();
2203 mask = 0; 2215 mask = 0;
2204 raw_spin_lock_irqsave(&rnp->lock, flags); 2216 raw_spin_lock_irqsave(&rnp->lock, flags);
2217 smp_mb__after_unlock_lock();
2205 if (!rcu_gp_in_progress(rsp)) { 2218 if (!rcu_gp_in_progress(rsp)) {
2206 raw_spin_unlock_irqrestore(&rnp->lock, flags); 2219 raw_spin_unlock_irqrestore(&rnp->lock, flags);
2207 return; 2220 return;
@@ -2231,6 +2244,7 @@ static void force_qs_rnp(struct rcu_state *rsp,
2231 rnp = rcu_get_root(rsp); 2244 rnp = rcu_get_root(rsp);
2232 if (rnp->qsmask == 0) { 2245 if (rnp->qsmask == 0) {
2233 raw_spin_lock_irqsave(&rnp->lock, flags); 2246 raw_spin_lock_irqsave(&rnp->lock, flags);
2247 smp_mb__after_unlock_lock();
2234 rcu_initiate_boost(rnp, flags); /* releases rnp->lock. */ 2248 rcu_initiate_boost(rnp, flags); /* releases rnp->lock. */
2235 } 2249 }
2236} 2250}
@@ -2263,6 +2277,7 @@ static void force_quiescent_state(struct rcu_state *rsp)
2263 2277
2264 /* Reached the root of the rcu_node tree, acquire lock. */ 2278 /* Reached the root of the rcu_node tree, acquire lock. */
2265 raw_spin_lock_irqsave(&rnp_old->lock, flags); 2279 raw_spin_lock_irqsave(&rnp_old->lock, flags);
2280 smp_mb__after_unlock_lock();
2266 raw_spin_unlock(&rnp_old->fqslock); 2281 raw_spin_unlock(&rnp_old->fqslock);
2267 if (ACCESS_ONCE(rsp->gp_flags) & RCU_GP_FLAG_FQS) { 2282 if (ACCESS_ONCE(rsp->gp_flags) & RCU_GP_FLAG_FQS) {
2268 rsp->n_force_qs_lh++; 2283 rsp->n_force_qs_lh++;
@@ -2378,6 +2393,7 @@ static void __call_rcu_core(struct rcu_state *rsp, struct rcu_data *rdp,
2378 struct rcu_node *rnp_root = rcu_get_root(rsp); 2393 struct rcu_node *rnp_root = rcu_get_root(rsp);
2379 2394
2380 raw_spin_lock(&rnp_root->lock); 2395 raw_spin_lock(&rnp_root->lock);
2396 smp_mb__after_unlock_lock();
2381 rcu_start_gp(rsp); 2397 rcu_start_gp(rsp);
2382 raw_spin_unlock(&rnp_root->lock); 2398 raw_spin_unlock(&rnp_root->lock);
2383 } else { 2399 } else {
diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h
index 6abb03dff5c0..eb161d80cbde 100644
--- a/kernel/rcu/tree_plugin.h
+++ b/kernel/rcu/tree_plugin.h
@@ -204,6 +204,7 @@ static void rcu_preempt_note_context_switch(int cpu)
204 rdp = per_cpu_ptr(rcu_preempt_state.rda, cpu); 204 rdp = per_cpu_ptr(rcu_preempt_state.rda, cpu);
205 rnp = rdp->mynode; 205 rnp = rdp->mynode;
206 raw_spin_lock_irqsave(&rnp->lock, flags); 206 raw_spin_lock_irqsave(&rnp->lock, flags);
207 smp_mb__after_unlock_lock();
207 t->rcu_read_unlock_special |= RCU_READ_UNLOCK_BLOCKED; 208 t->rcu_read_unlock_special |= RCU_READ_UNLOCK_BLOCKED;
208 t->rcu_blocked_node = rnp; 209 t->rcu_blocked_node = rnp;
209 210
@@ -312,6 +313,7 @@ static void rcu_report_unblock_qs_rnp(struct rcu_node *rnp, unsigned long flags)
312 mask = rnp->grpmask; 313 mask = rnp->grpmask;
313 raw_spin_unlock(&rnp->lock); /* irqs remain disabled. */ 314 raw_spin_unlock(&rnp->lock); /* irqs remain disabled. */
314 raw_spin_lock(&rnp_p->lock); /* irqs already disabled. */ 315 raw_spin_lock(&rnp_p->lock); /* irqs already disabled. */
316 smp_mb__after_unlock_lock();
315 rcu_report_qs_rnp(mask, &rcu_preempt_state, rnp_p, flags); 317 rcu_report_qs_rnp(mask, &rcu_preempt_state, rnp_p, flags);
316} 318}
317 319
@@ -381,6 +383,7 @@ void rcu_read_unlock_special(struct task_struct *t)
381 for (;;) { 383 for (;;) {
382 rnp = t->rcu_blocked_node; 384 rnp = t->rcu_blocked_node;
383 raw_spin_lock(&rnp->lock); /* irqs already disabled. */ 385 raw_spin_lock(&rnp->lock); /* irqs already disabled. */
386 smp_mb__after_unlock_lock();
384 if (rnp == t->rcu_blocked_node) 387 if (rnp == t->rcu_blocked_node)
385 break; 388 break;
386 raw_spin_unlock(&rnp->lock); /* irqs remain disabled. */ 389 raw_spin_unlock(&rnp->lock); /* irqs remain disabled. */
@@ -605,6 +608,7 @@ static int rcu_preempt_offline_tasks(struct rcu_state *rsp,
605 while (!list_empty(lp)) { 608 while (!list_empty(lp)) {
606 t = list_entry(lp->next, typeof(*t), rcu_node_entry); 609 t = list_entry(lp->next, typeof(*t), rcu_node_entry);
607 raw_spin_lock(&rnp_root->lock); /* irqs already disabled */ 610 raw_spin_lock(&rnp_root->lock); /* irqs already disabled */
611 smp_mb__after_unlock_lock();
608 list_del(&t->rcu_node_entry); 612 list_del(&t->rcu_node_entry);
609 t->rcu_blocked_node = rnp_root; 613 t->rcu_blocked_node = rnp_root;
610 list_add(&t->rcu_node_entry, lp_root); 614 list_add(&t->rcu_node_entry, lp_root);
@@ -629,6 +633,7 @@ static int rcu_preempt_offline_tasks(struct rcu_state *rsp,
629 * in this case. 633 * in this case.
630 */ 634 */
631 raw_spin_lock(&rnp_root->lock); /* irqs already disabled */ 635 raw_spin_lock(&rnp_root->lock); /* irqs already disabled */
636 smp_mb__after_unlock_lock();
632 if (rnp_root->boost_tasks != NULL && 637 if (rnp_root->boost_tasks != NULL &&
633 rnp_root->boost_tasks != rnp_root->gp_tasks && 638 rnp_root->boost_tasks != rnp_root->gp_tasks &&
634 rnp_root->boost_tasks != rnp_root->exp_tasks) 639 rnp_root->boost_tasks != rnp_root->exp_tasks)
@@ -772,6 +777,7 @@ static void rcu_report_exp_rnp(struct rcu_state *rsp, struct rcu_node *rnp,
772 unsigned long mask; 777 unsigned long mask;
773 778
774 raw_spin_lock_irqsave(&rnp->lock, flags); 779 raw_spin_lock_irqsave(&rnp->lock, flags);
780 smp_mb__after_unlock_lock();
775 for (;;) { 781 for (;;) {
776 if (!sync_rcu_preempt_exp_done(rnp)) { 782 if (!sync_rcu_preempt_exp_done(rnp)) {
777 raw_spin_unlock_irqrestore(&rnp->lock, flags); 783 raw_spin_unlock_irqrestore(&rnp->lock, flags);
@@ -787,6 +793,7 @@ static void rcu_report_exp_rnp(struct rcu_state *rsp, struct rcu_node *rnp,
787 raw_spin_unlock(&rnp->lock); /* irqs remain disabled */ 793 raw_spin_unlock(&rnp->lock); /* irqs remain disabled */
788 rnp = rnp->parent; 794 rnp = rnp->parent;
789 raw_spin_lock(&rnp->lock); /* irqs already disabled */ 795 raw_spin_lock(&rnp->lock); /* irqs already disabled */
796 smp_mb__after_unlock_lock();
790 rnp->expmask &= ~mask; 797 rnp->expmask &= ~mask;
791 } 798 }
792} 799}
@@ -806,6 +813,7 @@ sync_rcu_preempt_exp_init(struct rcu_state *rsp, struct rcu_node *rnp)
806 int must_wait = 0; 813 int must_wait = 0;
807 814
808 raw_spin_lock_irqsave(&rnp->lock, flags); 815 raw_spin_lock_irqsave(&rnp->lock, flags);
816 smp_mb__after_unlock_lock();
809 if (list_empty(&rnp->blkd_tasks)) { 817 if (list_empty(&rnp->blkd_tasks)) {
810 raw_spin_unlock_irqrestore(&rnp->lock, flags); 818 raw_spin_unlock_irqrestore(&rnp->lock, flags);
811 } else { 819 } else {
@@ -886,6 +894,7 @@ void synchronize_rcu_expedited(void)
886 /* Initialize ->expmask for all non-leaf rcu_node structures. */ 894 /* Initialize ->expmask for all non-leaf rcu_node structures. */
887 rcu_for_each_nonleaf_node_breadth_first(rsp, rnp) { 895 rcu_for_each_nonleaf_node_breadth_first(rsp, rnp) {
888 raw_spin_lock_irqsave(&rnp->lock, flags); 896 raw_spin_lock_irqsave(&rnp->lock, flags);
897 smp_mb__after_unlock_lock();
889 rnp->expmask = rnp->qsmaskinit; 898 rnp->expmask = rnp->qsmaskinit;
890 raw_spin_unlock_irqrestore(&rnp->lock, flags); 899 raw_spin_unlock_irqrestore(&rnp->lock, flags);
891 } 900 }
@@ -1191,6 +1200,7 @@ static int rcu_boost(struct rcu_node *rnp)
1191 return 0; /* Nothing left to boost. */ 1200 return 0; /* Nothing left to boost. */
1192 1201
1193 raw_spin_lock_irqsave(&rnp->lock, flags); 1202 raw_spin_lock_irqsave(&rnp->lock, flags);
1203 smp_mb__after_unlock_lock();
1194 1204
1195 /* 1205 /*
1196 * Recheck under the lock: all tasks in need of boosting 1206 * Recheck under the lock: all tasks in need of boosting
@@ -1377,6 +1387,7 @@ static int rcu_spawn_one_boost_kthread(struct rcu_state *rsp,
1377 if (IS_ERR(t)) 1387 if (IS_ERR(t))
1378 return PTR_ERR(t); 1388 return PTR_ERR(t);
1379 raw_spin_lock_irqsave(&rnp->lock, flags); 1389 raw_spin_lock_irqsave(&rnp->lock, flags);
1390 smp_mb__after_unlock_lock();
1380 rnp->boost_kthread_task = t; 1391 rnp->boost_kthread_task = t;
1381 raw_spin_unlock_irqrestore(&rnp->lock, flags); 1392 raw_spin_unlock_irqrestore(&rnp->lock, flags);
1382 sp.sched_priority = RCU_BOOST_PRIO; 1393 sp.sched_priority = RCU_BOOST_PRIO;
@@ -1769,6 +1780,7 @@ static void rcu_prepare_for_idle(int cpu)
1769 continue; 1780 continue;
1770 rnp = rdp->mynode; 1781 rnp = rdp->mynode;
1771 raw_spin_lock(&rnp->lock); /* irqs already disabled. */ 1782 raw_spin_lock(&rnp->lock); /* irqs already disabled. */
1783 smp_mb__after_unlock_lock();
1772 rcu_accelerate_cbs(rsp, rnp, rdp); 1784 rcu_accelerate_cbs(rsp, rnp, rdp);
1773 raw_spin_unlock(&rnp->lock); /* irqs remain disabled. */ 1785 raw_spin_unlock(&rnp->lock); /* irqs remain disabled. */
1774 } 1786 }
@@ -2209,6 +2221,7 @@ static void rcu_nocb_wait_gp(struct rcu_data *rdp)
2209 struct rcu_node *rnp = rdp->mynode; 2221 struct rcu_node *rnp = rdp->mynode;
2210 2222
2211 raw_spin_lock_irqsave(&rnp->lock, flags); 2223 raw_spin_lock_irqsave(&rnp->lock, flags);
2224 smp_mb__after_unlock_lock();
2212 c = rcu_start_future_gp(rnp, rdp); 2225 c = rcu_start_future_gp(rnp, rdp);
2213 raw_spin_unlock_irqrestore(&rnp->lock, flags); 2226 raw_spin_unlock_irqrestore(&rnp->lock, flags);
2214 2227