aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/rcutree.c
diff options
context:
space:
mode:
authorPaul E. McKenney <paulmck@linux.vnet.ibm.com>2010-12-14 20:36:02 -0500
committerPaul E. McKenney <paulmck@linux.vnet.ibm.com>2010-12-17 15:34:49 -0500
commitb52573d2796274f7f31cfeff7185c320adcd4f12 (patch)
tree61580632fa8fbf80225ba7339274ada0c013a01b /kernel/rcutree.c
parent0209f6490b030f35349a2bb71294f3fd75b0f36d (diff)
rcu: reduce __call_rcu()-induced contention on rcu_node structures
When the current __call_rcu() function was written, the expedited APIs did not exist. The __call_rcu() implementation therefore went to great lengths to detect the end of old grace periods and to start new ones, all in the name of reducing grace-period latency. Now the expedited APIs do exist, and the usage of __call_rcu() has increased considerably. This commit therefore causes __call_rcu() to avoid worrying about grace periods unless there are a large number of RCU callbacks stacked up on the current CPU. Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Diffstat (limited to 'kernel/rcutree.c')
-rw-r--r--kernel/rcutree.c38
1 files changed, 21 insertions, 17 deletions
diff --git a/kernel/rcutree.c b/kernel/rcutree.c
index 01c8ad33c510..d0ddfea6579d 100644
--- a/kernel/rcutree.c
+++ b/kernel/rcutree.c
@@ -1435,22 +1435,11 @@ __call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu),
1435 */ 1435 */
1436 local_irq_save(flags); 1436 local_irq_save(flags);
1437 rdp = this_cpu_ptr(rsp->rda); 1437 rdp = this_cpu_ptr(rsp->rda);
1438 rcu_process_gp_end(rsp, rdp);
1439 check_for_new_grace_period(rsp, rdp);
1440 1438
1441 /* Add the callback to our list. */ 1439 /* Add the callback to our list. */
1442 *rdp->nxttail[RCU_NEXT_TAIL] = head; 1440 *rdp->nxttail[RCU_NEXT_TAIL] = head;
1443 rdp->nxttail[RCU_NEXT_TAIL] = &head->next; 1441 rdp->nxttail[RCU_NEXT_TAIL] = &head->next;
1444 1442
1445 /* Start a new grace period if one not already started. */
1446 if (!rcu_gp_in_progress(rsp)) {
1447 unsigned long nestflag;
1448 struct rcu_node *rnp_root = rcu_get_root(rsp);
1449
1450 raw_spin_lock_irqsave(&rnp_root->lock, nestflag);
1451 rcu_start_gp(rsp, nestflag); /* releases rnp_root->lock. */
1452 }
1453
1454 /* 1443 /*
1455 * Force the grace period if too many callbacks or too long waiting. 1444 * Force the grace period if too many callbacks or too long waiting.
1456 * Enforce hysteresis, and don't invoke force_quiescent_state() 1445 * Enforce hysteresis, and don't invoke force_quiescent_state()
@@ -1459,12 +1448,27 @@ __call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu),
1459 * is the only one waiting for a grace period to complete. 1448 * is the only one waiting for a grace period to complete.
1460 */ 1449 */
1461 if (unlikely(++rdp->qlen > rdp->qlen_last_fqs_check + qhimark)) { 1450 if (unlikely(++rdp->qlen > rdp->qlen_last_fqs_check + qhimark)) {
1462 rdp->blimit = LONG_MAX; 1451
1463 if (rsp->n_force_qs == rdp->n_force_qs_snap && 1452 /* Are we ignoring a completed grace period? */
1464 *rdp->nxttail[RCU_DONE_TAIL] != head) 1453 rcu_process_gp_end(rsp, rdp);
1465 force_quiescent_state(rsp, 0); 1454 check_for_new_grace_period(rsp, rdp);
1466 rdp->n_force_qs_snap = rsp->n_force_qs; 1455
1467 rdp->qlen_last_fqs_check = rdp->qlen; 1456 /* Start a new grace period if one not already started. */
1457 if (!rcu_gp_in_progress(rsp)) {
1458 unsigned long nestflag;
1459 struct rcu_node *rnp_root = rcu_get_root(rsp);
1460
1461 raw_spin_lock_irqsave(&rnp_root->lock, nestflag);
1462 rcu_start_gp(rsp, nestflag); /* rlses rnp_root->lock */
1463 } else {
1464 /* Give the grace period a kick. */
1465 rdp->blimit = LONG_MAX;
1466 if (rsp->n_force_qs == rdp->n_force_qs_snap &&
1467 *rdp->nxttail[RCU_DONE_TAIL] != head)
1468 force_quiescent_state(rsp, 0);
1469 rdp->n_force_qs_snap = rsp->n_force_qs;
1470 rdp->qlen_last_fqs_check = rdp->qlen;
1471 }
1468 } else if (ULONG_CMP_LT(ACCESS_ONCE(rsp->jiffies_force_qs), jiffies)) 1472 } else if (ULONG_CMP_LT(ACCESS_ONCE(rsp->jiffies_force_qs), jiffies))
1469 force_quiescent_state(rsp, 1); 1473 force_quiescent_state(rsp, 1);
1470 local_irq_restore(flags); 1474 local_irq_restore(flags);