diff options
author | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2008-05-12 15:21:05 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-05-19 04:01:36 -0400 |
commit | 70f12f848d3e981479b4f6f751e73c14f7c13e5b (patch) | |
tree | f964e121463ab2f6b697f043bf487017bc85d635 /kernel | |
parent | 8db559b83009bed92e1b5dd13a651ff273d9ff62 (diff) |
rcu: add rcu_barrier_sched() and rcu_barrier_bh()
Add rcu_barrier_sched() and rcu_barrier_bh(). With these in place,
rcutorture no longer gives the occasional oops when repeatedly starting
and stopping torturing rcu_bh. Also adds the API needed to flush out
pre-existing call_rcu_sched() callbacks.
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/rcupdate.c | 55 |
1 files changed, 49 insertions, 6 deletions
diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c index a4e329d92883..4a74b8d48d90 100644 --- a/kernel/rcupdate.c +++ b/kernel/rcupdate.c | |||
@@ -45,6 +45,12 @@ | |||
45 | #include <linux/mutex.h> | 45 | #include <linux/mutex.h> |
46 | #include <linux/module.h> | 46 | #include <linux/module.h> |
47 | 47 | ||
48 | enum rcu_barrier { | ||
49 | RCU_BARRIER_STD, | ||
50 | RCU_BARRIER_BH, | ||
51 | RCU_BARRIER_SCHED, | ||
52 | }; | ||
53 | |||
48 | static DEFINE_PER_CPU(struct rcu_head, rcu_barrier_head) = {NULL}; | 54 | static DEFINE_PER_CPU(struct rcu_head, rcu_barrier_head) = {NULL}; |
49 | static atomic_t rcu_barrier_cpu_count; | 55 | static atomic_t rcu_barrier_cpu_count; |
50 | static DEFINE_MUTEX(rcu_barrier_mutex); | 56 | static DEFINE_MUTEX(rcu_barrier_mutex); |
@@ -83,19 +89,30 @@ static void rcu_barrier_callback(struct rcu_head *notused) | |||
83 | /* | 89 | /* |
84 | * Called with preemption disabled, and from cross-cpu IRQ context. | 90 | * Called with preemption disabled, and from cross-cpu IRQ context. |
85 | */ | 91 | */ |
86 | static void rcu_barrier_func(void *notused) | 92 | static void rcu_barrier_func(void *type) |
87 | { | 93 | { |
88 | int cpu = smp_processor_id(); | 94 | int cpu = smp_processor_id(); |
89 | struct rcu_head *head = &per_cpu(rcu_barrier_head, cpu); | 95 | struct rcu_head *head = &per_cpu(rcu_barrier_head, cpu); |
90 | 96 | ||
91 | atomic_inc(&rcu_barrier_cpu_count); | 97 | atomic_inc(&rcu_barrier_cpu_count); |
92 | call_rcu(head, rcu_barrier_callback); | 98 | switch ((enum rcu_barrier)type) { |
99 | case RCU_BARRIER_STD: | ||
100 | call_rcu(head, rcu_barrier_callback); | ||
101 | break; | ||
102 | case RCU_BARRIER_BH: | ||
103 | call_rcu_bh(head, rcu_barrier_callback); | ||
104 | break; | ||
105 | case RCU_BARRIER_SCHED: | ||
106 | call_rcu_sched(head, rcu_barrier_callback); | ||
107 | break; | ||
108 | } | ||
93 | } | 109 | } |
94 | 110 | ||
95 | /** | 111 | /* |
96 | * rcu_barrier - Wait until all the in-flight RCUs are complete. | 112 | * Orchestrate the specified type of RCU barrier, waiting for all |
113 | * RCU callbacks of the specified type to complete. | ||
97 | */ | 114 | */ |
98 | void rcu_barrier(void) | 115 | static void _rcu_barrier(enum rcu_barrier type) |
99 | { | 116 | { |
100 | BUG_ON(in_interrupt()); | 117 | BUG_ON(in_interrupt()); |
101 | /* Take cpucontrol mutex to protect against CPU hotplug */ | 118 | /* Take cpucontrol mutex to protect against CPU hotplug */ |
@@ -111,13 +128,39 @@ void rcu_barrier(void) | |||
111 | * until all the callbacks are queued. | 128 | * until all the callbacks are queued. |
112 | */ | 129 | */ |
113 | rcu_read_lock(); | 130 | rcu_read_lock(); |
114 | on_each_cpu(rcu_barrier_func, NULL, 0, 1); | 131 | on_each_cpu(rcu_barrier_func, (void *)type, 0, 1); |
115 | rcu_read_unlock(); | 132 | rcu_read_unlock(); |
116 | wait_for_completion(&rcu_barrier_completion); | 133 | wait_for_completion(&rcu_barrier_completion); |
117 | mutex_unlock(&rcu_barrier_mutex); | 134 | mutex_unlock(&rcu_barrier_mutex); |
118 | } | 135 | } |
136 | |||
137 | /** | ||
138 | * rcu_barrier - Wait until all in-flight call_rcu() callbacks complete. | ||
139 | */ | ||
140 | void rcu_barrier(void) | ||
141 | { | ||
142 | _rcu_barrier(RCU_BARRIER_STD); | ||
143 | } | ||
119 | EXPORT_SYMBOL_GPL(rcu_barrier); | 144 | EXPORT_SYMBOL_GPL(rcu_barrier); |
120 | 145 | ||
146 | /** | ||
147 | * rcu_barrier_bh - Wait until all in-flight call_rcu_bh() callbacks complete. | ||
148 | */ | ||
149 | void rcu_barrier_bh(void) | ||
150 | { | ||
151 | _rcu_barrier(RCU_BARRIER_BH); | ||
152 | } | ||
153 | EXPORT_SYMBOL_GPL(rcu_barrier_bh); | ||
154 | |||
155 | /** | ||
156 | * rcu_barrier_sched - Wait for in-flight call_rcu_sched() callbacks. | ||
157 | */ | ||
158 | void rcu_barrier_sched(void) | ||
159 | { | ||
160 | _rcu_barrier(RCU_BARRIER_SCHED); | ||
161 | } | ||
162 | EXPORT_SYMBOL_GPL(rcu_barrier_sched); | ||
163 | |||
121 | void __init rcu_init(void) | 164 | void __init rcu_init(void) |
122 | { | 165 | { |
123 | __rcu_init(); | 166 | __rcu_init(); |