aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/rcutree.c
diff options
context:
space:
mode:
authorPaul E. McKenney <paul.mckenney@linaro.org>2012-01-06 17:11:30 -0500
committerPaul E. McKenney <paulmck@linux.vnet.ibm.com>2012-02-21 12:03:25 -0500
commit486e259340fc4c60474f2c14703e3b3634bb58ca (patch)
tree70a58702194588fa0773463523f72c682785d040 /kernel/rcutree.c
parent0bb7b59d6e2b8440cd7097097dd4bbfc4d76ed07 (diff)
rcu: Avoid waking up CPUs having only kfree_rcu() callbacks
When CONFIG_RCU_FAST_NO_HZ is enabled, RCU will allow a given CPU to enter dyntick-idle mode even if it still has RCU callbacks queued. RCU avoids system hangs in this case by scheduling a timer for several jiffies in the future. However, if all of the callbacks on that CPU are from kfree_rcu(), there is no reason to wake the CPU up, as it is not a problem to defer freeing of memory. This commit therefore tracks the number of callbacks on a given CPU that are from kfree_rcu(), and avoids scheduling the timer if all of a given CPU's callbacks are from kfree_rcu(). 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/rcutree.c')
-rw-r--r--kernel/rcutree.c29
1 files changed, 18 insertions, 11 deletions
diff --git a/kernel/rcutree.c b/kernel/rcutree.c
index 570f7530f4b3..acf2d67ad2f4 100644
--- a/kernel/rcutree.c
+++ b/kernel/rcutree.c
@@ -1261,6 +1261,7 @@ static void rcu_send_cbs_to_online(struct rcu_state *rsp)
1261 1261
1262 *receive_rdp->nxttail[RCU_NEXT_TAIL] = rdp->nxtlist; 1262 *receive_rdp->nxttail[RCU_NEXT_TAIL] = rdp->nxtlist;
1263 receive_rdp->nxttail[RCU_NEXT_TAIL] = rdp->nxttail[RCU_NEXT_TAIL]; 1263 receive_rdp->nxttail[RCU_NEXT_TAIL] = rdp->nxttail[RCU_NEXT_TAIL];
1264 receive_rdp->qlen_lazy += rdp->qlen_lazy;
1264 receive_rdp->qlen += rdp->qlen; 1265 receive_rdp->qlen += rdp->qlen;
1265 receive_rdp->n_cbs_adopted += rdp->qlen; 1266 receive_rdp->n_cbs_adopted += rdp->qlen;
1266 rdp->n_cbs_orphaned += rdp->qlen; 1267 rdp->n_cbs_orphaned += rdp->qlen;
@@ -1268,6 +1269,7 @@ static void rcu_send_cbs_to_online(struct rcu_state *rsp)
1268 rdp->nxtlist = NULL; 1269 rdp->nxtlist = NULL;
1269 for (i = 0; i < RCU_NEXT_SIZE; i++) 1270 for (i = 0; i < RCU_NEXT_SIZE; i++)
1270 rdp->nxttail[i] = &rdp->nxtlist; 1271 rdp->nxttail[i] = &rdp->nxtlist;
1272 rdp->qlen_lazy = 0;
1271 rdp->qlen = 0; 1273 rdp->qlen = 0;
1272} 1274}
1273 1275
@@ -1368,11 +1370,11 @@ static void rcu_do_batch(struct rcu_state *rsp, struct rcu_data *rdp)
1368{ 1370{
1369 unsigned long flags; 1371 unsigned long flags;
1370 struct rcu_head *next, *list, **tail; 1372 struct rcu_head *next, *list, **tail;
1371 int bl, count; 1373 int bl, count, count_lazy;
1372 1374
1373 /* If no callbacks are ready, just return.*/ 1375 /* If no callbacks are ready, just return.*/
1374 if (!cpu_has_callbacks_ready_to_invoke(rdp)) { 1376 if (!cpu_has_callbacks_ready_to_invoke(rdp)) {
1375 trace_rcu_batch_start(rsp->name, 0, 0); 1377 trace_rcu_batch_start(rsp->name, rdp->qlen_lazy, rdp->qlen, 0);
1376 trace_rcu_batch_end(rsp->name, 0, !!ACCESS_ONCE(rdp->nxtlist), 1378 trace_rcu_batch_end(rsp->name, 0, !!ACCESS_ONCE(rdp->nxtlist),
1377 need_resched(), is_idle_task(current), 1379 need_resched(), is_idle_task(current),
1378 rcu_is_callbacks_kthread()); 1380 rcu_is_callbacks_kthread());
@@ -1385,7 +1387,7 @@ static void rcu_do_batch(struct rcu_state *rsp, struct rcu_data *rdp)
1385 */ 1387 */
1386 local_irq_save(flags); 1388 local_irq_save(flags);
1387 bl = rdp->blimit; 1389 bl = rdp->blimit;
1388 trace_rcu_batch_start(rsp->name, rdp->qlen, bl); 1390 trace_rcu_batch_start(rsp->name, rdp->qlen_lazy, rdp->qlen, bl);
1389 list = rdp->nxtlist; 1391 list = rdp->nxtlist;
1390 rdp->nxtlist = *rdp->nxttail[RCU_DONE_TAIL]; 1392 rdp->nxtlist = *rdp->nxttail[RCU_DONE_TAIL];
1391 *rdp->nxttail[RCU_DONE_TAIL] = NULL; 1393 *rdp->nxttail[RCU_DONE_TAIL] = NULL;
@@ -1396,12 +1398,13 @@ static void rcu_do_batch(struct rcu_state *rsp, struct rcu_data *rdp)
1396 local_irq_restore(flags); 1398 local_irq_restore(flags);
1397 1399
1398 /* Invoke callbacks. */ 1400 /* Invoke callbacks. */
1399 count = 0; 1401 count = count_lazy = 0;
1400 while (list) { 1402 while (list) {
1401 next = list->next; 1403 next = list->next;
1402 prefetch(next); 1404 prefetch(next);
1403 debug_rcu_head_unqueue(list); 1405 debug_rcu_head_unqueue(list);
1404 __rcu_reclaim(rsp->name, list); 1406 if (__rcu_reclaim(rsp->name, list))
1407 count_lazy++;
1405 list = next; 1408 list = next;
1406 /* Stop only if limit reached and CPU has something to do. */ 1409 /* Stop only if limit reached and CPU has something to do. */
1407 if (++count >= bl && 1410 if (++count >= bl &&
@@ -1416,6 +1419,7 @@ static void rcu_do_batch(struct rcu_state *rsp, struct rcu_data *rdp)
1416 rcu_is_callbacks_kthread()); 1419 rcu_is_callbacks_kthread());
1417 1420
1418 /* Update count, and requeue any remaining callbacks. */ 1421 /* Update count, and requeue any remaining callbacks. */
1422 rdp->qlen_lazy -= count_lazy;
1419 rdp->qlen -= count; 1423 rdp->qlen -= count;
1420 rdp->n_cbs_invoked += count; 1424 rdp->n_cbs_invoked += count;
1421 if (list != NULL) { 1425 if (list != NULL) {
@@ -1702,7 +1706,7 @@ static void invoke_rcu_core(void)
1702 1706
1703static void 1707static void
1704__call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu), 1708__call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu),
1705 struct rcu_state *rsp) 1709 struct rcu_state *rsp, bool lazy)
1706{ 1710{
1707 unsigned long flags; 1711 unsigned long flags;
1708 struct rcu_data *rdp; 1712 struct rcu_data *rdp;
@@ -1727,12 +1731,14 @@ __call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu),
1727 *rdp->nxttail[RCU_NEXT_TAIL] = head; 1731 *rdp->nxttail[RCU_NEXT_TAIL] = head;
1728 rdp->nxttail[RCU_NEXT_TAIL] = &head->next; 1732 rdp->nxttail[RCU_NEXT_TAIL] = &head->next;
1729 rdp->qlen++; 1733 rdp->qlen++;
1734 if (lazy)
1735 rdp->qlen_lazy++;
1730 1736
1731 if (__is_kfree_rcu_offset((unsigned long)func)) 1737 if (__is_kfree_rcu_offset((unsigned long)func))
1732 trace_rcu_kfree_callback(rsp->name, head, (unsigned long)func, 1738 trace_rcu_kfree_callback(rsp->name, head, (unsigned long)func,
1733 rdp->qlen); 1739 rdp->qlen_lazy, rdp->qlen);
1734 else 1740 else
1735 trace_rcu_callback(rsp->name, head, rdp->qlen); 1741 trace_rcu_callback(rsp->name, head, rdp->qlen_lazy, rdp->qlen);
1736 1742
1737 /* If interrupts were disabled, don't dive into RCU core. */ 1743 /* If interrupts were disabled, don't dive into RCU core. */
1738 if (irqs_disabled_flags(flags)) { 1744 if (irqs_disabled_flags(flags)) {
@@ -1779,16 +1785,16 @@ __call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu),
1779 */ 1785 */
1780void call_rcu_sched(struct rcu_head *head, void (*func)(struct rcu_head *rcu)) 1786void call_rcu_sched(struct rcu_head *head, void (*func)(struct rcu_head *rcu))
1781{ 1787{
1782 __call_rcu(head, func, &rcu_sched_state); 1788 __call_rcu(head, func, &rcu_sched_state, 0);
1783} 1789}
1784EXPORT_SYMBOL_GPL(call_rcu_sched); 1790EXPORT_SYMBOL_GPL(call_rcu_sched);
1785 1791
1786/* 1792/*
1787 * Queue an RCU for invocation after a quicker grace period. 1793 * Queue an RCU callback for invocation after a quicker grace period.
1788 */ 1794 */
1789void call_rcu_bh(struct rcu_head *head, void (*func)(struct rcu_head *rcu)) 1795void call_rcu_bh(struct rcu_head *head, void (*func)(struct rcu_head *rcu))
1790{ 1796{
1791 __call_rcu(head, func, &rcu_bh_state); 1797 __call_rcu(head, func, &rcu_bh_state, 0);
1792} 1798}
1793EXPORT_SYMBOL_GPL(call_rcu_bh); 1799EXPORT_SYMBOL_GPL(call_rcu_bh);
1794 1800
@@ -2036,6 +2042,7 @@ rcu_boot_init_percpu_data(int cpu, struct rcu_state *rsp)
2036 rdp->nxtlist = NULL; 2042 rdp->nxtlist = NULL;
2037 for (i = 0; i < RCU_NEXT_SIZE; i++) 2043 for (i = 0; i < RCU_NEXT_SIZE; i++)
2038 rdp->nxttail[i] = &rdp->nxtlist; 2044 rdp->nxttail[i] = &rdp->nxtlist;
2045 rdp->qlen_lazy = 0;
2039 rdp->qlen = 0; 2046 rdp->qlen = 0;
2040 rdp->dynticks = &per_cpu(rcu_dynticks, cpu); 2047 rdp->dynticks = &per_cpu(rcu_dynticks, cpu);
2041 WARN_ON_ONCE(rdp->dynticks->dynticks_nesting != DYNTICK_TASK_NESTING); 2048 WARN_ON_ONCE(rdp->dynticks->dynticks_nesting != DYNTICK_TASK_NESTING);