diff options
-rw-r--r-- | include/linux/rcupdate.h | 2 | ||||
-rw-r--r-- | kernel/rcupdate.c | 55 |
2 files changed, 51 insertions, 6 deletions
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index 411969cb5243..e8b4039cfb2f 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h | |||
@@ -246,6 +246,8 @@ extern void call_rcu_bh(struct rcu_head *head, | |||
246 | /* Exported common interfaces */ | 246 | /* Exported common interfaces */ |
247 | extern void synchronize_rcu(void); | 247 | extern void synchronize_rcu(void); |
248 | extern void rcu_barrier(void); | 248 | extern void rcu_barrier(void); |
249 | extern void rcu_barrier_bh(void); | ||
250 | extern void rcu_barrier_sched(void); | ||
249 | 251 | ||
250 | /* Internal to kernel */ | 252 | /* Internal to kernel */ |
251 | extern void rcu_init(void); | 253 | extern void rcu_init(void); |
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(); |