diff options
author | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2009-10-07 00:48:16 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-10-07 02:11:20 -0400 |
commit | d0ec774cb2599c858be9d923bb873cf6697520d8 (patch) | |
tree | 0897fd843622033a6db6ab43167e47c3236aa22d /kernel/rcutree.c | |
parent | 322a2c100a8998158445599ea437fb556aa95b11 (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.c | 119 |
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 | ||
1366 | static DEFINE_PER_CPU(struct rcu_head, rcu_barrier_head) = {NULL}; | ||
1367 | static atomic_t rcu_barrier_cpu_count; | ||
1368 | static DEFINE_MUTEX(rcu_barrier_mutex); | ||
1369 | static struct completion rcu_barrier_completion; | ||
1370 | static atomic_t rcu_migrate_type_count = ATOMIC_INIT(0); | ||
1371 | static struct rcu_head rcu_migrate_head[3]; | ||
1372 | static DECLARE_WAIT_QUEUE_HEAD(rcu_migrate_wq); | ||
1373 | |||
1374 | static 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 | */ | ||
1383 | static 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 | |||
1395 | static 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 | */ | ||
1405 | static 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 | */ | ||
1433 | void rcu_barrier(void) | ||
1434 | { | ||
1435 | _rcu_barrier(call_rcu); | ||
1436 | } | ||
1437 | EXPORT_SYMBOL_GPL(rcu_barrier); | ||
1438 | |||
1439 | /** | ||
1440 | * rcu_barrier_bh - Wait until all in-flight call_rcu_bh() callbacks complete. | ||
1441 | */ | ||
1442 | void rcu_barrier_bh(void) | ||
1443 | { | ||
1444 | _rcu_barrier(call_rcu_bh); | ||
1445 | } | ||
1446 | EXPORT_SYMBOL_GPL(rcu_barrier_bh); | ||
1447 | |||
1448 | /** | ||
1449 | * rcu_barrier_sched - Wait for in-flight call_rcu_sched() callbacks. | ||
1450 | */ | ||
1451 | void rcu_barrier_sched(void) | ||
1452 | { | ||
1453 | _rcu_barrier(call_rcu_sched); | ||
1454 | } | ||
1455 | EXPORT_SYMBOL_GPL(rcu_barrier_sched); | ||
1456 | |||
1457 | static 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: |