aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/rcutree.c
diff options
context:
space:
mode:
authorPaul E. McKenney <paulmck@linux.vnet.ibm.com>2009-10-07 00:48:16 -0400
committerIngo Molnar <mingo@elte.hu>2009-10-07 02:11:20 -0400
commitd0ec774cb2599c858be9d923bb873cf6697520d8 (patch)
tree0897fd843622033a6db6ab43167e47c3236aa22d /kernel/rcutree.c
parent322a2c100a8998158445599ea437fb556aa95b11 (diff)
rcu: Move rcu_barrier() to rcutree
Move the existing rcu_barrier() implementation to rcutree.c, consistent with the fact that the rcu_barrier() implementation is tied quite tightly to the RCU implementation. This opens the way to simplify and fix rcutree.c's rcu_barrier() implementation in a later patch. Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Cc: laijs@cn.fujitsu.com Cc: dipankar@in.ibm.com Cc: akpm@linux-foundation.org Cc: mathieu.desnoyers@polymtl.ca Cc: josh@joshtriplett.org Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org Cc: Valdis.Kletnieks@vt.edu Cc: dhowells@redhat.com LKML-Reference: <12548908982563-git-send-email-> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/rcutree.c')
-rw-r--r--kernel/rcutree.c119
1 files changed, 119 insertions, 0 deletions
diff --git a/kernel/rcutree.c b/kernel/rcutree.c
index e2e272b5c277..0108570a192c 100644
--- a/kernel/rcutree.c
+++ b/kernel/rcutree.c
@@ -1363,6 +1363,103 @@ int rcu_needs_cpu(int cpu)
1363 rcu_preempt_needs_cpu(cpu); 1363 rcu_preempt_needs_cpu(cpu);
1364} 1364}
1365 1365
1366static DEFINE_PER_CPU(struct rcu_head, rcu_barrier_head) = {NULL};
1367static atomic_t rcu_barrier_cpu_count;
1368static DEFINE_MUTEX(rcu_barrier_mutex);
1369static struct completion rcu_barrier_completion;
1370static atomic_t rcu_migrate_type_count = ATOMIC_INIT(0);
1371static struct rcu_head rcu_migrate_head[3];
1372static DECLARE_WAIT_QUEUE_HEAD(rcu_migrate_wq);
1373
1374static void rcu_barrier_callback(struct rcu_head *notused)
1375{
1376 if (atomic_dec_and_test(&rcu_barrier_cpu_count))
1377 complete(&rcu_barrier_completion);
1378}
1379
1380/*
1381 * Called with preemption disabled, and from cross-cpu IRQ context.
1382 */
1383static void rcu_barrier_func(void *type)
1384{
1385 int cpu = smp_processor_id();
1386 struct rcu_head *head = &per_cpu(rcu_barrier_head, cpu);
1387 void (*call_rcu_func)(struct rcu_head *head,
1388 void (*func)(struct rcu_head *head));
1389
1390 atomic_inc(&rcu_barrier_cpu_count);
1391 call_rcu_func = type;
1392 call_rcu_func(head, rcu_barrier_callback);
1393}
1394
1395static inline void wait_migrated_callbacks(void)
1396{
1397 wait_event(rcu_migrate_wq, !atomic_read(&rcu_migrate_type_count));
1398 smp_mb(); /* In case we didn't sleep. */
1399}
1400
1401/*
1402 * Orchestrate the specified type of RCU barrier, waiting for all
1403 * RCU callbacks of the specified type to complete.
1404 */
1405static void _rcu_barrier(void (*call_rcu_func)(struct rcu_head *head,
1406 void (*func)(struct rcu_head *head)))
1407{
1408 BUG_ON(in_interrupt());
1409 /* Take cpucontrol mutex to protect against CPU hotplug */
1410 mutex_lock(&rcu_barrier_mutex);
1411 init_completion(&rcu_barrier_completion);
1412 /*
1413 * Initialize rcu_barrier_cpu_count to 1, then invoke
1414 * rcu_barrier_func() on each CPU, so that each CPU also has
1415 * incremented rcu_barrier_cpu_count. Only then is it safe to
1416 * decrement rcu_barrier_cpu_count -- otherwise the first CPU
1417 * might complete its grace period before all of the other CPUs
1418 * did their increment, causing this function to return too
1419 * early.
1420 */
1421 atomic_set(&rcu_barrier_cpu_count, 1);
1422 on_each_cpu(rcu_barrier_func, (void *)call_rcu_func, 1);
1423 if (atomic_dec_and_test(&rcu_barrier_cpu_count))
1424 complete(&rcu_barrier_completion);
1425 wait_for_completion(&rcu_barrier_completion);
1426 mutex_unlock(&rcu_barrier_mutex);
1427 wait_migrated_callbacks();
1428}
1429
1430/**
1431 * rcu_barrier - Wait until all in-flight call_rcu() callbacks complete.
1432 */
1433void rcu_barrier(void)
1434{
1435 _rcu_barrier(call_rcu);
1436}
1437EXPORT_SYMBOL_GPL(rcu_barrier);
1438
1439/**
1440 * rcu_barrier_bh - Wait until all in-flight call_rcu_bh() callbacks complete.
1441 */
1442void rcu_barrier_bh(void)
1443{
1444 _rcu_barrier(call_rcu_bh);
1445}
1446EXPORT_SYMBOL_GPL(rcu_barrier_bh);
1447
1448/**
1449 * rcu_barrier_sched - Wait for in-flight call_rcu_sched() callbacks.
1450 */
1451void rcu_barrier_sched(void)
1452{
1453 _rcu_barrier(call_rcu_sched);
1454}
1455EXPORT_SYMBOL_GPL(rcu_barrier_sched);
1456
1457static void rcu_migrate_callback(struct rcu_head *notused)
1458{
1459 if (atomic_dec_and_test(&rcu_migrate_type_count))
1460 wake_up(&rcu_migrate_wq);
1461}
1462
1366/* 1463/*
1367 * Do boot-time initialization of a CPU's per-CPU RCU data. 1464 * Do boot-time initialization of a CPU's per-CPU RCU data.
1368 */ 1465 */
@@ -1459,6 +1556,28 @@ int __cpuinit rcu_cpu_notify(struct notifier_block *self,
1459 case CPU_UP_PREPARE_FROZEN: 1556 case CPU_UP_PREPARE_FROZEN:
1460 rcu_online_cpu(cpu); 1557 rcu_online_cpu(cpu);
1461 break; 1558 break;
1559 case CPU_DOWN_PREPARE:
1560 case CPU_DOWN_PREPARE_FROZEN:
1561 /* Don't need to wait until next removal operation. */
1562 /* rcu_migrate_head is protected by cpu_add_remove_lock */
1563 wait_migrated_callbacks();
1564 break;
1565 case CPU_DYING:
1566 case CPU_DYING_FROZEN:
1567 /*
1568 * preempt_disable() in on_each_cpu() prevents stop_machine(),
1569 * so when "on_each_cpu(rcu_barrier_func, (void *)type, 1);"
1570 * returns, all online cpus have queued rcu_barrier_func(),
1571 * and the dead cpu(if it exist) queues rcu_migrate_callback()s.
1572 *
1573 * These callbacks ensure _rcu_barrier() waits for all
1574 * RCU callbacks of the specified type to complete.
1575 */
1576 atomic_set(&rcu_migrate_type_count, 3);
1577 call_rcu_bh(rcu_migrate_head, rcu_migrate_callback);
1578 call_rcu_sched(rcu_migrate_head + 1, rcu_migrate_callback);
1579 call_rcu(rcu_migrate_head + 2, rcu_migrate_callback);
1580 break;
1462 case CPU_DEAD: 1581 case CPU_DEAD:
1463 case CPU_DEAD_FROZEN: 1582 case CPU_DEAD_FROZEN:
1464 case CPU_UP_CANCELED: 1583 case CPU_UP_CANCELED: