aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/rcupdate.h2
-rw-r--r--kernel/rcupdate.c41
2 files changed, 43 insertions, 0 deletions
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index cce25591eec2..a471f3bb713e 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -100,6 +100,7 @@ struct rcu_data {
100 struct rcu_head *donelist; 100 struct rcu_head *donelist;
101 struct rcu_head **donetail; 101 struct rcu_head **donetail;
102 int cpu; 102 int cpu;
103 struct rcu_head barrier;
103}; 104};
104 105
105DECLARE_PER_CPU(struct rcu_data, rcu_data); 106DECLARE_PER_CPU(struct rcu_data, rcu_data);
@@ -285,6 +286,7 @@ extern void FASTCALL(call_rcu_bh(struct rcu_head *head,
285extern __deprecated_for_modules void synchronize_kernel(void); 286extern __deprecated_for_modules void synchronize_kernel(void);
286extern void synchronize_rcu(void); 287extern void synchronize_rcu(void);
287void synchronize_idle(void); 288void synchronize_idle(void);
289extern void rcu_barrier(void);
288 290
289#endif /* __KERNEL__ */ 291#endif /* __KERNEL__ */
290#endif /* __LINUX_RCUPDATE_H */ 292#endif /* __LINUX_RCUPDATE_H */
diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c
index c4d159a21e04..f45b91723dc6 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.
@@ -457,6 +497,7 @@ static struct notifier_block __devinitdata rcu_nb = {
457 */ 497 */
458void __init rcu_init(void) 498void __init rcu_init(void)
459{ 499{
500 sema_init(&rcu_barrier_sema, 1);
460 rcu_cpu_notify(&rcu_nb, CPU_UP_PREPARE, 501 rcu_cpu_notify(&rcu_nb, CPU_UP_PREPARE,
461 (void *)(long)smp_processor_id()); 502 (void *)(long)smp_processor_id());
462 /* Register notifier for non-boot CPUs */ 503 /* Register notifier for non-boot CPUs */