diff options
author | Paul E. McKenney <paul.mckenney@linaro.org> | 2012-12-30 01:04:18 -0500 |
---|---|---|
committer | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2013-03-26 11:04:55 -0400 |
commit | b8462084a2a88a6a0489f9bb7d8b1bb95bc455ab (patch) | |
tree | c784b3be6b83d2f55cac528c6c877504c27078df | |
parent | bd9f0686fc8c9a01c6850b1c611d1c9ad80b86d6 (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.c | 24 | ||||
-rw-r--r-- | kernel/rcutree_plugin.h | 5 |
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 | */ |
1497 | static void | 1496 | static void |
1498 | rcu_start_gp(struct rcu_state *rsp, unsigned long flags) | 1497 | rcu_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 | */ |
1541 | static void rcu_report_qs_rsp(struct rcu_state *rsp, unsigned long flags) | 1536 | static 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. */ |