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
34
35
36
37
38#include <linux/types.h>
39#include <linux/kernel.h>
40#include <linux/init.h>
41#include <linux/spinlock.h>
42#include <linux/smp.h>
43#include <linux/rcupdate.h>
44#include <linux/interrupt.h>
45#include <linux/sched.h>
46#include <asm/atomic.h>
47#include <linux/bitops.h>
48#include <linux/module.h>
49#include <linux/completion.h>
50#include <linux/moduleparam.h>
51#include <linux/percpu.h>
52#include <linux/notifier.h>
53#include <linux/rcupdate.h>
54#include <linux/cpu.h>
55#include <linux/random.h>
56#include <linux/delay.h>
57#include <linux/byteorder/swabb.h>
58#include <linux/cpumask.h>
59#include <linux/rcupreempt_trace.h>
60
61
62
63
64
65
66
67#define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))
68
69
70
71
72
73
74
75
76
77
78
79
80#define GP_STAGES 2
81struct rcu_data {
82 spinlock_t lock;
83 long completed;
84 int waitlistcount;
85 struct tasklet_struct rcu_tasklet;
86 struct rcu_head *nextlist;
87 struct rcu_head **nexttail;
88 struct rcu_head *waitlist[GP_STAGES];
89 struct rcu_head **waittail[GP_STAGES];
90 struct rcu_head *donelist;
91 struct rcu_head **donetail;
92 long rcu_flipctr[2];
93#ifdef CONFIG_RCU_TRACE
94 struct rcupreempt_trace trace;
95#endif
96};
97
98
99
100
101
102enum rcu_try_flip_states {
103
104
105
106
107
108 rcu_try_flip_idle_state,
109
110
111
112
113
114
115
116
117 rcu_try_flip_waitack_state,
118
119
120
121
122
123 rcu_try_flip_waitzero_state,
124
125
126
127
128
129
130
131 rcu_try_flip_waitmb_state,
132};
133
134struct rcu_ctrlblk {
135 spinlock_t fliplock;
136 long completed;
137 enum rcu_try_flip_states rcu_try_flip_state;
138
139};
140
141static DEFINE_PER_CPU(struct rcu_data, rcu_data);
142static struct rcu_ctrlblk rcu_ctrlblk = {
143 .fliplock = __SPIN_LOCK_UNLOCKED(rcu_ctrlblk.fliplock),
144 .completed = 0,
145 .rcu_try_flip_state = rcu_try_flip_idle_state,
146};
147
148
149#ifdef CONFIG_RCU_TRACE
150static char *rcu_try_flip_state_names[] =
151 { "idle", "waitack", "waitzero", "waitmb" };
152#endif
153
154static cpumask_t rcu_cpu_online_map __read_mostly = CPU_MASK_NONE;
155
156
157
158
159
160
161enum rcu_flip_flag_values {
162 rcu_flip_seen,
163
164 rcu_flipped
165
166};
167static DEFINE_PER_CPU_SHARED_ALIGNED(enum rcu_flip_flag_values, rcu_flip_flag)
168 = rcu_flip_seen;
169
170
171
172
173
174
175
176enum rcu_mb_flag_values {
177 rcu_mb_done,
178
179 rcu_mb_needed
180
181};
182static DEFINE_PER_CPU_SHARED_ALIGNED(enum rcu_mb_flag_values, rcu_mb_flag)
183 = rcu_mb_done;
184
185
186
187
188
189#define RCU_DATA_ME() (&__get_cpu_var(rcu_data))
190#define RCU_DATA_CPU(cpu) (&per_cpu(rcu_data, cpu))
191
192
193
194
195
196#define RCU_TRACE_CPU(f, cpu) RCU_TRACE(f, &(RCU_DATA_CPU(cpu)->trace));
197
198
199
200
201
202#define RCU_TRACE_ME(f) RCU_TRACE(f, &(RCU_DATA_ME()->trace));
203
204
205
206
207
208#define RCU_TRACE_RDP(f, rdp) RCU_TRACE(f, &((rdp)->trace));
209
210
211
212
213
214long rcu_batches_completed(void)
215{
216 return rcu_ctrlblk.completed;
217}
218EXPORT_SYMBOL_GPL(rcu_batches_completed);
219
220void __rcu_read_lock(void)
221{
222 int idx;
223 struct task_struct *t = current;
224 int nesting;
225
226 nesting = ACCESS_ONCE(t->rcu_read_lock_nesting);
227 if (nesting != 0) {
228
229
230
231 t->rcu_read_lock_nesting = nesting + 1;
232
233 } else {
234 unsigned long flags;
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252 local_irq_save(flags);
253
254
255
256
257
258
259
260 idx = ACCESS_ONCE(rcu_ctrlblk.completed) & 0x1;
261 ACCESS_ONCE(RCU_DATA_ME()->rcu_flipctr[idx])++;
262
263
264
265
266
267
268
269
270
271 ACCESS_ONCE(t->rcu_read_lock_nesting) = nesting + 1;
272
273
274
275
276
277
278
279
280 ACCESS_ONCE(t->rcu_flipctr_idx) = idx;
281 local_irq_restore(flags);
282 }
283}
284EXPORT_SYMBOL_GPL(__rcu_read_lock);
285
286void __rcu_read_unlock(void)
287{
288 int idx;
289 struct task_struct *t = current;
290 int nesting;
291
292 nesting = ACCESS_ONCE(t->rcu_read_lock_nesting);
293 if (nesting > 1) {
294
295
296
297
298
299
300 t->rcu_read_lock_nesting = nesting - 1;
301
302 } else {
303 unsigned long flags;
304
305
306
307
308
309
310
311
312 local_irq_save(flags);
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331 idx = ACCESS_ONCE(t->rcu_flipctr_idx);
332
333
334
335
336
337
338
339 ACCESS_ONCE(t->rcu_read_lock_nesting) = nesting - 1;
340
341
342
343
344
345
346
347
348
349
350 ACCESS_ONCE(RCU_DATA_ME()->rcu_flipctr[idx])--;
351 local_irq_restore(flags);
352 }
353}
354EXPORT_SYMBOL_GPL(__rcu_read_unlock);
355
356
357
358
359
360
361static void __rcu_advance_callbacks(struct rcu_data *rdp)
362{
363 int cpu;
364 int i;
365 int wlc = 0;
366
367 if (rdp->completed != rcu_ctrlblk.completed) {
368 if (rdp->waitlist[GP_STAGES - 1] != NULL) {
369 *rdp->donetail = rdp->waitlist[GP_STAGES - 1];
370 rdp->donetail = rdp->waittail[GP_STAGES - 1];
371 RCU_TRACE_RDP(rcupreempt_trace_move2done, rdp);
372 }
373 for (i = GP_STAGES - 2; i >= 0; i--) {
374 if (rdp->waitlist[i] != NULL) {
375 rdp->waitlist[i + 1] = rdp->waitlist[i];
376 rdp->waittail[i + 1] = rdp->waittail[i];
377 wlc++;
378 } else {
379 rdp->waitlist[i + 1] = NULL;
380 rdp->waittail[i + 1] =
381 &rdp->waitlist[i + 1];
382 }
383 }
384 if (rdp->nextlist != NULL) {
385 rdp->waitlist[0] = rdp->nextlist;
386 rdp->waittail[0] = rdp->nexttail;
387 wlc++;
388 rdp->nextlist = NULL;
389 rdp->nexttail = &rdp->nextlist;
390 RCU_TRACE_RDP(rcupreempt_trace_move2wait, rdp);
391 } else {
392 rdp->waitlist[0] = NULL;
393 rdp->waittail[0] = &rdp->waitlist[0];
394 }
395 rdp->waitlistcount = wlc;
396 rdp->completed = rcu_ctrlblk.completed;
397 }
398
399
400
401
402
403
404
405 cpu = raw_smp_processor_id();
406 if (per_cpu(rcu_flip_flag, cpu) == rcu_flipped) {
407 smp_mb();
408 per_cpu(rcu_flip_flag, cpu) = rcu_flip_seen;
409 smp_mb();
410
411 }
412}
413
414#ifdef CONFIG_NO_HZ
415
416DEFINE_PER_CPU(long, dynticks_progress_counter) = 1;
417static DEFINE_PER_CPU(long, rcu_dyntick_snapshot);
418static DEFINE_PER_CPU(int, rcu_update_flag);
419
420
421
422
423
424
425
426
427void rcu_irq_enter(void)
428{
429 int cpu = smp_processor_id();
430
431 if (per_cpu(rcu_update_flag, cpu))
432 per_cpu(rcu_update_flag, cpu)++;
433
434
435
436
437
438 if (!in_interrupt() &&
439 (per_cpu(dynticks_progress_counter, cpu) & 0x1) == 0) {
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462 per_cpu(dynticks_progress_counter, cpu)++;
463
464
465
466
467
468
469
470
471
472 smp_mb();
473
474
475
476
477
478
479 per_cpu(rcu_update_flag, cpu)++;
480
481
482
483
484
485
486 }
487}
488
489
490
491
492
493
494
495
496void rcu_irq_exit(void)
497{
498 int cpu = smp_processor_id();
499
500
501
502
503
504
505
506
507
508
509 if (per_cpu(rcu_update_flag, cpu)) {
510 if (--per_cpu(rcu_update_flag, cpu))
511 return;
512
513
514 WARN_ON(in_interrupt());
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530 smp_mb();
531 per_cpu(dynticks_progress_counter, cpu)++;
532 WARN_ON(per_cpu(dynticks_progress_counter, cpu) & 0x1);
533 }
534}
535
536static void dyntick_save_progress_counter(int cpu)
537{
538 per_cpu(rcu_dyntick_snapshot, cpu) =
539 per_cpu(dynticks_progress_counter, cpu);
540}
541
542static inline int
543rcu_try_flip_waitack_needed(int cpu)
544{
545 long curr;
546 long snap;
547
548 curr = per_cpu(dynticks_progress_counter, cpu);
549 snap = per_cpu(rcu_dyntick_snapshot, cpu);
550 smp_mb();
551
552
553
554
555
556
557
558
559
560
561 if ((curr == snap) && ((curr & 0x1) == 0))
562 return 0;
563
564
565
566
567
568
569
570 if ((curr - snap) > 2 || (curr & 0x1) == 0)
571 return 0;
572
573
574
575 return 1;
576}
577
578static inline int
579rcu_try_flip_waitmb_needed(int cpu)
580{
581 long curr;
582 long snap;
583
584 curr = per_cpu(dynticks_progress_counter, cpu);
585 snap = per_cpu(rcu_dyntick_snapshot, cpu);
586 smp_mb();
587
588
589
590
591
592
593
594
595
596 if ((curr == snap) && ((curr & 0x1) == 0))
597 return 0;
598
599
600
601
602
603
604 if (curr != snap)
605 return 0;
606
607
608
609 return 1;
610}
611
612#else
613
614# define dyntick_save_progress_counter(cpu) do { } while (0)
615# define rcu_try_flip_waitack_needed(cpu) (1)
616# define rcu_try_flip_waitmb_needed(cpu) (1)
617
618#endif
619
620
621
622
623
624
625
626
627
628
629
630static int
631rcu_try_flip_idle(void)
632{
633 int cpu;
634
635 RCU_TRACE_ME(rcupreempt_trace_try_flip_i1);
636 if (!rcu_pending(smp_processor_id())) {
637 RCU_TRACE_ME(rcupreempt_trace_try_flip_ie1);
638 return 0;
639 }
640
641
642
643
644
645 RCU_TRACE_ME(rcupreempt_trace_try_flip_g1);
646 rcu_ctrlblk.completed++;
647
648
649
650
651
652
653
654 smp_mb();
655
656
657
658 for_each_cpu_mask(cpu, rcu_cpu_online_map) {
659 per_cpu(rcu_flip_flag, cpu) = rcu_flipped;
660 dyntick_save_progress_counter(cpu);
661 }
662
663 return 1;
664}
665
666
667
668
669
670static int
671rcu_try_flip_waitack(void)
672{
673 int cpu;
674
675 RCU_TRACE_ME(rcupreempt_trace_try_flip_a1);
676 for_each_cpu_mask(cpu, rcu_cpu_online_map)
677 if (rcu_try_flip_waitack_needed(cpu) &&
678 per_cpu(rcu_flip_flag, cpu) != rcu_flip_seen) {
679 RCU_TRACE_ME(rcupreempt_trace_try_flip_ae1);
680 return 0;
681 }
682
683
684
685
686
687
688 smp_mb();
689 RCU_TRACE_ME(rcupreempt_trace_try_flip_a2);
690 return 1;
691}
692
693
694
695
696
697
698static int
699rcu_try_flip_waitzero(void)
700{
701 int cpu;
702 int lastidx = !(rcu_ctrlblk.completed & 0x1);
703 int sum = 0;
704
705
706
707 RCU_TRACE_ME(rcupreempt_trace_try_flip_z1);
708 for_each_cpu_mask(cpu, rcu_cpu_online_map)
709 sum += RCU_DATA_CPU(cpu)->rcu_flipctr[lastidx];
710 if (sum != 0) {
711 RCU_TRACE_ME(rcupreempt_trace_try_flip_ze1);
712 return 0;
713 }
714
715
716
717
718
719
720 smp_mb();
721
722
723 for_each_cpu_mask(cpu, rcu_cpu_online_map) {
724 per_cpu(rcu_mb_flag, cpu) = rcu_mb_needed;
725 dyntick_save_progress_counter(cpu);
726 }
727
728 RCU_TRACE_ME(rcupreempt_trace_try_flip_z2);
729 return 1;
730}
731
732
733
734
735
736
737static int
738rcu_try_flip_waitmb(void)
739{
740 int cpu;
741
742 RCU_TRACE_ME(rcupreempt_trace_try_flip_m1);
743 for_each_cpu_mask(cpu, rcu_cpu_online_map)
744 if (rcu_try_flip_waitmb_needed(cpu) &&
745 per_cpu(rcu_mb_flag, cpu) != rcu_mb_done) {
746 RCU_TRACE_ME(rcupreempt_trace_try_flip_me1);
747 return 0;
748 }
749
750 smp_mb();
751 RCU_TRACE_ME(rcupreempt_trace_try_flip_m2);
752 return 1;
753}
754
755
756
757
758
759
760
761
762
763
764static void rcu_try_flip(void)
765{
766 unsigned long flags;
767
768 RCU_TRACE_ME(rcupreempt_trace_try_flip_1);
769 if (unlikely(!spin_trylock_irqsave(&rcu_ctrlblk.fliplock, flags))) {
770 RCU_TRACE_ME(rcupreempt_trace_try_flip_e1);
771 return;
772 }
773
774
775
776
777
778
779 switch (rcu_ctrlblk.rcu_try_flip_state) {
780 case rcu_try_flip_idle_state:
781 if (rcu_try_flip_idle())
782 rcu_ctrlblk.rcu_try_flip_state =
783 rcu_try_flip_waitack_state;
784 break;
785 case rcu_try_flip_waitack_state:
786 if (rcu_try_flip_waitack())
787 rcu_ctrlblk.rcu_try_flip_state =
788 rcu_try_flip_waitzero_state;
789 break;
790 case rcu_try_flip_waitzero_state:
791 if (rcu_try_flip_waitzero())
792 rcu_ctrlblk.rcu_try_flip_state =
793 rcu_try_flip_waitmb_state;
794 break;
795 case rcu_try_flip_waitmb_state:
796 if (rcu_try_flip_waitmb())
797 rcu_ctrlblk.rcu_try_flip_state =
798 rcu_try_flip_idle_state;
799 }
800 spin_unlock_irqrestore(&rcu_ctrlblk.fliplock, flags);
801}
802
803
804
805
806
807
808
809static void rcu_check_mb(int cpu)
810{
811 if (per_cpu(rcu_mb_flag, cpu) == rcu_mb_needed) {
812 smp_mb();
813 per_cpu(rcu_mb_flag, cpu) = rcu_mb_done;
814 }
815}
816
817void rcu_check_callbacks(int cpu, int user)
818{
819 unsigned long flags;
820 struct rcu_data *rdp = RCU_DATA_CPU(cpu);
821
822 rcu_check_mb(cpu);
823 if (rcu_ctrlblk.completed == rdp->completed)
824 rcu_try_flip();
825 spin_lock_irqsave(&rdp->lock, flags);
826 RCU_TRACE_RDP(rcupreempt_trace_check_callbacks, rdp);
827 __rcu_advance_callbacks(rdp);
828 if (rdp->donelist == NULL) {
829 spin_unlock_irqrestore(&rdp->lock, flags);
830 } else {
831 spin_unlock_irqrestore(&rdp->lock, flags);
832 raise_softirq(RCU_SOFTIRQ);
833 }
834}
835
836
837
838
839
840void rcu_advance_callbacks(int cpu, int user)
841{
842 unsigned long flags;
843 struct rcu_data *rdp = RCU_DATA_CPU(cpu);
844
845 if (rcu_ctrlblk.completed == rdp->completed) {
846 rcu_try_flip();
847 if (rcu_ctrlblk.completed == rdp->completed)
848 return;
849 }
850 spin_lock_irqsave(&rdp->lock, flags);
851 RCU_TRACE_RDP(rcupreempt_trace_check_callbacks, rdp);
852 __rcu_advance_callbacks(rdp);
853 spin_unlock_irqrestore(&rdp->lock, flags);
854}
855
856#ifdef CONFIG_HOTPLUG_CPU
857#define rcu_offline_cpu_enqueue(srclist, srctail, dstlist, dsttail) do { \
858 *dsttail = srclist; \
859 if (srclist != NULL) { \
860 dsttail = srctail; \
861 srclist = NULL; \
862 srctail = &srclist;\
863 } \
864 } while (0)
865
866void rcu_offline_cpu(int cpu)
867{
868 int i;
869 struct rcu_head *list = NULL;
870 unsigned long flags;
871 struct rcu_data *rdp = RCU_DATA_CPU(cpu);
872 struct rcu_head **tail = &list;
873
874
875
876
877
878
879 spin_lock_irqsave(&rdp->lock, flags);
880 rcu_offline_cpu_enqueue(rdp->donelist, rdp->donetail, list, tail);
881 for (i = GP_STAGES - 1; i >= 0; i--)
882 rcu_offline_cpu_enqueue(rdp->waitlist[i], rdp->waittail[i],
883 list, tail);
884 rcu_offline_cpu_enqueue(rdp->nextlist, rdp->nexttail, list, tail);
885 spin_unlock_irqrestore(&rdp->lock, flags);
886 rdp->waitlistcount = 0;
887
888
889
890 spin_lock_irqsave(&rcu_ctrlblk.fliplock, flags);
891 rcu_check_mb(cpu);
892 if (per_cpu(rcu_flip_flag, cpu) == rcu_flipped) {
893 smp_mb();
894 per_cpu(rcu_flip_flag, cpu) = rcu_flip_seen;
895 smp_mb();
896
897 }
898
899 RCU_DATA_ME()->rcu_flipctr[0] += RCU_DATA_CPU(cpu)->rcu_flipctr[0];
900 RCU_DATA_ME()->rcu_flipctr[1] += RCU_DATA_CPU(cpu)->rcu_flipctr[1];
901
902 RCU_DATA_CPU(cpu)->rcu_flipctr[0] = 0;
903 RCU_DATA_CPU(cpu)->rcu_flipctr[1] = 0;
904
905 cpu_clear(cpu, rcu_cpu_online_map);
906
907 spin_unlock_irqrestore(&rcu_ctrlblk.fliplock, flags);
908
909
910
911
912
913
914
915
916
917
918
919 local_irq_save(flags);
920 rdp = RCU_DATA_ME();
921 spin_lock(&rdp->lock);
922 *rdp->nexttail = list;
923 if (list)
924 rdp->nexttail = tail;
925 spin_unlock_irqrestore(&rdp->lock, flags);
926}
927
928#else
929
930void rcu_offline_cpu(int cpu)
931{
932}
933
934#endif
935
936void __cpuinit rcu_online_cpu(int cpu)
937{
938 unsigned long flags;
939
940 spin_lock_irqsave(&rcu_ctrlblk.fliplock, flags);
941 cpu_set(cpu, rcu_cpu_online_map);
942 spin_unlock_irqrestore(&rcu_ctrlblk.fliplock, flags);
943}
944
945static void rcu_process_callbacks(struct softirq_action *unused)
946{
947 unsigned long flags;
948 struct rcu_head *next, *list;
949 struct rcu_data *rdp;
950
951 local_irq_save(flags);
952 rdp = RCU_DATA_ME();
953 spin_lock(&rdp->lock);
954 list = rdp->donelist;
955 if (list == NULL) {
956 spin_unlock_irqrestore(&rdp->lock, flags);
957 return;
958 }
959 rdp->donelist = NULL;
960 rdp->donetail = &rdp->donelist;
961 RCU_TRACE_RDP(rcupreempt_trace_done_remove, rdp);
962 spin_unlock_irqrestore(&rdp->lock, flags);
963 while (list) {
964 next = list->next;
965 list->func(list);
966 list = next;
967 RCU_TRACE_ME(rcupreempt_trace_invoke);
968 }
969}
970
971void call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu))
972{
973 unsigned long flags;
974 struct rcu_data *rdp;
975
976 head->func = func;
977 head->next = NULL;
978 local_irq_save(flags);
979 rdp = RCU_DATA_ME();
980 spin_lock(&rdp->lock);
981 __rcu_advance_callbacks(rdp);
982 *rdp->nexttail = head;
983 rdp->nexttail = &head->next;
984 RCU_TRACE_RDP(rcupreempt_trace_next_add, rdp);
985 spin_unlock(&rdp->lock);
986 local_irq_restore(flags);
987}
988EXPORT_SYMBOL_GPL(call_rcu);
989
990
991
992
993
994
995
996void __synchronize_sched(void)
997{
998 cpumask_t oldmask;
999 int cpu;
1000
1001 if (sched_getaffinity(0, &oldmask) < 0)
1002 oldmask = cpu_possible_map;
1003 for_each_online_cpu(cpu) {
1004 sched_setaffinity(0, &cpumask_of_cpu(cpu));
1005 schedule();
1006 }
1007 sched_setaffinity(0, &oldmask);
1008}
1009EXPORT_SYMBOL_GPL(__synchronize_sched);
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020int rcu_needs_cpu(int cpu)
1021{
1022 struct rcu_data *rdp = RCU_DATA_CPU(cpu);
1023
1024 return (rdp->donelist != NULL ||
1025 !!rdp->waitlistcount ||
1026 rdp->nextlist != NULL);
1027}
1028
1029int rcu_pending(int cpu)
1030{
1031 struct rcu_data *rdp = RCU_DATA_CPU(cpu);
1032
1033
1034
1035 if (rdp->donelist != NULL ||
1036 !!rdp->waitlistcount ||
1037 rdp->nextlist != NULL)
1038 return 1;
1039
1040
1041
1042 if ((per_cpu(rcu_flip_flag, cpu) == rcu_flipped) ||
1043 (per_cpu(rcu_mb_flag, cpu) == rcu_mb_needed))
1044 return 1;
1045
1046
1047
1048 if (rdp->completed != rcu_ctrlblk.completed)
1049 return 1;
1050
1051
1052
1053 return 0;
1054}
1055
1056static int __cpuinit rcu_cpu_notify(struct notifier_block *self,
1057 unsigned long action, void *hcpu)
1058{
1059 long cpu = (long)hcpu;
1060
1061 switch (action) {
1062 case CPU_UP_PREPARE:
1063 case CPU_UP_PREPARE_FROZEN:
1064 rcu_online_cpu(cpu);
1065 break;
1066 case CPU_UP_CANCELED:
1067 case CPU_UP_CANCELED_FROZEN:
1068 case CPU_DEAD:
1069 case CPU_DEAD_FROZEN:
1070 rcu_offline_cpu(cpu);
1071 break;
1072 default:
1073 break;
1074 }
1075 return NOTIFY_OK;
1076}
1077
1078static struct notifier_block __cpuinitdata rcu_nb = {
1079 .notifier_call = rcu_cpu_notify,
1080};
1081
1082void __init __rcu_init(void)
1083{
1084 int cpu;
1085 int i;
1086 struct rcu_data *rdp;
1087
1088 printk(KERN_NOTICE "Preemptible RCU implementation.\n");
1089 for_each_possible_cpu(cpu) {
1090 rdp = RCU_DATA_CPU(cpu);
1091 spin_lock_init(&rdp->lock);
1092 rdp->completed = 0;
1093 rdp->waitlistcount = 0;
1094 rdp->nextlist = NULL;
1095 rdp->nexttail = &rdp->nextlist;
1096 for (i = 0; i < GP_STAGES; i++) {
1097 rdp->waitlist[i] = NULL;
1098 rdp->waittail[i] = &rdp->waitlist[i];
1099 }
1100 rdp->donelist = NULL;
1101 rdp->donetail = &rdp->donelist;
1102 rdp->rcu_flipctr[0] = 0;
1103 rdp->rcu_flipctr[1] = 0;
1104 }
1105 register_cpu_notifier(&rcu_nb);
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119 for_each_online_cpu(cpu)
1120 rcu_cpu_notify(&rcu_nb, CPU_UP_PREPARE, (void *)(long) cpu);
1121
1122 open_softirq(RCU_SOFTIRQ, rcu_process_callbacks, NULL);
1123}
1124
1125
1126
1127
1128void synchronize_kernel(void)
1129{
1130 synchronize_rcu();
1131}
1132
1133#ifdef CONFIG_RCU_TRACE
1134long *rcupreempt_flipctr(int cpu)
1135{
1136 return &RCU_DATA_CPU(cpu)->rcu_flipctr[0];
1137}
1138EXPORT_SYMBOL_GPL(rcupreempt_flipctr);
1139
1140int rcupreempt_flip_flag(int cpu)
1141{
1142 return per_cpu(rcu_flip_flag, cpu);
1143}
1144EXPORT_SYMBOL_GPL(rcupreempt_flip_flag);
1145
1146int rcupreempt_mb_flag(int cpu)
1147{
1148 return per_cpu(rcu_mb_flag, cpu);
1149}
1150EXPORT_SYMBOL_GPL(rcupreempt_mb_flag);
1151
1152char *rcupreempt_try_flip_state_name(void)
1153{
1154 return rcu_try_flip_state_names[rcu_ctrlblk.rcu_try_flip_state];
1155}
1156EXPORT_SYMBOL_GPL(rcupreempt_try_flip_state_name);
1157
1158struct rcupreempt_trace *rcupreempt_trace_cpu(int cpu)
1159{
1160 struct rcu_data *rdp = RCU_DATA_CPU(cpu);
1161
1162 return &rdp->trace;
1163}
1164EXPORT_SYMBOL_GPL(rcupreempt_trace_cpu);
1165
1166#endif
1167