aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul E. McKenney <paul.mckenney@linaro.org>2012-12-30 01:04:18 -0500
committerPaul E. McKenney <paulmck@linux.vnet.ibm.com>2013-03-26 11:04:55 -0400
commitb8462084a2a88a6a0489f9bb7d8b1bb95bc455ab (patch)
treec784b3be6b83d2f55cac528c6c877504c27078df
parentbd9f0686fc8c9a01c6850b1c611d1c9ad80b86d6 (diff)
rcu: Push lock release to rcu_start_gp()'s callers
If CPUs are to give prior notice of needed grace periods, it will be necessary to invoke rcu_start_gp() without dropping the root rcu_node structure's ->lock. This commit takes a second step in this direction by moving the release of this lock to rcu_start_gp()'s callers. Signed-off-by: Paul E. McKenney <paul.mckenney@linaro.org> Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
-rw-r--r--kernel/rcutree.c24
-rw-r--r--kernel/rcutree_plugin.h5
2 files changed, 12 insertions, 17 deletions
diff --git a/kernel/rcutree.c b/kernel/rcutree.c
index 2c6a9314c7f7..0d532950baa3 100644
--- a/kernel/rcutree.c
+++ b/kernel/rcutree.c
@@ -1487,16 +1487,14 @@ static int __noreturn rcu_gp_kthread(void *arg)
1487/* 1487/*
1488 * Start a new RCU grace period if warranted, re-initializing the hierarchy 1488 * Start a new RCU grace period if warranted, re-initializing the hierarchy
1489 * in preparation for detecting the next grace period. The caller must hold 1489 * in preparation for detecting the next grace period. The caller must hold
1490 * the root node's ->lock, which is released before return. Hard irqs must 1490 * the root node's ->lock and hard irqs must be disabled.
1491 * be disabled.
1492 * 1491 *
1493 * Note that it is legal for a dying CPU (which is marked as offline) to 1492 * Note that it is legal for a dying CPU (which is marked as offline) to
1494 * invoke this function. This can happen when the dying CPU reports its 1493 * invoke this function. This can happen when the dying CPU reports its
1495 * quiescent state. 1494 * quiescent state.
1496 */ 1495 */
1497static void 1496static void
1498rcu_start_gp(struct rcu_state *rsp, unsigned long flags) 1497rcu_start_gp(struct rcu_state *rsp)
1499 __releases(rcu_get_root(rsp)->lock)
1500{ 1498{
1501 struct rcu_data *rdp = this_cpu_ptr(rsp->rda); 1499 struct rcu_data *rdp = this_cpu_ptr(rsp->rda);
1502 struct rcu_node *rnp = rcu_get_root(rsp); 1500 struct rcu_node *rnp = rcu_get_root(rsp);
@@ -1510,15 +1508,13 @@ rcu_start_gp(struct rcu_state *rsp, unsigned long flags)
1510 */ 1508 */
1511 rcu_advance_cbs(rsp, rnp, rdp); 1509 rcu_advance_cbs(rsp, rnp, rdp);
1512 1510
1513 if (!rsp->gp_kthread || 1511 if (!rsp->gp_kthread || !cpu_needs_another_gp(rsp, rdp)) {
1514 !cpu_needs_another_gp(rsp, rdp)) {
1515 /* 1512 /*
1516 * Either we have not yet spawned the grace-period 1513 * Either we have not yet spawned the grace-period
1517 * task, this CPU does not need another grace period, 1514 * task, this CPU does not need another grace period,
1518 * or a grace period is already in progress. 1515 * or a grace period is already in progress.
1519 * Either way, don't start a new grace period. 1516 * Either way, don't start a new grace period.
1520 */ 1517 */
1521 raw_spin_unlock_irqrestore(&rnp->lock, flags);
1522 return; 1518 return;
1523 } 1519 }
1524 rsp->gp_flags = RCU_GP_FLAG_INIT; 1520 rsp->gp_flags = RCU_GP_FLAG_INIT;
@@ -1528,15 +1524,14 @@ rcu_start_gp(struct rcu_state *rsp, unsigned long flags)
1528 1524
1529 /* Wake up rcu_gp_kthread() to start the grace period. */ 1525 /* Wake up rcu_gp_kthread() to start the grace period. */
1530 wake_up(&rsp->gp_wq); 1526 wake_up(&rsp->gp_wq);
1531 raw_spin_unlock_irqrestore(&rnp->lock, flags);
1532} 1527}
1533 1528
1534/* 1529/*
1535 * Report a full set of quiescent states to the specified rcu_state 1530 * Report a full set of quiescent states to the specified rcu_state
1536 * data structure. This involves cleaning up after the prior grace 1531 * data structure. This involves cleaning up after the prior grace
1537 * period and letting rcu_start_gp() start up the next grace period 1532 * period and letting rcu_start_gp() start up the next grace period
1538 * if one is needed. Note that the caller must hold rnp->lock, as 1533 * if one is needed. Note that the caller must hold rnp->lock, which
1539 * required by rcu_start_gp(), which will release it. 1534 * is released before return.
1540 */ 1535 */
1541static void rcu_report_qs_rsp(struct rcu_state *rsp, unsigned long flags) 1536static void rcu_report_qs_rsp(struct rcu_state *rsp, unsigned long flags)
1542 __releases(rcu_get_root(rsp)->lock) 1537 __releases(rcu_get_root(rsp)->lock)
@@ -2134,7 +2129,8 @@ __rcu_process_callbacks(struct rcu_state *rsp)
2134 local_irq_save(flags); 2129 local_irq_save(flags);
2135 if (cpu_needs_another_gp(rsp, rdp)) { 2130 if (cpu_needs_another_gp(rsp, rdp)) {
2136 raw_spin_lock(&rcu_get_root(rsp)->lock); /* irqs disabled. */ 2131 raw_spin_lock(&rcu_get_root(rsp)->lock); /* irqs disabled. */
2137 rcu_start_gp(rsp, flags); /* releases above lock */ 2132 rcu_start_gp(rsp);
2133 raw_spin_unlock_irqrestore(&rcu_get_root(rsp)->lock, flags);
2138 } else { 2134 } else {
2139 local_irq_restore(flags); 2135 local_irq_restore(flags);
2140 } 2136 }
@@ -2214,11 +2210,11 @@ static void __call_rcu_core(struct rcu_state *rsp, struct rcu_data *rdp,
2214 2210
2215 /* Start a new grace period if one not already started. */ 2211 /* Start a new grace period if one not already started. */
2216 if (!rcu_gp_in_progress(rsp)) { 2212 if (!rcu_gp_in_progress(rsp)) {
2217 unsigned long nestflag;
2218 struct rcu_node *rnp_root = rcu_get_root(rsp); 2213 struct rcu_node *rnp_root = rcu_get_root(rsp);
2219 2214
2220 raw_spin_lock_irqsave(&rnp_root->lock, nestflag); 2215 raw_spin_lock(&rnp_root->lock);
2221 rcu_start_gp(rsp, nestflag); /* rlses rnp_root->lock */ 2216 rcu_start_gp(rsp);
2217 raw_spin_unlock(&rnp_root->lock);
2222 } else { 2218 } else {
2223 /* Give the grace period a kick. */ 2219 /* Give the grace period a kick. */
2224 rdp->blimit = LONG_MAX; 2220 rdp->blimit = LONG_MAX;
diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h
index df50502eca2c..073ded26e259 100644
--- a/kernel/rcutree_plugin.h
+++ b/kernel/rcutree_plugin.h
@@ -2174,7 +2174,6 @@ static void rcu_nocb_wait_gp(struct rcu_data *rdp)
2174 unsigned long c; 2174 unsigned long c;
2175 bool d; 2175 bool d;
2176 unsigned long flags; 2176 unsigned long flags;
2177 unsigned long flags1;
2178 struct rcu_node *rnp = rdp->mynode; 2177 struct rcu_node *rnp = rdp->mynode;
2179 struct rcu_node *rnp_root = rcu_get_root(rdp->rsp); 2178 struct rcu_node *rnp_root = rcu_get_root(rdp->rsp);
2180 2179
@@ -2236,8 +2235,8 @@ static void rcu_nocb_wait_gp(struct rcu_data *rdp)
2236 c, rnp->level, 2235 c, rnp->level,
2237 rnp->grplo, rnp->grphi, 2236 rnp->grplo, rnp->grphi,
2238 "Startedroot"); 2237 "Startedroot");
2239 local_save_flags(flags1); 2238 rcu_start_gp(rdp->rsp);
2240 rcu_start_gp(rdp->rsp, flags1); /* Rlses ->lock. */ 2239 raw_spin_unlock(&rnp->lock);
2241 } 2240 }
2242 2241
2243 /* Clean up locking and irq state. */ 2242 /* Clean up locking and irq state. */