aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/rcupdate.h1
-rw-r--r--include/linux/rcutiny.h8
-rw-r--r--include/linux/rcutree.h1
-rw-r--r--kernel/rcutiny.c71
-rw-r--r--kernel/rcutiny_plugin.h15
5 files changed, 70 insertions, 26 deletions
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index 03cda7bed985..7142ee3304ab 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -118,7 +118,6 @@ static inline int rcu_preempt_depth(void)
118#endif /* #else #ifdef CONFIG_PREEMPT_RCU */ 118#endif /* #else #ifdef CONFIG_PREEMPT_RCU */
119 119
120/* Internal to kernel */ 120/* Internal to kernel */
121extern void rcu_init(void);
122extern void rcu_sched_qs(int cpu); 121extern void rcu_sched_qs(int cpu);
123extern void rcu_bh_qs(int cpu); 122extern void rcu_bh_qs(int cpu);
124extern void rcu_check_callbacks(int cpu, int user); 123extern void rcu_check_callbacks(int cpu, int user);
diff --git a/include/linux/rcutiny.h b/include/linux/rcutiny.h
index 13877cb93a60..ea025a611fcc 100644
--- a/include/linux/rcutiny.h
+++ b/include/linux/rcutiny.h
@@ -27,7 +27,9 @@
27 27
28#include <linux/cache.h> 28#include <linux/cache.h>
29 29
30#define rcu_init_sched() do { } while (0) 30static inline void rcu_init(void)
31{
32}
31 33
32#ifdef CONFIG_TINY_RCU 34#ifdef CONFIG_TINY_RCU
33 35
@@ -125,16 +127,12 @@ static inline void rcu_cpu_stall_reset(void)
125} 127}
126 128
127#ifdef CONFIG_DEBUG_LOCK_ALLOC 129#ifdef CONFIG_DEBUG_LOCK_ALLOC
128
129extern int rcu_scheduler_active __read_mostly; 130extern int rcu_scheduler_active __read_mostly;
130extern void rcu_scheduler_starting(void); 131extern void rcu_scheduler_starting(void);
131
132#else /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */ 132#else /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */
133
134static inline void rcu_scheduler_starting(void) 133static inline void rcu_scheduler_starting(void)
135{ 134{
136} 135}
137
138#endif /* #else #ifdef CONFIG_DEBUG_LOCK_ALLOC */ 136#endif /* #else #ifdef CONFIG_DEBUG_LOCK_ALLOC */
139 137
140#endif /* __LINUX_RCUTINY_H */ 138#endif /* __LINUX_RCUTINY_H */
diff --git a/include/linux/rcutree.h b/include/linux/rcutree.h
index 95518e628794..c0e96833aa73 100644
--- a/include/linux/rcutree.h
+++ b/include/linux/rcutree.h
@@ -30,6 +30,7 @@
30#ifndef __LINUX_RCUTREE_H 30#ifndef __LINUX_RCUTREE_H
31#define __LINUX_RCUTREE_H 31#define __LINUX_RCUTREE_H
32 32
33extern void rcu_init(void);
33extern void rcu_note_context_switch(int cpu); 34extern void rcu_note_context_switch(int cpu);
34extern int rcu_needs_cpu(int cpu); 35extern int rcu_needs_cpu(int cpu);
35extern void rcu_cpu_stall_reset(void); 36extern void rcu_cpu_stall_reset(void);
diff --git a/kernel/rcutiny.c b/kernel/rcutiny.c
index d806735342ac..86eef29cdfb2 100644
--- a/kernel/rcutiny.c
+++ b/kernel/rcutiny.c
@@ -59,8 +59,15 @@ int rcu_scheduler_active __read_mostly;
59EXPORT_SYMBOL_GPL(rcu_scheduler_active); 59EXPORT_SYMBOL_GPL(rcu_scheduler_active);
60#endif /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */ 60#endif /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */
61 61
62/* Controls for rcu_cbs() kthread, replacing RCU_SOFTIRQ used previously. */
63static struct task_struct *rcu_cbs_task;
64static DECLARE_WAIT_QUEUE_HEAD(rcu_cbs_wq);
65static unsigned long have_rcu_cbs;
66static void invoke_rcu_cbs(void);
67
62/* Forward declarations for rcutiny_plugin.h. */ 68/* Forward declarations for rcutiny_plugin.h. */
63static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp); 69static void rcu_process_callbacks(struct rcu_ctrlblk *rcp);
70static int rcu_cbs(void *arg);
64static void __call_rcu(struct rcu_head *head, 71static void __call_rcu(struct rcu_head *head,
65 void (*func)(struct rcu_head *rcu), 72 void (*func)(struct rcu_head *rcu),
66 struct rcu_ctrlblk *rcp); 73 struct rcu_ctrlblk *rcp);
@@ -123,7 +130,7 @@ void rcu_sched_qs(int cpu)
123{ 130{
124 if (rcu_qsctr_help(&rcu_sched_ctrlblk) + 131 if (rcu_qsctr_help(&rcu_sched_ctrlblk) +
125 rcu_qsctr_help(&rcu_bh_ctrlblk)) 132 rcu_qsctr_help(&rcu_bh_ctrlblk))
126 raise_softirq(RCU_SOFTIRQ); 133 invoke_rcu_cbs();
127} 134}
128 135
129/* 136/*
@@ -132,7 +139,7 @@ void rcu_sched_qs(int cpu)
132void rcu_bh_qs(int cpu) 139void rcu_bh_qs(int cpu)
133{ 140{
134 if (rcu_qsctr_help(&rcu_bh_ctrlblk)) 141 if (rcu_qsctr_help(&rcu_bh_ctrlblk))
135 raise_softirq(RCU_SOFTIRQ); 142 invoke_rcu_cbs();
136} 143}
137 144
138/* 145/*
@@ -152,10 +159,10 @@ void rcu_check_callbacks(int cpu, int user)
152} 159}
153 160
154/* 161/*
155 * Helper function for rcu_process_callbacks() that operates on the 162 * Invoke the RCU callbacks on the specified rcu_ctrlkblk structure
156 * specified rcu_ctrlkblk structure. 163 * whose grace period has elapsed.
157 */ 164 */
158static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp) 165static void rcu_process_callbacks(struct rcu_ctrlblk *rcp)
159{ 166{
160 struct rcu_head *next, *list; 167 struct rcu_head *next, *list;
161 unsigned long flags; 168 unsigned long flags;
@@ -180,19 +187,52 @@ static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp)
180 next = list->next; 187 next = list->next;
181 prefetch(next); 188 prefetch(next);
182 debug_rcu_head_unqueue(list); 189 debug_rcu_head_unqueue(list);
190 local_bh_disable();
183 list->func(list); 191 list->func(list);
192 local_bh_enable();
184 list = next; 193 list = next;
185 } 194 }
186} 195}
187 196
188/* 197/*
189 * Invoke any callbacks whose grace period has completed. 198 * This kthread invokes RCU callbacks whose grace periods have
199 * elapsed. It is awakened as needed, and takes the place of the
200 * RCU_SOFTIRQ that was used previously for this purpose.
201 * This is a kthread, but it is never stopped, at least not until
202 * the system goes down.
203 */
204static int rcu_cbs(void *arg)
205{
206 unsigned long work;
207 unsigned long flags;
208
209 for (;;) {
210 wait_event(rcu_cbs_wq, have_rcu_cbs != 0);
211 local_irq_save(flags);
212 work = have_rcu_cbs;
213 have_rcu_cbs = 0;
214 local_irq_restore(flags);
215 if (work) {
216 rcu_process_callbacks(&rcu_sched_ctrlblk);
217 rcu_process_callbacks(&rcu_bh_ctrlblk);
218 rcu_preempt_process_callbacks();
219 }
220 }
221
222 return 0; /* Not reached, but needed to shut gcc up. */
223}
224
225/*
226 * Wake up rcu_cbs() to process callbacks now eligible for invocation.
190 */ 227 */
191static void rcu_process_callbacks(struct softirq_action *unused) 228static void invoke_rcu_cbs(void)
192{ 229{
193 __rcu_process_callbacks(&rcu_sched_ctrlblk); 230 unsigned long flags;
194 __rcu_process_callbacks(&rcu_bh_ctrlblk); 231
195 rcu_preempt_process_callbacks(); 232 local_irq_save(flags);
233 have_rcu_cbs = 1;
234 wake_up(&rcu_cbs_wq);
235 local_irq_restore(flags);
196} 236}
197 237
198/* 238/*
@@ -282,7 +322,12 @@ void rcu_barrier_sched(void)
282} 322}
283EXPORT_SYMBOL_GPL(rcu_barrier_sched); 323EXPORT_SYMBOL_GPL(rcu_barrier_sched);
284 324
285void __init rcu_init(void) 325/*
326 * Spawn the kthread that invokes RCU callbacks.
327 */
328static int __init rcu_spawn_kthreads(void)
286{ 329{
287 open_softirq(RCU_SOFTIRQ, rcu_process_callbacks); 330 rcu_cbs_task = kthread_run(rcu_cbs, NULL, "rcu_cbs");
331 return 0;
288} 332}
333early_initcall(rcu_spawn_kthreads);
diff --git a/kernel/rcutiny_plugin.h b/kernel/rcutiny_plugin.h
index 6ceca4f745ff..95f9239df512 100644
--- a/kernel/rcutiny_plugin.h
+++ b/kernel/rcutiny_plugin.h
@@ -22,6 +22,8 @@
22 * Author: Paul E. McKenney <paulmck@linux.vnet.ibm.com> 22 * Author: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
23 */ 23 */
24 24
25#include <linux/kthread.h>
26
25#ifdef CONFIG_TINY_PREEMPT_RCU 27#ifdef CONFIG_TINY_PREEMPT_RCU
26 28
27#include <linux/delay.h> 29#include <linux/delay.h>
@@ -164,9 +166,9 @@ static void rcu_preempt_cpu_qs(void)
164 if (!rcu_preempt_blocked_readers_any()) 166 if (!rcu_preempt_blocked_readers_any())
165 rcu_preempt_ctrlblk.rcb.donetail = rcu_preempt_ctrlblk.nexttail; 167 rcu_preempt_ctrlblk.rcb.donetail = rcu_preempt_ctrlblk.nexttail;
166 168
167 /* If there are done callbacks, make RCU_SOFTIRQ process them. */ 169 /* If there are done callbacks, cause them to be invoked. */
168 if (*rcu_preempt_ctrlblk.rcb.donetail != NULL) 170 if (*rcu_preempt_ctrlblk.rcb.donetail != NULL)
169 raise_softirq(RCU_SOFTIRQ); 171 invoke_rcu_cbs();
170} 172}
171 173
172/* 174/*
@@ -374,7 +376,7 @@ static void rcu_preempt_check_callbacks(void)
374 rcu_preempt_cpu_qs(); 376 rcu_preempt_cpu_qs();
375 if (&rcu_preempt_ctrlblk.rcb.rcucblist != 377 if (&rcu_preempt_ctrlblk.rcb.rcucblist !=
376 rcu_preempt_ctrlblk.rcb.donetail) 378 rcu_preempt_ctrlblk.rcb.donetail)
377 raise_softirq(RCU_SOFTIRQ); 379 invoke_rcu_cbs();
378 if (rcu_preempt_gp_in_progress() && 380 if (rcu_preempt_gp_in_progress() &&
379 rcu_cpu_blocking_cur_gp() && 381 rcu_cpu_blocking_cur_gp() &&
380 rcu_preempt_running_reader()) 382 rcu_preempt_running_reader())
@@ -383,7 +385,7 @@ static void rcu_preempt_check_callbacks(void)
383 385
384/* 386/*
385 * TINY_PREEMPT_RCU has an extra callback-list tail pointer to 387 * TINY_PREEMPT_RCU has an extra callback-list tail pointer to
386 * update, so this is invoked from __rcu_process_callbacks() to 388 * update, so this is invoked from rcu_process_callbacks() to
387 * handle that case. Of course, it is invoked for all flavors of 389 * handle that case. Of course, it is invoked for all flavors of
388 * RCU, but RCU callbacks can appear only on one of the lists, and 390 * RCU, but RCU callbacks can appear only on one of the lists, and
389 * neither ->nexttail nor ->donetail can possibly be NULL, so there 391 * neither ->nexttail nor ->donetail can possibly be NULL, so there
@@ -400,7 +402,7 @@ static void rcu_preempt_remove_callbacks(struct rcu_ctrlblk *rcp)
400 */ 402 */
401static void rcu_preempt_process_callbacks(void) 403static void rcu_preempt_process_callbacks(void)
402{ 404{
403 __rcu_process_callbacks(&rcu_preempt_ctrlblk.rcb); 405 rcu_process_callbacks(&rcu_preempt_ctrlblk.rcb);
404} 406}
405 407
406/* 408/*
@@ -599,14 +601,13 @@ static void rcu_preempt_process_callbacks(void)
599#endif /* #else #ifdef CONFIG_TINY_PREEMPT_RCU */ 601#endif /* #else #ifdef CONFIG_TINY_PREEMPT_RCU */
600 602
601#ifdef CONFIG_DEBUG_LOCK_ALLOC 603#ifdef CONFIG_DEBUG_LOCK_ALLOC
602
603#include <linux/kernel_stat.h> 604#include <linux/kernel_stat.h>
604 605
605/* 606/*
606 * During boot, we forgive RCU lockdep issues. After this function is 607 * During boot, we forgive RCU lockdep issues. After this function is
607 * invoked, we start taking RCU lockdep issues seriously. 608 * invoked, we start taking RCU lockdep issues seriously.
608 */ 609 */
609void rcu_scheduler_starting(void) 610void __init rcu_scheduler_starting(void)
610{ 611{
611 WARN_ON(nr_context_switches() > 0); 612 WARN_ON(nr_context_switches() > 0);
612 rcu_scheduler_active = 1; 613 rcu_scheduler_active = 1;