aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/rcupdate.c
diff options
context:
space:
mode:
authorJody McIntyre <scjody@modernduck.com>2005-12-12 23:58:44 -0500
committerJody McIntyre <scjody@modernduck.com>2005-12-12 23:58:44 -0500
commit25d3f1622fdbc73db3f6860961b5fb3035a39f32 (patch)
treef4eef88bc0083f282c64c14e81c0ecc95e5f2b43 /kernel/rcupdate.c
parentdc3edd5412341b02d84144ddfd5bf6ccaaeeb1ac (diff)
parent0e670506668a43e1355b8f10c33d081a676bd521 (diff)
Merge with http://kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
Diffstat (limited to 'kernel/rcupdate.c')
-rw-r--r--kernel/rcupdate.c59
1 files changed, 54 insertions, 5 deletions
diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c
index c4d159a21e04..48d3bce465b8 100644
--- a/kernel/rcupdate.c
+++ b/kernel/rcupdate.c
@@ -116,6 +116,10 @@ void fastcall call_rcu(struct rcu_head *head,
116 local_irq_restore(flags); 116 local_irq_restore(flags);
117} 117}
118 118
119static atomic_t rcu_barrier_cpu_count;
120static struct semaphore rcu_barrier_sema;
121static struct completion rcu_barrier_completion;
122
119/** 123/**
120 * call_rcu_bh - Queue an RCU for invocation after a quicker grace period. 124 * call_rcu_bh - Queue an RCU for invocation after a quicker grace period.
121 * @head: structure to be used for queueing the RCU updates. 125 * @head: structure to be used for queueing the RCU updates.
@@ -162,6 +166,42 @@ long rcu_batches_completed(void)
162 return rcu_ctrlblk.completed; 166 return rcu_ctrlblk.completed;
163} 167}
164 168
169static void rcu_barrier_callback(struct rcu_head *notused)
170{
171 if (atomic_dec_and_test(&rcu_barrier_cpu_count))
172 complete(&rcu_barrier_completion);
173}
174
175/*
176 * Called with preemption disabled, and from cross-cpu IRQ context.
177 */
178static void rcu_barrier_func(void *notused)
179{
180 int cpu = smp_processor_id();
181 struct rcu_data *rdp = &per_cpu(rcu_data, cpu);
182 struct rcu_head *head;
183
184 head = &rdp->barrier;
185 atomic_inc(&rcu_barrier_cpu_count);
186 call_rcu(head, rcu_barrier_callback);
187}
188
189/**
190 * rcu_barrier - Wait until all the in-flight RCUs are complete.
191 */
192void rcu_barrier(void)
193{
194 BUG_ON(in_interrupt());
195 /* Take cpucontrol semaphore to protect against CPU hotplug */
196 down(&rcu_barrier_sema);
197 init_completion(&rcu_barrier_completion);
198 atomic_set(&rcu_barrier_cpu_count, 0);
199 on_each_cpu(rcu_barrier_func, NULL, 0, 1);
200 wait_for_completion(&rcu_barrier_completion);
201 up(&rcu_barrier_sema);
202}
203EXPORT_SYMBOL_GPL(rcu_barrier);
204
165/* 205/*
166 * Invoke the completed RCU callbacks. They are expected to be in 206 * Invoke the completed RCU callbacks. They are expected to be in
167 * a per-cpu list. 207 * a per-cpu list.
@@ -217,15 +257,23 @@ static void rcu_start_batch(struct rcu_ctrlblk *rcp, struct rcu_state *rsp,
217 257
218 if (rcp->next_pending && 258 if (rcp->next_pending &&
219 rcp->completed == rcp->cur) { 259 rcp->completed == rcp->cur) {
220 /* Can't change, since spin lock held. */
221 cpus_andnot(rsp->cpumask, cpu_online_map, nohz_cpu_mask);
222
223 rcp->next_pending = 0; 260 rcp->next_pending = 0;
224 /* next_pending == 0 must be visible in __rcu_process_callbacks() 261 /*
225 * before it can see new value of cur. 262 * next_pending == 0 must be visible in
263 * __rcu_process_callbacks() before it can see new value of cur.
226 */ 264 */
227 smp_wmb(); 265 smp_wmb();
228 rcp->cur++; 266 rcp->cur++;
267
268 /*
269 * Accessing nohz_cpu_mask before incrementing rcp->cur needs a
270 * Barrier Otherwise it can cause tickless idle CPUs to be
271 * included in rsp->cpumask, which will extend graceperiods
272 * unnecessarily.
273 */
274 smp_mb();
275 cpus_andnot(rsp->cpumask, cpu_online_map, nohz_cpu_mask);
276
229 } 277 }
230} 278}
231 279
@@ -457,6 +505,7 @@ static struct notifier_block __devinitdata rcu_nb = {
457 */ 505 */
458void __init rcu_init(void) 506void __init rcu_init(void)
459{ 507{
508 sema_init(&rcu_barrier_sema, 1);
460 rcu_cpu_notify(&rcu_nb, CPU_UP_PREPARE, 509 rcu_cpu_notify(&rcu_nb, CPU_UP_PREPARE,
461 (void *)(long)smp_processor_id()); 510 (void *)(long)smp_processor_id());
462 /* Register notifier for non-boot CPUs */ 511 /* Register notifier for non-boot CPUs */