diff options
author | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2009-08-15 12:53:46 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-08-15 13:02:07 -0400 |
commit | 27569620c748ec13f801b4683b448a2ac2adaae4 (patch) | |
tree | d5fd5dd1b9d352ca0ef2cf224f7141338d3413f3 | |
parent | fa08661af834875c9bd6f7f0b1b9388dc72a6585 (diff) |
rcu: Split hierarchical RCU initialization into boot-time and CPU-online pieces
This patch divides the rcutree initialization into boot-time
and hotplug-time components, so that the tree data structures
are guaranteed to be fully linked at boot time regardless of
what might happen in CPU hotplug operations.
This makes RCU more resilient against CPU hotplug misbehavior
(and vice versa), but more importantly, does a better job of
compartmentalizing the code.
Reported-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: laijs@cn.fujitsu.com
Cc: dipankar@in.ibm.com
Cc: josht@linux.vnet.ibm.com
Cc: akpm@linux-foundation.org
Cc: mathieu.desnoyers@polymtl.ca
Cc: dvhltc@us.ibm.com
Cc: niv@us.ibm.com
Cc: peterz@infradead.org
Cc: rostedt@goodmis.org
Cc: hugh.dickins@tiscali.co.uk
Cc: benh@kernel.crashing.org
LKML-Reference: <1250355231152-git-send-email->
Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r-- | kernel/rcutree.c | 53 |
1 files changed, 33 insertions, 20 deletions
diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 7717b95c2027..f3e43274ed53 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c | |||
@@ -1325,22 +1325,40 @@ int rcu_needs_cpu(int cpu) | |||
1325 | } | 1325 | } |
1326 | 1326 | ||
1327 | /* | 1327 | /* |
1328 | * Initialize a CPU's per-CPU RCU data. We take this "scorched earth" | 1328 | * Do boot-time initialization of a CPU's per-CPU RCU data. |
1329 | * approach so that we don't have to worry about how long the CPU has | 1329 | */ |
1330 | * been gone, or whether it ever was online previously. We do trust the | 1330 | static void __init |
1331 | * ->mynode field, as it is constant for a given struct rcu_data and | 1331 | rcu_boot_init_percpu_data(int cpu, struct rcu_state *rsp) |
1332 | * initialized during early boot. | 1332 | { |
1333 | * | 1333 | unsigned long flags; |
1334 | * Note that only one online or offline event can be happening at a given | 1334 | int i; |
1335 | * time. Note also that we can accept some slop in the rsp->completed | 1335 | struct rcu_data *rdp = rsp->rda[cpu]; |
1336 | * access due to the fact that this CPU cannot possibly have any RCU | 1336 | struct rcu_node *rnp = rcu_get_root(rsp); |
1337 | * callbacks in flight yet. | 1337 | |
1338 | /* Set up local state, ensuring consistent view of global state. */ | ||
1339 | spin_lock_irqsave(&rnp->lock, flags); | ||
1340 | rdp->grpmask = 1UL << (cpu - rdp->mynode->grplo); | ||
1341 | rdp->nxtlist = NULL; | ||
1342 | for (i = 0; i < RCU_NEXT_SIZE; i++) | ||
1343 | rdp->nxttail[i] = &rdp->nxtlist; | ||
1344 | rdp->qlen = 0; | ||
1345 | #ifdef CONFIG_NO_HZ | ||
1346 | rdp->dynticks = &per_cpu(rcu_dynticks, cpu); | ||
1347 | #endif /* #ifdef CONFIG_NO_HZ */ | ||
1348 | rdp->cpu = cpu; | ||
1349 | spin_unlock_irqrestore(&rnp->lock, flags); | ||
1350 | } | ||
1351 | |||
1352 | /* | ||
1353 | * Initialize a CPU's per-CPU RCU data. Note that only one online or | ||
1354 | * offline event can be happening at a given time. Note also that we | ||
1355 | * can accept some slop in the rsp->completed access due to the fact | ||
1356 | * that this CPU cannot possibly have any RCU callbacks in flight yet. | ||
1338 | */ | 1357 | */ |
1339 | static void __cpuinit | 1358 | static void __cpuinit |
1340 | rcu_init_percpu_data(int cpu, struct rcu_state *rsp) | 1359 | rcu_init_percpu_data(int cpu, struct rcu_state *rsp) |
1341 | { | 1360 | { |
1342 | unsigned long flags; | 1361 | unsigned long flags; |
1343 | int i; | ||
1344 | long lastcomp; | 1362 | long lastcomp; |
1345 | unsigned long mask; | 1363 | unsigned long mask; |
1346 | struct rcu_data *rdp = rsp->rda[cpu]; | 1364 | struct rcu_data *rdp = rsp->rda[cpu]; |
@@ -1355,16 +1373,7 @@ rcu_init_percpu_data(int cpu, struct rcu_state *rsp) | |||
1355 | rdp->qs_pending = 1; /* so set up to respond to current GP. */ | 1373 | rdp->qs_pending = 1; /* so set up to respond to current GP. */ |
1356 | rdp->beenonline = 1; /* We have now been online. */ | 1374 | rdp->beenonline = 1; /* We have now been online. */ |
1357 | rdp->passed_quiesc_completed = lastcomp - 1; | 1375 | rdp->passed_quiesc_completed = lastcomp - 1; |
1358 | rdp->grpmask = 1UL << (cpu - rdp->mynode->grplo); | ||
1359 | rdp->nxtlist = NULL; | ||
1360 | for (i = 0; i < RCU_NEXT_SIZE; i++) | ||
1361 | rdp->nxttail[i] = &rdp->nxtlist; | ||
1362 | rdp->qlen = 0; | ||
1363 | rdp->blimit = blimit; | 1376 | rdp->blimit = blimit; |
1364 | #ifdef CONFIG_NO_HZ | ||
1365 | rdp->dynticks = &per_cpu(rcu_dynticks, cpu); | ||
1366 | #endif /* #ifdef CONFIG_NO_HZ */ | ||
1367 | rdp->cpu = cpu; | ||
1368 | spin_unlock(&rnp->lock); /* irqs remain disabled. */ | 1377 | spin_unlock(&rnp->lock); /* irqs remain disabled. */ |
1369 | 1378 | ||
1370 | /* | 1379 | /* |
@@ -1539,8 +1548,12 @@ void __init __rcu_init(void) | |||
1539 | #endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */ | 1548 | #endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */ |
1540 | rcu_init_one(&rcu_state); | 1549 | rcu_init_one(&rcu_state); |
1541 | RCU_DATA_PTR_INIT(&rcu_state, rcu_data); | 1550 | RCU_DATA_PTR_INIT(&rcu_state, rcu_data); |
1551 | for_each_possible_cpu(i) | ||
1552 | rcu_boot_init_percpu_data(i, &rcu_state); | ||
1542 | rcu_init_one(&rcu_bh_state); | 1553 | rcu_init_one(&rcu_bh_state); |
1543 | RCU_DATA_PTR_INIT(&rcu_bh_state, rcu_bh_data); | 1554 | RCU_DATA_PTR_INIT(&rcu_bh_state, rcu_bh_data); |
1555 | for_each_possible_cpu(i) | ||
1556 | rcu_boot_init_percpu_data(i, &rcu_bh_state); | ||
1544 | 1557 | ||
1545 | for_each_online_cpu(i) | 1558 | for_each_online_cpu(i) |
1546 | rcu_cpu_notify(&rcu_nb, CPU_UP_PREPARE, (void *)(long)i); | 1559 | rcu_cpu_notify(&rcu_nb, CPU_UP_PREPARE, (void *)(long)i); |