diff options
Diffstat (limited to 'kernel/rcutiny.c')
-rw-r--r-- | kernel/rcutiny.c | 26 |
1 files changed, 20 insertions, 6 deletions
diff --git a/kernel/rcutiny.c b/kernel/rcutiny.c index 977296dca0a4..37a5444204d2 100644 --- a/kernel/rcutiny.c +++ b/kernel/rcutiny.c | |||
@@ -53,7 +53,7 @@ static void __call_rcu(struct rcu_head *head, | |||
53 | 53 | ||
54 | #include "rcutiny_plugin.h" | 54 | #include "rcutiny_plugin.h" |
55 | 55 | ||
56 | static long long rcu_dynticks_nesting = DYNTICK_TASK_NESTING; | 56 | static long long rcu_dynticks_nesting = DYNTICK_TASK_EXIT_IDLE; |
57 | 57 | ||
58 | /* Common code for rcu_idle_enter() and rcu_irq_exit(), see kernel/rcutree.c. */ | 58 | /* Common code for rcu_idle_enter() and rcu_irq_exit(), see kernel/rcutree.c. */ |
59 | static void rcu_idle_enter_common(long long oldval) | 59 | static void rcu_idle_enter_common(long long oldval) |
@@ -88,10 +88,16 @@ void rcu_idle_enter(void) | |||
88 | 88 | ||
89 | local_irq_save(flags); | 89 | local_irq_save(flags); |
90 | oldval = rcu_dynticks_nesting; | 90 | oldval = rcu_dynticks_nesting; |
91 | rcu_dynticks_nesting = 0; | 91 | WARN_ON_ONCE((rcu_dynticks_nesting & DYNTICK_TASK_NEST_MASK) == 0); |
92 | if ((rcu_dynticks_nesting & DYNTICK_TASK_NEST_MASK) == | ||
93 | DYNTICK_TASK_NEST_VALUE) | ||
94 | rcu_dynticks_nesting = 0; | ||
95 | else | ||
96 | rcu_dynticks_nesting -= DYNTICK_TASK_NEST_VALUE; | ||
92 | rcu_idle_enter_common(oldval); | 97 | rcu_idle_enter_common(oldval); |
93 | local_irq_restore(flags); | 98 | local_irq_restore(flags); |
94 | } | 99 | } |
100 | EXPORT_SYMBOL_GPL(rcu_idle_enter); | ||
95 | 101 | ||
96 | /* | 102 | /* |
97 | * Exit an interrupt handler towards idle. | 103 | * Exit an interrupt handler towards idle. |
@@ -140,11 +146,15 @@ void rcu_idle_exit(void) | |||
140 | 146 | ||
141 | local_irq_save(flags); | 147 | local_irq_save(flags); |
142 | oldval = rcu_dynticks_nesting; | 148 | oldval = rcu_dynticks_nesting; |
143 | WARN_ON_ONCE(oldval != 0); | 149 | WARN_ON_ONCE(rcu_dynticks_nesting < 0); |
144 | rcu_dynticks_nesting = DYNTICK_TASK_NESTING; | 150 | if (rcu_dynticks_nesting & DYNTICK_TASK_NEST_MASK) |
151 | rcu_dynticks_nesting += DYNTICK_TASK_NEST_VALUE; | ||
152 | else | ||
153 | rcu_dynticks_nesting = DYNTICK_TASK_EXIT_IDLE; | ||
145 | rcu_idle_exit_common(oldval); | 154 | rcu_idle_exit_common(oldval); |
146 | local_irq_restore(flags); | 155 | local_irq_restore(flags); |
147 | } | 156 | } |
157 | EXPORT_SYMBOL_GPL(rcu_idle_exit); | ||
148 | 158 | ||
149 | /* | 159 | /* |
150 | * Enter an interrupt handler, moving away from idle. | 160 | * Enter an interrupt handler, moving away from idle. |
@@ -258,7 +268,7 @@ static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp) | |||
258 | 268 | ||
259 | /* If no RCU callbacks ready to invoke, just return. */ | 269 | /* If no RCU callbacks ready to invoke, just return. */ |
260 | if (&rcp->rcucblist == rcp->donetail) { | 270 | if (&rcp->rcucblist == rcp->donetail) { |
261 | RCU_TRACE(trace_rcu_batch_start(rcp->name, 0, -1)); | 271 | RCU_TRACE(trace_rcu_batch_start(rcp->name, 0, 0, -1)); |
262 | RCU_TRACE(trace_rcu_batch_end(rcp->name, 0, | 272 | RCU_TRACE(trace_rcu_batch_end(rcp->name, 0, |
263 | ACCESS_ONCE(rcp->rcucblist), | 273 | ACCESS_ONCE(rcp->rcucblist), |
264 | need_resched(), | 274 | need_resched(), |
@@ -269,7 +279,7 @@ static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp) | |||
269 | 279 | ||
270 | /* Move the ready-to-invoke callbacks to a local list. */ | 280 | /* Move the ready-to-invoke callbacks to a local list. */ |
271 | local_irq_save(flags); | 281 | local_irq_save(flags); |
272 | RCU_TRACE(trace_rcu_batch_start(rcp->name, 0, -1)); | 282 | RCU_TRACE(trace_rcu_batch_start(rcp->name, 0, rcp->qlen, -1)); |
273 | list = rcp->rcucblist; | 283 | list = rcp->rcucblist; |
274 | rcp->rcucblist = *rcp->donetail; | 284 | rcp->rcucblist = *rcp->donetail; |
275 | *rcp->donetail = NULL; | 285 | *rcp->donetail = NULL; |
@@ -319,6 +329,10 @@ static void rcu_process_callbacks(struct softirq_action *unused) | |||
319 | */ | 329 | */ |
320 | void synchronize_sched(void) | 330 | void synchronize_sched(void) |
321 | { | 331 | { |
332 | rcu_lockdep_assert(!lock_is_held(&rcu_bh_lock_map) && | ||
333 | !lock_is_held(&rcu_lock_map) && | ||
334 | !lock_is_held(&rcu_sched_lock_map), | ||
335 | "Illegal synchronize_sched() in RCU read-side critical section"); | ||
322 | cond_resched(); | 336 | cond_resched(); |
323 | } | 337 | } |
324 | EXPORT_SYMBOL_GPL(synchronize_sched); | 338 | EXPORT_SYMBOL_GPL(synchronize_sched); |