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
26
27
28
29
30
31
32
33#include <linux/types.h>
34#include <linux/kernel.h>
35#include <linux/init.h>
36#include <linux/spinlock.h>
37#include <linux/smp.h>
38#include <linux/rcupdate.h>
39#include <linux/interrupt.h>
40#include <linux/sched.h>
41#include <asm/atomic.h>
42#include <linux/bitops.h>
43#include <linux/module.h>
44#include <linux/completion.h>
45#include <linux/moduleparam.h>
46#include <linux/percpu.h>
47#include <linux/notifier.h>
48#include <linux/cpu.h>
49#include <linux/mutex.h>
50
51#ifdef CONFIG_DEBUG_LOCK_ALLOC
52static struct lock_class_key rcu_lock_key;
53struct lockdep_map rcu_lock_map =
54 STATIC_LOCKDEP_MAP_INIT("rcu_read_lock", &rcu_lock_key);
55EXPORT_SYMBOL_GPL(rcu_lock_map);
56#endif
57
58
59
60static struct rcu_ctrlblk rcu_ctrlblk = {
61 .cur = -300,
62 .completed = -300,
63 .lock = __SPIN_LOCK_UNLOCKED(&rcu_ctrlblk.lock),
64 .cpumask = CPU_MASK_NONE,
65};
66static struct rcu_ctrlblk rcu_bh_ctrlblk = {
67 .cur = -300,
68 .completed = -300,
69 .lock = __SPIN_LOCK_UNLOCKED(&rcu_bh_ctrlblk.lock),
70 .cpumask = CPU_MASK_NONE,
71};
72
73DEFINE_PER_CPU(struct rcu_data, rcu_data) = { 0L };
74DEFINE_PER_CPU(struct rcu_data, rcu_bh_data) = { 0L };
75
76static int blimit = 10;
77static int qhimark = 10000;
78static int qlowmark = 100;
79
80#ifdef CONFIG_SMP
81static void force_quiescent_state(struct rcu_data *rdp,
82 struct rcu_ctrlblk *rcp)
83{
84 int cpu;
85 cpumask_t cpumask;
86 set_need_resched();
87 if (unlikely(!rcp->signaled)) {
88 rcp->signaled = 1;
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107 cpus_and(cpumask, rcp->cpumask, cpu_online_map);
108 cpu_clear(rdp->cpu, cpumask);
109 for_each_cpu_mask(cpu, cpumask)
110 smp_send_reschedule(cpu);
111 }
112}
113#else
114static inline void force_quiescent_state(struct rcu_data *rdp,
115 struct rcu_ctrlblk *rcp)
116{
117 set_need_resched();
118}
119#endif
120
121
122
123
124
125
126
127
128
129
130
131
132void call_rcu(struct rcu_head *head,
133 void (*func)(struct rcu_head *rcu))
134{
135 unsigned long flags;
136 struct rcu_data *rdp;
137
138 head->func = func;
139 head->next = NULL;
140 local_irq_save(flags);
141 rdp = &__get_cpu_var(rcu_data);
142 *rdp->nxttail = head;
143 rdp->nxttail = &head->next;
144 if (unlikely(++rdp->qlen > qhimark)) {
145 rdp->blimit = INT_MAX;
146 force_quiescent_state(rdp, &rcu_ctrlblk);
147 }
148 local_irq_restore(flags);
149}
150EXPORT_SYMBOL_GPL(call_rcu);
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168void call_rcu_bh(struct rcu_head *head,
169 void (*func)(struct rcu_head *rcu))
170{
171 unsigned long flags;
172 struct rcu_data *rdp;
173
174 head->func = func;
175 head->next = NULL;
176 local_irq_save(flags);
177 rdp = &__get_cpu_var(rcu_bh_data);
178 *rdp->nxttail = head;
179 rdp->nxttail = &head->next;
180
181 if (unlikely(++rdp->qlen > qhimark)) {
182 rdp->blimit = INT_MAX;
183 force_quiescent_state(rdp, &rcu_bh_ctrlblk);
184 }
185
186 local_irq_restore(flags);
187}
188EXPORT_SYMBOL_GPL(call_rcu_bh);
189
190
191
192
193
194long rcu_batches_completed(void)
195{
196 return rcu_ctrlblk.completed;
197}
198EXPORT_SYMBOL_GPL(rcu_batches_completed);
199
200
201
202
203
204long rcu_batches_completed_bh(void)
205{
206 return rcu_bh_ctrlblk.completed;
207}
208EXPORT_SYMBOL_GPL(rcu_batches_completed_bh);
209
210
211static inline void raise_rcu_softirq(void)
212{
213 raise_softirq(RCU_SOFTIRQ);
214
215
216
217
218
219 smp_mb();
220}
221
222
223
224
225
226static void rcu_do_batch(struct rcu_data *rdp)
227{
228 struct rcu_head *next, *list;
229 int count = 0;
230
231 list = rdp->donelist;
232 while (list) {
233 next = list->next;
234 prefetch(next);
235 list->func(list);
236 list = next;
237 if (++count >= rdp->blimit)
238 break;
239 }
240 rdp->donelist = list;
241
242 local_irq_disable();
243 rdp->qlen -= count;
244 local_irq_enable();
245 if (rdp->blimit == INT_MAX && rdp->qlen <= qlowmark)
246 rdp->blimit = blimit;
247
248 if (!rdp->donelist)
249 rdp->donetail = &rdp->donelist;
250 else
251 raise_rcu_softirq();
252}
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277static void rcu_start_batch(struct rcu_ctrlblk *rcp)
278{
279 if (rcp->next_pending &&
280 rcp->completed == rcp->cur) {
281 rcp->next_pending = 0;
282
283
284
285
286 smp_wmb();
287 rcp->cur++;
288
289
290
291
292
293
294
295 smp_mb();
296 cpus_andnot(rcp->cpumask, cpu_online_map, nohz_cpu_mask);
297
298 rcp->signaled = 0;
299 }
300}
301
302
303
304
305
306
307static void cpu_quiet(int cpu, struct rcu_ctrlblk *rcp)
308{
309 cpu_clear(cpu, rcp->cpumask);
310 if (cpus_empty(rcp->cpumask)) {
311
312 rcp->completed = rcp->cur;
313 rcu_start_batch(rcp);
314 }
315}
316
317
318
319
320
321
322static void rcu_check_quiescent_state(struct rcu_ctrlblk *rcp,
323 struct rcu_data *rdp)
324{
325 if (rdp->quiescbatch != rcp->cur) {
326
327 rdp->qs_pending = 1;
328 rdp->passed_quiesc = 0;
329 rdp->quiescbatch = rcp->cur;
330 return;
331 }
332
333
334
335
336
337 if (!rdp->qs_pending)
338 return;
339
340
341
342
343
344 if (!rdp->passed_quiesc)
345 return;
346 rdp->qs_pending = 0;
347
348 spin_lock(&rcp->lock);
349
350
351
352
353 if (likely(rdp->quiescbatch == rcp->cur))
354 cpu_quiet(rdp->cpu, rcp);
355
356 spin_unlock(&rcp->lock);
357}
358
359
360#ifdef CONFIG_HOTPLUG_CPU
361
362
363
364
365
366static void rcu_move_batch(struct rcu_data *this_rdp, struct rcu_head *list,
367 struct rcu_head **tail)
368{
369 local_irq_disable();
370 *this_rdp->nxttail = list;
371 if (list)
372 this_rdp->nxttail = tail;
373 local_irq_enable();
374}
375
376static void __rcu_offline_cpu(struct rcu_data *this_rdp,
377 struct rcu_ctrlblk *rcp, struct rcu_data *rdp)
378{
379
380
381
382
383 spin_lock_bh(&rcp->lock);
384 if (rcp->cur != rcp->completed)
385 cpu_quiet(rdp->cpu, rcp);
386 spin_unlock_bh(&rcp->lock);
387 rcu_move_batch(this_rdp, rdp->donelist, rdp->donetail);
388 rcu_move_batch(this_rdp, rdp->curlist, rdp->curtail);
389 rcu_move_batch(this_rdp, rdp->nxtlist, rdp->nxttail);
390}
391
392static void rcu_offline_cpu(int cpu)
393{
394 struct rcu_data *this_rdp = &get_cpu_var(rcu_data);
395 struct rcu_data *this_bh_rdp = &get_cpu_var(rcu_bh_data);
396
397 __rcu_offline_cpu(this_rdp, &rcu_ctrlblk,
398 &per_cpu(rcu_data, cpu));
399 __rcu_offline_cpu(this_bh_rdp, &rcu_bh_ctrlblk,
400 &per_cpu(rcu_bh_data, cpu));
401 put_cpu_var(rcu_data);
402 put_cpu_var(rcu_bh_data);
403}
404
405#else
406
407static void rcu_offline_cpu(int cpu)
408{
409}
410
411#endif
412
413
414
415
416static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp,
417 struct rcu_data *rdp)
418{
419 if (rdp->curlist && !rcu_batch_before(rcp->completed, rdp->batch)) {
420 *rdp->donetail = rdp->curlist;
421 rdp->donetail = rdp->curtail;
422 rdp->curlist = NULL;
423 rdp->curtail = &rdp->curlist;
424 }
425
426 if (rdp->nxtlist && !rdp->curlist) {
427 local_irq_disable();
428 rdp->curlist = rdp->nxtlist;
429 rdp->curtail = rdp->nxttail;
430 rdp->nxtlist = NULL;
431 rdp->nxttail = &rdp->nxtlist;
432 local_irq_enable();
433
434
435
436
437
438
439 rdp->batch = rcp->cur + 1;
440
441
442
443 smp_rmb();
444
445 if (!rcp->next_pending) {
446
447 spin_lock(&rcp->lock);
448 rcp->next_pending = 1;
449 rcu_start_batch(rcp);
450 spin_unlock(&rcp->lock);
451 }
452 }
453
454 rcu_check_quiescent_state(rcp, rdp);
455 if (rdp->donelist)
456 rcu_do_batch(rdp);
457}
458
459static void rcu_process_callbacks(struct softirq_action *unused)
460{
461 __rcu_process_callbacks(&rcu_ctrlblk, &__get_cpu_var(rcu_data));
462 __rcu_process_callbacks(&rcu_bh_ctrlblk, &__get_cpu_var(rcu_bh_data));
463}
464
465static int __rcu_pending(struct rcu_ctrlblk *rcp, struct rcu_data *rdp)
466{
467
468
469
470 if (rdp->curlist && !rcu_batch_before(rcp->completed, rdp->batch))
471 return 1;
472
473
474 if (!rdp->curlist && rdp->nxtlist)
475 return 1;
476
477
478 if (rdp->donelist)
479 return 1;
480
481
482 if (rdp->quiescbatch != rcp->cur || rdp->qs_pending)
483 return 1;
484
485
486 return 0;
487}
488
489
490
491
492
493
494int rcu_pending(int cpu)
495{
496 return __rcu_pending(&rcu_ctrlblk, &per_cpu(rcu_data, cpu)) ||
497 __rcu_pending(&rcu_bh_ctrlblk, &per_cpu(rcu_bh_data, cpu));
498}
499
500
501
502
503
504
505
506int rcu_needs_cpu(int cpu)
507{
508 struct rcu_data *rdp = &per_cpu(rcu_data, cpu);
509 struct rcu_data *rdp_bh = &per_cpu(rcu_bh_data, cpu);
510
511 return (!!rdp->curlist || !!rdp_bh->curlist || rcu_pending(cpu));
512}
513
514void rcu_check_callbacks(int cpu, int user)
515{
516 if (user ||
517 (idle_cpu(cpu) && !in_softirq() &&
518 hardirq_count() <= (1 << HARDIRQ_SHIFT))) {
519 rcu_qsctr_inc(cpu);
520 rcu_bh_qsctr_inc(cpu);
521 } else if (!in_softirq())
522 rcu_bh_qsctr_inc(cpu);
523 raise_rcu_softirq();
524}
525
526static void rcu_init_percpu_data(int cpu, struct rcu_ctrlblk *rcp,
527 struct rcu_data *rdp)
528{
529 memset(rdp, 0, sizeof(*rdp));
530 rdp->curtail = &rdp->curlist;
531 rdp->nxttail = &rdp->nxtlist;
532 rdp->donetail = &rdp->donelist;
533 rdp->quiescbatch = rcp->completed;
534 rdp->qs_pending = 0;
535 rdp->cpu = cpu;
536 rdp->blimit = blimit;
537}
538
539static void __cpuinit rcu_online_cpu(int cpu)
540{
541 struct rcu_data *rdp = &per_cpu(rcu_data, cpu);
542 struct rcu_data *bh_rdp = &per_cpu(rcu_bh_data, cpu);
543
544 rcu_init_percpu_data(cpu, &rcu_ctrlblk, rdp);
545 rcu_init_percpu_data(cpu, &rcu_bh_ctrlblk, bh_rdp);
546 open_softirq(RCU_SOFTIRQ, rcu_process_callbacks, NULL);
547}
548
549static int __cpuinit rcu_cpu_notify(struct notifier_block *self,
550 unsigned long action, void *hcpu)
551{
552 long cpu = (long)hcpu;
553
554 switch (action) {
555 case CPU_UP_PREPARE:
556 case CPU_UP_PREPARE_FROZEN:
557 rcu_online_cpu(cpu);
558 break;
559 case CPU_DEAD:
560 case CPU_DEAD_FROZEN:
561 rcu_offline_cpu(cpu);
562 break;
563 default:
564 break;
565 }
566 return NOTIFY_OK;
567}
568
569static struct notifier_block __cpuinitdata rcu_nb = {
570 .notifier_call = rcu_cpu_notify,
571};
572
573
574
575
576
577
578
579void __init __rcu_init(void)
580{
581 rcu_cpu_notify(&rcu_nb, CPU_UP_PREPARE,
582 (void *)(long)smp_processor_id());
583
584 register_cpu_notifier(&rcu_nb);
585}
586
587module_param(blimit, int, 0);
588module_param(qhimark, int, 0);
589module_param(qlowmark, int, 0);
590