diff options
author | Paul E. McKenney <paul.mckenney@linaro.org> | 2010-09-09 16:40:39 -0400 |
---|---|---|
committer | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2010-11-17 18:45:09 -0500 |
commit | b2c0710c464ede15e1fc52fb1e7ee9ba54cea186 (patch) | |
tree | 7524518fec8a02e53c3fab558b40a5e94f0bb5ec /kernel/rcutiny_plugin.h | |
parent | 8e8be45e8e55daa381028aec339829929ddb53a5 (diff) |
rcu: move TINY_RCU from softirq to kthread
If RCU priority boosting is to be meaningful, callback invocation must
be boosted in addition to preempted RCU readers. Otherwise, in presence
of CPU real-time threads, the grace period ends, but the callbacks don't
get invoked. If the callbacks don't get invoked, the associated memory
doesn't get freed, so the system is still subject to OOM.
But it is not reasonable to priority-boost RCU_SOFTIRQ, so this commit
moves the callback invocations to a kthread, which can be boosted easily.
Signed-off-by: Paul E. McKenney <paul.mckenney@linaro.org>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Diffstat (limited to 'kernel/rcutiny_plugin.h')
-rw-r--r-- | kernel/rcutiny_plugin.h | 15 |
1 files changed, 8 insertions, 7 deletions
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 | */ |
401 | static void rcu_preempt_process_callbacks(void) | 403 | static 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 | */ |
609 | void rcu_scheduler_starting(void) | 610 | void __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; |