1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25#include <linux/completion.h>
26#include <linux/interrupt.h>
27#include <linux/notifier.h>
28#include <linux/rcupdate_wait.h>
29#include <linux/kernel.h>
30#include <linux/export.h>
31#include <linux/mutex.h>
32#include <linux/sched.h>
33#include <linux/types.h>
34#include <linux/init.h>
35#include <linux/time.h>
36#include <linux/cpu.h>
37#include <linux/prefetch.h>
38#include <linux/trace_events.h>
39
40#include "rcu.h"
41
42
43struct rcu_ctrlblk;
44static void __call_rcu(struct rcu_head *head,
45 rcu_callback_t func,
46 struct rcu_ctrlblk *rcp);
47
48#include "tiny_plugin.h"
49
50void rcu_barrier_bh(void)
51{
52 wait_rcu_gp(call_rcu_bh);
53}
54EXPORT_SYMBOL(rcu_barrier_bh);
55
56void rcu_barrier_sched(void)
57{
58 wait_rcu_gp(call_rcu_sched);
59}
60EXPORT_SYMBOL(rcu_barrier_sched);
61
62#if defined(CONFIG_DEBUG_LOCK_ALLOC) || defined(CONFIG_RCU_TRACE)
63
64
65
66
67bool notrace __rcu_is_watching(void)
68{
69 return true;
70}
71EXPORT_SYMBOL(__rcu_is_watching);
72
73#endif
74
75
76
77
78
79
80static int rcu_qsctr_help(struct rcu_ctrlblk *rcp)
81{
82 RCU_TRACE(reset_cpu_stall_ticks(rcp));
83 if (rcp->donetail != rcp->curtail) {
84 rcp->donetail = rcp->curtail;
85 return 1;
86 }
87
88 return 0;
89}
90
91
92
93
94
95
96void rcu_sched_qs(void)
97{
98 unsigned long flags;
99
100 local_irq_save(flags);
101 if (rcu_qsctr_help(&rcu_sched_ctrlblk) +
102 rcu_qsctr_help(&rcu_bh_ctrlblk))
103 raise_softirq(RCU_SOFTIRQ);
104 local_irq_restore(flags);
105}
106
107
108
109
110void rcu_bh_qs(void)
111{
112 unsigned long flags;
113
114 local_irq_save(flags);
115 if (rcu_qsctr_help(&rcu_bh_ctrlblk))
116 raise_softirq(RCU_SOFTIRQ);
117 local_irq_restore(flags);
118}
119
120
121
122
123
124
125
126void rcu_check_callbacks(int user)
127{
128 RCU_TRACE(check_cpu_stalls());
129 if (user)
130 rcu_sched_qs();
131 else if (!in_softirq())
132 rcu_bh_qs();
133 if (user)
134 rcu_note_voluntary_context_switch(current);
135}
136
137
138
139
140
141static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp)
142{
143 const char *rn = NULL;
144 struct rcu_head *next, *list;
145 unsigned long flags;
146 RCU_TRACE(int cb_count = 0);
147
148
149 local_irq_save(flags);
150 if (rcp->donetail == &rcp->rcucblist) {
151
152 local_irq_restore(flags);
153 return;
154 }
155 RCU_TRACE(trace_rcu_batch_start(rcp->name, 0, rcp->qlen, -1));
156 list = rcp->rcucblist;
157 rcp->rcucblist = *rcp->donetail;
158 *rcp->donetail = NULL;
159 if (rcp->curtail == rcp->donetail)
160 rcp->curtail = &rcp->rcucblist;
161 rcp->donetail = &rcp->rcucblist;
162 local_irq_restore(flags);
163
164
165 RCU_TRACE(rn = rcp->name);
166 while (list) {
167 next = list->next;
168 prefetch(next);
169 debug_rcu_head_unqueue(list);
170 local_bh_disable();
171 __rcu_reclaim(rn, list);
172 local_bh_enable();
173 list = next;
174 RCU_TRACE(cb_count++);
175 }
176 RCU_TRACE(rcu_trace_sub_qlen(rcp, cb_count));
177 RCU_TRACE(trace_rcu_batch_end(rcp->name,
178 cb_count, 0, need_resched(),
179 is_idle_task(current),
180 false));
181}
182
183static __latent_entropy void rcu_process_callbacks(struct softirq_action *unused)
184{
185 __rcu_process_callbacks(&rcu_sched_ctrlblk);
186 __rcu_process_callbacks(&rcu_bh_ctrlblk);
187}
188
189
190
191
192
193
194
195
196
197
198
199void synchronize_sched(void)
200{
201 RCU_LOCKDEP_WARN(lock_is_held(&rcu_bh_lock_map) ||
202 lock_is_held(&rcu_lock_map) ||
203 lock_is_held(&rcu_sched_lock_map),
204 "Illegal synchronize_sched() in RCU read-side critical section");
205}
206EXPORT_SYMBOL_GPL(synchronize_sched);
207
208
209
210
211static void __call_rcu(struct rcu_head *head,
212 rcu_callback_t func,
213 struct rcu_ctrlblk *rcp)
214{
215 unsigned long flags;
216
217 debug_rcu_head_queue(head);
218 head->func = func;
219 head->next = NULL;
220
221 local_irq_save(flags);
222 *rcp->curtail = head;
223 rcp->curtail = &head->next;
224 RCU_TRACE(rcp->qlen++);
225 local_irq_restore(flags);
226
227 if (unlikely(is_idle_task(current))) {
228
229 resched_cpu(0);
230 }
231}
232
233
234
235
236
237
238void call_rcu_sched(struct rcu_head *head, rcu_callback_t func)
239{
240 __call_rcu(head, func, &rcu_sched_ctrlblk);
241}
242EXPORT_SYMBOL_GPL(call_rcu_sched);
243
244
245
246
247
248void call_rcu_bh(struct rcu_head *head, rcu_callback_t func)
249{
250 __call_rcu(head, func, &rcu_bh_ctrlblk);
251}
252EXPORT_SYMBOL_GPL(call_rcu_bh);
253
254void __init rcu_init(void)
255{
256 open_softirq(RCU_SOFTIRQ, rcu_process_callbacks);
257 RCU_TRACE(reset_cpu_stall_ticks(&rcu_sched_ctrlblk));
258 RCU_TRACE(reset_cpu_stall_ticks(&rcu_bh_ctrlblk));
259
260 rcu_early_boot_tests();
261}
262