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/kthread.h>
26#include <linux/module.h>
27#include <linux/debugfs.h>
28#include <linux/seq_file.h>
29
30
31struct rcu_ctrlblk {
32 struct rcu_head *rcucblist;
33 struct rcu_head **donetail;
34 struct rcu_head **curtail;
35 RCU_TRACE(long qlen);
36 RCU_TRACE(char *name);
37};
38
39
40static struct rcu_ctrlblk rcu_sched_ctrlblk = {
41 .donetail = &rcu_sched_ctrlblk.rcucblist,
42 .curtail = &rcu_sched_ctrlblk.rcucblist,
43 RCU_TRACE(.name = "rcu_sched")
44};
45
46static struct rcu_ctrlblk rcu_bh_ctrlblk = {
47 .donetail = &rcu_bh_ctrlblk.rcucblist,
48 .curtail = &rcu_bh_ctrlblk.rcucblist,
49 RCU_TRACE(.name = "rcu_bh")
50};
51
52#ifdef CONFIG_DEBUG_LOCK_ALLOC
53int rcu_scheduler_active __read_mostly;
54EXPORT_SYMBOL_GPL(rcu_scheduler_active);
55#endif
56
57#ifdef CONFIG_TINY_PREEMPT_RCU
58
59#include <linux/delay.h>
60
61
62struct rcu_preempt_ctrlblk {
63 struct rcu_ctrlblk rcb;
64 struct rcu_head **nexttail;
65
66
67
68
69
70
71
72
73
74 struct list_head blkd_tasks;
75
76
77
78 struct list_head *gp_tasks;
79
80
81
82 struct list_head *exp_tasks;
83
84
85
86
87
88#ifdef CONFIG_RCU_BOOST
89 struct list_head *boost_tasks;
90
91
92
93
94
95#endif
96 u8 gpnum;
97 u8 gpcpu;
98 u8 completed;
99
100#ifdef CONFIG_RCU_BOOST
101 unsigned long boost_time;
102#endif
103#ifdef CONFIG_RCU_TRACE
104 unsigned long n_grace_periods;
105#ifdef CONFIG_RCU_BOOST
106 unsigned long n_tasks_boosted;
107
108 unsigned long n_exp_boosts;
109
110 unsigned long n_normal_boosts;
111
112 unsigned long n_balk_blkd_tasks;
113
114 unsigned long n_balk_exp_gp_tasks;
115
116 unsigned long n_balk_boost_tasks;
117
118 unsigned long n_balk_notyet;
119
120 unsigned long n_balk_nos;
121
122
123#endif
124#endif
125};
126
127static struct rcu_preempt_ctrlblk rcu_preempt_ctrlblk = {
128 .rcb.donetail = &rcu_preempt_ctrlblk.rcb.rcucblist,
129 .rcb.curtail = &rcu_preempt_ctrlblk.rcb.rcucblist,
130 .nexttail = &rcu_preempt_ctrlblk.rcb.rcucblist,
131 .blkd_tasks = LIST_HEAD_INIT(rcu_preempt_ctrlblk.blkd_tasks),
132 RCU_TRACE(.rcb.name = "rcu_preempt")
133};
134
135static void rcu_read_unlock_special(struct task_struct *t);
136static int rcu_preempted_readers_exp(void);
137static void rcu_report_exp_done(void);
138
139
140
141
142static int rcu_cpu_blocking_cur_gp(void)
143{
144 return rcu_preempt_ctrlblk.gpcpu != rcu_preempt_ctrlblk.gpnum;
145}
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161static int rcu_preempt_running_reader(void)
162{
163 return current->rcu_read_lock_nesting;
164}
165
166
167
168
169
170static int rcu_preempt_blocked_readers_any(void)
171{
172 return !list_empty(&rcu_preempt_ctrlblk.blkd_tasks);
173}
174
175
176
177
178
179static int rcu_preempt_blocked_readers_cgp(void)
180{
181 return rcu_preempt_ctrlblk.gp_tasks != NULL;
182}
183
184
185
186
187static int rcu_preempt_needs_another_gp(void)
188{
189 return *rcu_preempt_ctrlblk.rcb.curtail != NULL;
190}
191
192
193
194
195
196static int rcu_preempt_gp_in_progress(void)
197{
198 return rcu_preempt_ctrlblk.completed != rcu_preempt_ctrlblk.gpnum;
199}
200
201
202
203
204
205static struct list_head *rcu_next_node_entry(struct task_struct *t)
206{
207 struct list_head *np;
208
209 np = t->rcu_node_entry.next;
210 if (np == &rcu_preempt_ctrlblk.blkd_tasks)
211 np = NULL;
212 return np;
213}
214
215#ifdef CONFIG_RCU_TRACE
216
217#ifdef CONFIG_RCU_BOOST
218static void rcu_initiate_boost_trace(void);
219#endif
220
221
222
223
224static void show_tiny_preempt_stats(struct seq_file *m)
225{
226 seq_printf(m, "rcu_preempt: qlen=%ld gp=%lu g%u/p%u/c%u tasks=%c%c%c\n",
227 rcu_preempt_ctrlblk.rcb.qlen,
228 rcu_preempt_ctrlblk.n_grace_periods,
229 rcu_preempt_ctrlblk.gpnum,
230 rcu_preempt_ctrlblk.gpcpu,
231 rcu_preempt_ctrlblk.completed,
232 "T."[list_empty(&rcu_preempt_ctrlblk.blkd_tasks)],
233 "N."[!rcu_preempt_ctrlblk.gp_tasks],
234 "E."[!rcu_preempt_ctrlblk.exp_tasks]);
235#ifdef CONFIG_RCU_BOOST
236 seq_printf(m, "%sttb=%c ntb=%lu neb=%lu nnb=%lu j=%04x bt=%04x\n",
237 " ",
238 "B."[!rcu_preempt_ctrlblk.boost_tasks],
239 rcu_preempt_ctrlblk.n_tasks_boosted,
240 rcu_preempt_ctrlblk.n_exp_boosts,
241 rcu_preempt_ctrlblk.n_normal_boosts,
242 (int)(jiffies & 0xffff),
243 (int)(rcu_preempt_ctrlblk.boost_time & 0xffff));
244 seq_printf(m, "%s: nt=%lu egt=%lu bt=%lu ny=%lu nos=%lu\n",
245 " balk",
246 rcu_preempt_ctrlblk.n_balk_blkd_tasks,
247 rcu_preempt_ctrlblk.n_balk_exp_gp_tasks,
248 rcu_preempt_ctrlblk.n_balk_boost_tasks,
249 rcu_preempt_ctrlblk.n_balk_notyet,
250 rcu_preempt_ctrlblk.n_balk_nos);
251#endif
252}
253
254#endif
255
256#ifdef CONFIG_RCU_BOOST
257
258#include "rtmutex_common.h"
259
260#define RCU_BOOST_PRIO CONFIG_RCU_BOOST_PRIO
261
262
263static struct task_struct *rcu_kthread_task;
264static DECLARE_WAIT_QUEUE_HEAD(rcu_kthread_wq);
265static unsigned long have_rcu_kthread_work;
266
267
268
269
270
271static int rcu_boost(void)
272{
273 unsigned long flags;
274 struct rt_mutex mtx;
275 struct task_struct *t;
276 struct list_head *tb;
277
278 if (rcu_preempt_ctrlblk.boost_tasks == NULL &&
279 rcu_preempt_ctrlblk.exp_tasks == NULL)
280 return 0;
281
282 raw_local_irq_save(flags);
283
284
285
286
287
288
289 if (rcu_preempt_ctrlblk.boost_tasks == NULL &&
290 rcu_preempt_ctrlblk.exp_tasks == NULL) {
291 raw_local_irq_restore(flags);
292 return 0;
293 }
294
295
296
297
298
299
300
301 if (rcu_preempt_ctrlblk.exp_tasks != NULL) {
302 tb = rcu_preempt_ctrlblk.exp_tasks;
303 RCU_TRACE(rcu_preempt_ctrlblk.n_exp_boosts++);
304 } else {
305 tb = rcu_preempt_ctrlblk.boost_tasks;
306 RCU_TRACE(rcu_preempt_ctrlblk.n_normal_boosts++);
307 }
308 RCU_TRACE(rcu_preempt_ctrlblk.n_tasks_boosted++);
309
310
311
312
313
314
315
316
317
318 t = container_of(tb, struct task_struct, rcu_node_entry);
319 rt_mutex_init_proxy_locked(&mtx, t);
320 t->rcu_boost_mutex = &mtx;
321 raw_local_irq_restore(flags);
322 rt_mutex_lock(&mtx);
323 rt_mutex_unlock(&mtx);
324
325 return ACCESS_ONCE(rcu_preempt_ctrlblk.boost_tasks) != NULL ||
326 ACCESS_ONCE(rcu_preempt_ctrlblk.exp_tasks) != NULL;
327}
328
329
330
331
332
333
334
335
336
337
338
339static int rcu_initiate_boost(void)
340{
341 if (!rcu_preempt_blocked_readers_cgp() &&
342 rcu_preempt_ctrlblk.exp_tasks == NULL) {
343 RCU_TRACE(rcu_preempt_ctrlblk.n_balk_exp_gp_tasks++);
344 return 0;
345 }
346 if (rcu_preempt_ctrlblk.exp_tasks != NULL ||
347 (rcu_preempt_ctrlblk.gp_tasks != NULL &&
348 rcu_preempt_ctrlblk.boost_tasks == NULL &&
349 ULONG_CMP_GE(jiffies, rcu_preempt_ctrlblk.boost_time))) {
350 if (rcu_preempt_ctrlblk.exp_tasks == NULL)
351 rcu_preempt_ctrlblk.boost_tasks =
352 rcu_preempt_ctrlblk.gp_tasks;
353 invoke_rcu_callbacks();
354 } else
355 RCU_TRACE(rcu_initiate_boost_trace());
356 return 1;
357}
358
359#define RCU_BOOST_DELAY_JIFFIES DIV_ROUND_UP(CONFIG_RCU_BOOST_DELAY * HZ, 1000)
360
361
362
363
364static void rcu_preempt_boost_start_gp(void)
365{
366 rcu_preempt_ctrlblk.boost_time = jiffies + RCU_BOOST_DELAY_JIFFIES;
367}
368
369#else
370
371
372
373
374
375
376static int rcu_initiate_boost(void)
377{
378 return rcu_preempt_blocked_readers_cgp();
379}
380
381
382
383
384static void rcu_preempt_boost_start_gp(void)
385{
386}
387
388#endif
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411static void rcu_preempt_cpu_qs(void)
412{
413
414 rcu_preempt_ctrlblk.gpcpu = rcu_preempt_ctrlblk.gpnum;
415 current->rcu_read_unlock_special &= ~RCU_READ_UNLOCK_NEED_QS;
416
417
418 if (!rcu_preempt_gp_in_progress())
419 return;
420
421
422
423
424 if (rcu_initiate_boost())
425 return;
426
427
428 rcu_preempt_ctrlblk.completed = rcu_preempt_ctrlblk.gpnum;
429 rcu_preempt_ctrlblk.rcb.donetail = rcu_preempt_ctrlblk.rcb.curtail;
430 rcu_preempt_ctrlblk.rcb.curtail = rcu_preempt_ctrlblk.nexttail;
431
432
433 if (!rcu_preempt_blocked_readers_any())
434 rcu_preempt_ctrlblk.rcb.donetail = rcu_preempt_ctrlblk.nexttail;
435
436
437 if (*rcu_preempt_ctrlblk.rcb.donetail != NULL)
438 invoke_rcu_callbacks();
439}
440
441
442
443
444static void rcu_preempt_start_gp(void)
445{
446 if (!rcu_preempt_gp_in_progress() && rcu_preempt_needs_another_gp()) {
447
448
449 rcu_preempt_ctrlblk.gpnum++;
450 RCU_TRACE(rcu_preempt_ctrlblk.n_grace_periods++);
451
452
453 if (rcu_preempt_blocked_readers_any())
454 rcu_preempt_ctrlblk.gp_tasks =
455 rcu_preempt_ctrlblk.blkd_tasks.next;
456
457
458 rcu_preempt_boost_start_gp();
459
460
461 if (!rcu_preempt_running_reader())
462 rcu_preempt_cpu_qs();
463 }
464}
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482void rcu_preempt_note_context_switch(void)
483{
484 struct task_struct *t = current;
485 unsigned long flags;
486
487 local_irq_save(flags);
488 if (rcu_preempt_running_reader() > 0 &&
489 (t->rcu_read_unlock_special & RCU_READ_UNLOCK_BLOCKED) == 0) {
490
491
492 t->rcu_read_unlock_special |= RCU_READ_UNLOCK_BLOCKED;
493
494
495
496
497
498
499
500
501
502
503
504 list_add(&t->rcu_node_entry, &rcu_preempt_ctrlblk.blkd_tasks);
505 if (rcu_cpu_blocking_cur_gp())
506 rcu_preempt_ctrlblk.gp_tasks = &t->rcu_node_entry;
507 } else if (rcu_preempt_running_reader() < 0 &&
508 t->rcu_read_unlock_special) {
509
510
511
512
513 rcu_read_unlock_special(t);
514 }
515
516
517
518
519
520
521
522
523
524
525 rcu_preempt_cpu_qs();
526 local_irq_restore(flags);
527}
528
529
530
531
532
533
534void __rcu_read_lock(void)
535{
536 current->rcu_read_lock_nesting++;
537 barrier();
538}
539EXPORT_SYMBOL_GPL(__rcu_read_lock);
540
541
542
543
544
545
546static noinline void rcu_read_unlock_special(struct task_struct *t)
547{
548 int empty;
549 int empty_exp;
550 unsigned long flags;
551 struct list_head *np;
552#ifdef CONFIG_RCU_BOOST
553 struct rt_mutex *rbmp = NULL;
554#endif
555 int special;
556
557
558
559
560
561 if (in_nmi())
562 return;
563
564 local_irq_save(flags);
565
566
567
568
569
570 special = t->rcu_read_unlock_special;
571 if (special & RCU_READ_UNLOCK_NEED_QS)
572 rcu_preempt_cpu_qs();
573
574
575 if (in_irq() || in_serving_softirq()) {
576 local_irq_restore(flags);
577 return;
578 }
579
580
581 if (special & RCU_READ_UNLOCK_BLOCKED) {
582 t->rcu_read_unlock_special &= ~RCU_READ_UNLOCK_BLOCKED;
583
584
585
586
587
588 empty = !rcu_preempt_blocked_readers_cgp();
589 empty_exp = rcu_preempt_ctrlblk.exp_tasks == NULL;
590 np = rcu_next_node_entry(t);
591 list_del_init(&t->rcu_node_entry);
592 if (&t->rcu_node_entry == rcu_preempt_ctrlblk.gp_tasks)
593 rcu_preempt_ctrlblk.gp_tasks = np;
594 if (&t->rcu_node_entry == rcu_preempt_ctrlblk.exp_tasks)
595 rcu_preempt_ctrlblk.exp_tasks = np;
596#ifdef CONFIG_RCU_BOOST
597 if (&t->rcu_node_entry == rcu_preempt_ctrlblk.boost_tasks)
598 rcu_preempt_ctrlblk.boost_tasks = np;
599#endif
600
601
602
603
604
605
606 if (!empty && !rcu_preempt_blocked_readers_cgp()) {
607 rcu_preempt_cpu_qs();
608 rcu_preempt_start_gp();
609 }
610
611
612
613
614
615 if (!empty_exp && rcu_preempt_ctrlblk.exp_tasks == NULL)
616 rcu_report_exp_done();
617 }
618#ifdef CONFIG_RCU_BOOST
619
620 if (t->rcu_boost_mutex != NULL) {
621 rbmp = t->rcu_boost_mutex;
622 t->rcu_boost_mutex = NULL;
623 rt_mutex_unlock(rbmp);
624 }
625#endif
626 local_irq_restore(flags);
627}
628
629
630
631
632
633
634
635
636void __rcu_read_unlock(void)
637{
638 struct task_struct *t = current;
639
640 barrier();
641 if (t->rcu_read_lock_nesting != 1)
642 --t->rcu_read_lock_nesting;
643 else {
644 t->rcu_read_lock_nesting = INT_MIN;
645 barrier();
646 if (unlikely(ACCESS_ONCE(t->rcu_read_unlock_special)))
647 rcu_read_unlock_special(t);
648 barrier();
649 t->rcu_read_lock_nesting = 0;
650 }
651#ifdef CONFIG_PROVE_LOCKING
652 {
653 int rrln = ACCESS_ONCE(t->rcu_read_lock_nesting);
654
655 WARN_ON_ONCE(rrln < 0 && rrln > INT_MIN / 2);
656 }
657#endif
658}
659EXPORT_SYMBOL_GPL(__rcu_read_unlock);
660
661
662
663
664
665
666
667
668static void rcu_preempt_check_callbacks(void)
669{
670 struct task_struct *t = current;
671
672 if (rcu_preempt_gp_in_progress() &&
673 (!rcu_preempt_running_reader() ||
674 !rcu_cpu_blocking_cur_gp()))
675 rcu_preempt_cpu_qs();
676 if (&rcu_preempt_ctrlblk.rcb.rcucblist !=
677 rcu_preempt_ctrlblk.rcb.donetail)
678 invoke_rcu_callbacks();
679 if (rcu_preempt_gp_in_progress() &&
680 rcu_cpu_blocking_cur_gp() &&
681 rcu_preempt_running_reader() > 0)
682 t->rcu_read_unlock_special |= RCU_READ_UNLOCK_NEED_QS;
683}
684
685
686
687
688
689
690
691
692
693static void rcu_preempt_remove_callbacks(struct rcu_ctrlblk *rcp)
694{
695 if (rcu_preempt_ctrlblk.nexttail == rcp->donetail)
696 rcu_preempt_ctrlblk.nexttail = &rcp->rcucblist;
697}
698
699
700
701
702static void rcu_preempt_process_callbacks(void)
703{
704 __rcu_process_callbacks(&rcu_preempt_ctrlblk.rcb);
705}
706
707
708
709
710void call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu))
711{
712 unsigned long flags;
713
714 debug_rcu_head_queue(head);
715 head->func = func;
716 head->next = NULL;
717
718 local_irq_save(flags);
719 *rcu_preempt_ctrlblk.nexttail = head;
720 rcu_preempt_ctrlblk.nexttail = &head->next;
721 RCU_TRACE(rcu_preempt_ctrlblk.rcb.qlen++);
722 rcu_preempt_start_gp();
723 local_irq_restore(flags);
724}
725EXPORT_SYMBOL_GPL(call_rcu);
726
727
728
729
730
731
732
733
734
735
736void synchronize_rcu(void)
737{
738 rcu_lockdep_assert(!lock_is_held(&rcu_bh_lock_map) &&
739 !lock_is_held(&rcu_lock_map) &&
740 !lock_is_held(&rcu_sched_lock_map),
741 "Illegal synchronize_rcu() in RCU read-side critical section");
742
743#ifdef CONFIG_DEBUG_LOCK_ALLOC
744 if (!rcu_scheduler_active)
745 return;
746#endif
747
748 WARN_ON_ONCE(rcu_preempt_running_reader());
749 if (!rcu_preempt_blocked_readers_any())
750 return;
751
752
753 rcu_barrier();
754}
755EXPORT_SYMBOL_GPL(synchronize_rcu);
756
757static DECLARE_WAIT_QUEUE_HEAD(sync_rcu_preempt_exp_wq);
758static unsigned long sync_rcu_preempt_exp_count;
759static DEFINE_MUTEX(sync_rcu_preempt_exp_mutex);
760
761
762
763
764
765
766
767static int rcu_preempted_readers_exp(void)
768{
769 return rcu_preempt_ctrlblk.exp_tasks != NULL;
770}
771
772
773
774
775
776
777static void rcu_report_exp_done(void)
778{
779 wake_up(&sync_rcu_preempt_exp_wq);
780}
781
782
783
784
785
786
787
788
789
790
791
792void synchronize_rcu_expedited(void)
793{
794 unsigned long flags;
795 struct rcu_preempt_ctrlblk *rpcp = &rcu_preempt_ctrlblk;
796 unsigned long snap;
797
798 barrier();
799
800 WARN_ON_ONCE(rcu_preempt_running_reader());
801
802
803
804
805
806
807 snap = sync_rcu_preempt_exp_count + 1;
808 mutex_lock(&sync_rcu_preempt_exp_mutex);
809 if (ULONG_CMP_LT(snap, sync_rcu_preempt_exp_count))
810 goto unlock_mb_ret;
811
812 local_irq_save(flags);
813
814
815
816
817
818
819
820
821 rpcp->exp_tasks = rpcp->blkd_tasks.next;
822 if (rpcp->exp_tasks == &rpcp->blkd_tasks)
823 rpcp->exp_tasks = NULL;
824
825
826 if (!rcu_preempted_readers_exp())
827 local_irq_restore(flags);
828 else {
829 rcu_initiate_boost();
830 local_irq_restore(flags);
831 wait_event(sync_rcu_preempt_exp_wq,
832 !rcu_preempted_readers_exp());
833 }
834
835
836 barrier();
837 sync_rcu_preempt_exp_count++;
838unlock_mb_ret:
839 mutex_unlock(&sync_rcu_preempt_exp_mutex);
840 barrier();
841}
842EXPORT_SYMBOL_GPL(synchronize_rcu_expedited);
843
844
845
846
847int rcu_preempt_needs_cpu(void)
848{
849 if (!rcu_preempt_running_reader())
850 rcu_preempt_cpu_qs();
851 return rcu_preempt_ctrlblk.rcb.rcucblist != NULL;
852}
853
854#else
855
856#ifdef CONFIG_RCU_TRACE
857
858
859
860
861
862static void show_tiny_preempt_stats(struct seq_file *m)
863{
864}
865
866#endif
867
868
869
870
871
872static void rcu_preempt_check_callbacks(void)
873{
874}
875
876
877
878
879
880static void rcu_preempt_remove_callbacks(struct rcu_ctrlblk *rcp)
881{
882}
883
884
885
886
887
888static void rcu_preempt_process_callbacks(void)
889{
890}
891
892#endif
893
894#ifdef CONFIG_RCU_BOOST
895
896
897
898
899
900static void invoke_rcu_callbacks(void)
901{
902 have_rcu_kthread_work = 1;
903 if (rcu_kthread_task != NULL)
904 wake_up(&rcu_kthread_wq);
905}
906
907#ifdef CONFIG_RCU_TRACE
908
909
910
911
912
913static bool rcu_is_callbacks_kthread(void)
914{
915 return rcu_kthread_task == current;
916}
917
918#endif
919
920
921
922
923
924
925
926
927static int rcu_kthread(void *arg)
928{
929 unsigned long work;
930 unsigned long morework;
931 unsigned long flags;
932
933 for (;;) {
934 wait_event_interruptible(rcu_kthread_wq,
935 have_rcu_kthread_work != 0);
936 morework = rcu_boost();
937 local_irq_save(flags);
938 work = have_rcu_kthread_work;
939 have_rcu_kthread_work = morework;
940 local_irq_restore(flags);
941 if (work)
942 rcu_process_callbacks(NULL);
943 schedule_timeout_interruptible(1);
944 }
945
946 return 0;
947}
948
949
950
951
952static int __init rcu_spawn_kthreads(void)
953{
954 struct sched_param sp;
955
956 rcu_kthread_task = kthread_run(rcu_kthread, NULL, "rcu_kthread");
957 sp.sched_priority = RCU_BOOST_PRIO;
958 sched_setscheduler_nocheck(rcu_kthread_task, SCHED_FIFO, &sp);
959 return 0;
960}
961early_initcall(rcu_spawn_kthreads);
962
963#else
964
965
966static int rcu_scheduler_fully_active __read_mostly;
967
968
969
970
971void invoke_rcu_callbacks(void)
972{
973 if (rcu_scheduler_fully_active)
974 raise_softirq(RCU_SOFTIRQ);
975}
976
977#ifdef CONFIG_RCU_TRACE
978
979
980
981
982static bool rcu_is_callbacks_kthread(void)
983{
984 return false;
985}
986
987#endif
988
989static int __init rcu_scheduler_really_started(void)
990{
991 rcu_scheduler_fully_active = 1;
992 open_softirq(RCU_SOFTIRQ, rcu_process_callbacks);
993 raise_softirq(RCU_SOFTIRQ);
994 return 0;
995}
996early_initcall(rcu_scheduler_really_started);
997
998#endif
999
1000#ifdef CONFIG_DEBUG_LOCK_ALLOC
1001#include <linux/kernel_stat.h>
1002
1003
1004
1005
1006
1007void __init rcu_scheduler_starting(void)
1008{
1009 WARN_ON(nr_context_switches() > 0);
1010 rcu_scheduler_active = 1;
1011}
1012
1013#endif
1014
1015#ifdef CONFIG_RCU_TRACE
1016
1017#ifdef CONFIG_RCU_BOOST
1018
1019static void rcu_initiate_boost_trace(void)
1020{
1021 if (list_empty(&rcu_preempt_ctrlblk.blkd_tasks))
1022 rcu_preempt_ctrlblk.n_balk_blkd_tasks++;
1023 else if (rcu_preempt_ctrlblk.gp_tasks == NULL &&
1024 rcu_preempt_ctrlblk.exp_tasks == NULL)
1025 rcu_preempt_ctrlblk.n_balk_exp_gp_tasks++;
1026 else if (rcu_preempt_ctrlblk.boost_tasks != NULL)
1027 rcu_preempt_ctrlblk.n_balk_boost_tasks++;
1028 else if (!ULONG_CMP_GE(jiffies, rcu_preempt_ctrlblk.boost_time))
1029 rcu_preempt_ctrlblk.n_balk_notyet++;
1030 else
1031 rcu_preempt_ctrlblk.n_balk_nos++;
1032}
1033
1034#endif
1035
1036static void rcu_trace_sub_qlen(struct rcu_ctrlblk *rcp, int n)
1037{
1038 unsigned long flags;
1039
1040 raw_local_irq_save(flags);
1041 rcp->qlen -= n;
1042 raw_local_irq_restore(flags);
1043}
1044
1045
1046
1047
1048static int show_tiny_stats(struct seq_file *m, void *unused)
1049{
1050 show_tiny_preempt_stats(m);
1051 seq_printf(m, "rcu_sched: qlen: %ld\n", rcu_sched_ctrlblk.qlen);
1052 seq_printf(m, "rcu_bh: qlen: %ld\n", rcu_bh_ctrlblk.qlen);
1053 return 0;
1054}
1055
1056static int show_tiny_stats_open(struct inode *inode, struct file *file)
1057{
1058 return single_open(file, show_tiny_stats, NULL);
1059}
1060
1061static const struct file_operations show_tiny_stats_fops = {
1062 .owner = THIS_MODULE,
1063 .open = show_tiny_stats_open,
1064 .read = seq_read,
1065 .llseek = seq_lseek,
1066 .release = single_release,
1067};
1068
1069static struct dentry *rcudir;
1070
1071static int __init rcutiny_trace_init(void)
1072{
1073 struct dentry *retval;
1074
1075 rcudir = debugfs_create_dir("rcu", NULL);
1076 if (!rcudir)
1077 goto free_out;
1078 retval = debugfs_create_file("rcudata", 0444, rcudir,
1079 NULL, &show_tiny_stats_fops);
1080 if (!retval)
1081 goto free_out;
1082 return 0;
1083free_out:
1084 debugfs_remove_recursive(rcudir);
1085 return 1;
1086}
1087
1088static void __exit rcutiny_trace_cleanup(void)
1089{
1090 debugfs_remove_recursive(rcudir);
1091}
1092
1093module_init(rcutiny_trace_init);
1094module_exit(rcutiny_trace_cleanup);
1095
1096MODULE_AUTHOR("Paul E. McKenney");
1097MODULE_DESCRIPTION("Read-Copy Update tracing for tiny implementation");
1098MODULE_LICENSE("GPL");
1099
1100#endif
1101