diff options
Diffstat (limited to 'kernel/rcutiny_plugin.h')
-rw-r--r-- | kernel/rcutiny_plugin.h | 135 |
1 files changed, 88 insertions, 47 deletions
diff --git a/kernel/rcutiny_plugin.h b/kernel/rcutiny_plugin.h index f259c676195f..2b0484a5dc28 100644 --- a/kernel/rcutiny_plugin.h +++ b/kernel/rcutiny_plugin.h | |||
@@ -23,32 +23,30 @@ | |||
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include <linux/kthread.h> | 25 | #include <linux/kthread.h> |
26 | #include <linux/module.h> | ||
26 | #include <linux/debugfs.h> | 27 | #include <linux/debugfs.h> |
27 | #include <linux/seq_file.h> | 28 | #include <linux/seq_file.h> |
28 | 29 | ||
29 | #ifdef CONFIG_RCU_TRACE | ||
30 | #define RCU_TRACE(stmt) stmt | ||
31 | #else /* #ifdef CONFIG_RCU_TRACE */ | ||
32 | #define RCU_TRACE(stmt) | ||
33 | #endif /* #else #ifdef CONFIG_RCU_TRACE */ | ||
34 | |||
35 | /* Global control variables for rcupdate callback mechanism. */ | 30 | /* Global control variables for rcupdate callback mechanism. */ |
36 | struct rcu_ctrlblk { | 31 | struct rcu_ctrlblk { |
37 | struct rcu_head *rcucblist; /* List of pending callbacks (CBs). */ | 32 | struct rcu_head *rcucblist; /* List of pending callbacks (CBs). */ |
38 | struct rcu_head **donetail; /* ->next pointer of last "done" CB. */ | 33 | struct rcu_head **donetail; /* ->next pointer of last "done" CB. */ |
39 | struct rcu_head **curtail; /* ->next pointer of last CB. */ | 34 | struct rcu_head **curtail; /* ->next pointer of last CB. */ |
40 | RCU_TRACE(long qlen); /* Number of pending CBs. */ | 35 | RCU_TRACE(long qlen); /* Number of pending CBs. */ |
36 | RCU_TRACE(char *name); /* Name of RCU type. */ | ||
41 | }; | 37 | }; |
42 | 38 | ||
43 | /* Definition for rcupdate control block. */ | 39 | /* Definition for rcupdate control block. */ |
44 | static struct rcu_ctrlblk rcu_sched_ctrlblk = { | 40 | static struct rcu_ctrlblk rcu_sched_ctrlblk = { |
45 | .donetail = &rcu_sched_ctrlblk.rcucblist, | 41 | .donetail = &rcu_sched_ctrlblk.rcucblist, |
46 | .curtail = &rcu_sched_ctrlblk.rcucblist, | 42 | .curtail = &rcu_sched_ctrlblk.rcucblist, |
43 | RCU_TRACE(.name = "rcu_sched") | ||
47 | }; | 44 | }; |
48 | 45 | ||
49 | static struct rcu_ctrlblk rcu_bh_ctrlblk = { | 46 | static struct rcu_ctrlblk rcu_bh_ctrlblk = { |
50 | .donetail = &rcu_bh_ctrlblk.rcucblist, | 47 | .donetail = &rcu_bh_ctrlblk.rcucblist, |
51 | .curtail = &rcu_bh_ctrlblk.rcucblist, | 48 | .curtail = &rcu_bh_ctrlblk.rcucblist, |
49 | RCU_TRACE(.name = "rcu_bh") | ||
52 | }; | 50 | }; |
53 | 51 | ||
54 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | 52 | #ifdef CONFIG_DEBUG_LOCK_ALLOC |
@@ -131,6 +129,7 @@ static struct rcu_preempt_ctrlblk rcu_preempt_ctrlblk = { | |||
131 | .rcb.curtail = &rcu_preempt_ctrlblk.rcb.rcucblist, | 129 | .rcb.curtail = &rcu_preempt_ctrlblk.rcb.rcucblist, |
132 | .nexttail = &rcu_preempt_ctrlblk.rcb.rcucblist, | 130 | .nexttail = &rcu_preempt_ctrlblk.rcb.rcucblist, |
133 | .blkd_tasks = LIST_HEAD_INIT(rcu_preempt_ctrlblk.blkd_tasks), | 131 | .blkd_tasks = LIST_HEAD_INIT(rcu_preempt_ctrlblk.blkd_tasks), |
132 | RCU_TRACE(.rcb.name = "rcu_preempt") | ||
134 | }; | 133 | }; |
135 | 134 | ||
136 | static int rcu_preempted_readers_exp(void); | 135 | static int rcu_preempted_readers_exp(void); |
@@ -247,6 +246,13 @@ static void show_tiny_preempt_stats(struct seq_file *m) | |||
247 | 246 | ||
248 | #include "rtmutex_common.h" | 247 | #include "rtmutex_common.h" |
249 | 248 | ||
249 | #define RCU_BOOST_PRIO CONFIG_RCU_BOOST_PRIO | ||
250 | |||
251 | /* Controls for rcu_kthread() kthread. */ | ||
252 | static struct task_struct *rcu_kthread_task; | ||
253 | static DECLARE_WAIT_QUEUE_HEAD(rcu_kthread_wq); | ||
254 | static unsigned long have_rcu_kthread_work; | ||
255 | |||
250 | /* | 256 | /* |
251 | * Carry out RCU priority boosting on the task indicated by ->boost_tasks, | 257 | * Carry out RCU priority boosting on the task indicated by ->boost_tasks, |
252 | * and advance ->boost_tasks to the next task in the ->blkd_tasks list. | 258 | * and advance ->boost_tasks to the next task in the ->blkd_tasks list. |
@@ -334,7 +340,7 @@ static int rcu_initiate_boost(void) | |||
334 | if (rcu_preempt_ctrlblk.exp_tasks == NULL) | 340 | if (rcu_preempt_ctrlblk.exp_tasks == NULL) |
335 | rcu_preempt_ctrlblk.boost_tasks = | 341 | rcu_preempt_ctrlblk.boost_tasks = |
336 | rcu_preempt_ctrlblk.gp_tasks; | 342 | rcu_preempt_ctrlblk.gp_tasks; |
337 | invoke_rcu_kthread(); | 343 | invoke_rcu_callbacks(); |
338 | } else | 344 | } else |
339 | RCU_TRACE(rcu_initiate_boost_trace()); | 345 | RCU_TRACE(rcu_initiate_boost_trace()); |
340 | return 1; | 346 | return 1; |
@@ -353,14 +359,6 @@ static void rcu_preempt_boost_start_gp(void) | |||
353 | #else /* #ifdef CONFIG_RCU_BOOST */ | 359 | #else /* #ifdef CONFIG_RCU_BOOST */ |
354 | 360 | ||
355 | /* | 361 | /* |
356 | * If there is no RCU priority boosting, we don't boost. | ||
357 | */ | ||
358 | static int rcu_boost(void) | ||
359 | { | ||
360 | return 0; | ||
361 | } | ||
362 | |||
363 | /* | ||
364 | * If there is no RCU priority boosting, we don't initiate boosting, | 362 | * If there is no RCU priority boosting, we don't initiate boosting, |
365 | * but we do indicate whether there are blocked readers blocking the | 363 | * but we do indicate whether there are blocked readers blocking the |
366 | * current grace period. | 364 | * current grace period. |
@@ -427,7 +425,7 @@ static void rcu_preempt_cpu_qs(void) | |||
427 | 425 | ||
428 | /* If there are done callbacks, cause them to be invoked. */ | 426 | /* If there are done callbacks, cause them to be invoked. */ |
429 | if (*rcu_preempt_ctrlblk.rcb.donetail != NULL) | 427 | if (*rcu_preempt_ctrlblk.rcb.donetail != NULL) |
430 | invoke_rcu_kthread(); | 428 | invoke_rcu_callbacks(); |
431 | } | 429 | } |
432 | 430 | ||
433 | /* | 431 | /* |
@@ -648,7 +646,7 @@ static void rcu_preempt_check_callbacks(void) | |||
648 | rcu_preempt_cpu_qs(); | 646 | rcu_preempt_cpu_qs(); |
649 | if (&rcu_preempt_ctrlblk.rcb.rcucblist != | 647 | if (&rcu_preempt_ctrlblk.rcb.rcucblist != |
650 | rcu_preempt_ctrlblk.rcb.donetail) | 648 | rcu_preempt_ctrlblk.rcb.donetail) |
651 | invoke_rcu_kthread(); | 649 | invoke_rcu_callbacks(); |
652 | if (rcu_preempt_gp_in_progress() && | 650 | if (rcu_preempt_gp_in_progress() && |
653 | rcu_cpu_blocking_cur_gp() && | 651 | rcu_cpu_blocking_cur_gp() && |
654 | rcu_preempt_running_reader()) | 652 | rcu_preempt_running_reader()) |
@@ -674,7 +672,7 @@ static void rcu_preempt_remove_callbacks(struct rcu_ctrlblk *rcp) | |||
674 | */ | 672 | */ |
675 | static void rcu_preempt_process_callbacks(void) | 673 | static void rcu_preempt_process_callbacks(void) |
676 | { | 674 | { |
677 | rcu_process_callbacks(&rcu_preempt_ctrlblk.rcb); | 675 | __rcu_process_callbacks(&rcu_preempt_ctrlblk.rcb); |
678 | } | 676 | } |
679 | 677 | ||
680 | /* | 678 | /* |
@@ -697,20 +695,6 @@ void call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu)) | |||
697 | } | 695 | } |
698 | EXPORT_SYMBOL_GPL(call_rcu); | 696 | EXPORT_SYMBOL_GPL(call_rcu); |
699 | 697 | ||
700 | void rcu_barrier(void) | ||
701 | { | ||
702 | struct rcu_synchronize rcu; | ||
703 | |||
704 | init_rcu_head_on_stack(&rcu.head); | ||
705 | init_completion(&rcu.completion); | ||
706 | /* Will wake me after RCU finished. */ | ||
707 | call_rcu(&rcu.head, wakeme_after_rcu); | ||
708 | /* Wait for it. */ | ||
709 | wait_for_completion(&rcu.completion); | ||
710 | destroy_rcu_head_on_stack(&rcu.head); | ||
711 | } | ||
712 | EXPORT_SYMBOL_GPL(rcu_barrier); | ||
713 | |||
714 | /* | 698 | /* |
715 | * synchronize_rcu - wait until a grace period has elapsed. | 699 | * synchronize_rcu - wait until a grace period has elapsed. |
716 | * | 700 | * |
@@ -864,15 +848,6 @@ static void show_tiny_preempt_stats(struct seq_file *m) | |||
864 | #endif /* #ifdef CONFIG_RCU_TRACE */ | 848 | #endif /* #ifdef CONFIG_RCU_TRACE */ |
865 | 849 | ||
866 | /* | 850 | /* |
867 | * Because preemptible RCU does not exist, it is never necessary to | ||
868 | * boost preempted RCU readers. | ||
869 | */ | ||
870 | static int rcu_boost(void) | ||
871 | { | ||
872 | return 0; | ||
873 | } | ||
874 | |||
875 | /* | ||
876 | * Because preemptible RCU does not exist, it never has any callbacks | 851 | * Because preemptible RCU does not exist, it never has any callbacks |
877 | * to check. | 852 | * to check. |
878 | */ | 853 | */ |
@@ -898,6 +873,78 @@ static void rcu_preempt_process_callbacks(void) | |||
898 | 873 | ||
899 | #endif /* #else #ifdef CONFIG_TINY_PREEMPT_RCU */ | 874 | #endif /* #else #ifdef CONFIG_TINY_PREEMPT_RCU */ |
900 | 875 | ||
876 | #ifdef CONFIG_RCU_BOOST | ||
877 | |||
878 | /* | ||
879 | * Wake up rcu_kthread() to process callbacks now eligible for invocation | ||
880 | * or to boost readers. | ||
881 | */ | ||
882 | static void invoke_rcu_callbacks(void) | ||
883 | { | ||
884 | have_rcu_kthread_work = 1; | ||
885 | wake_up(&rcu_kthread_wq); | ||
886 | } | ||
887 | |||
888 | /* | ||
889 | * This kthread invokes RCU callbacks whose grace periods have | ||
890 | * elapsed. It is awakened as needed, and takes the place of the | ||
891 | * RCU_SOFTIRQ that is used for this purpose when boosting is disabled. | ||
892 | * This is a kthread, but it is never stopped, at least not until | ||
893 | * the system goes down. | ||
894 | */ | ||
895 | static int rcu_kthread(void *arg) | ||
896 | { | ||
897 | unsigned long work; | ||
898 | unsigned long morework; | ||
899 | unsigned long flags; | ||
900 | |||
901 | for (;;) { | ||
902 | wait_event_interruptible(rcu_kthread_wq, | ||
903 | have_rcu_kthread_work != 0); | ||
904 | morework = rcu_boost(); | ||
905 | local_irq_save(flags); | ||
906 | work = have_rcu_kthread_work; | ||
907 | have_rcu_kthread_work = morework; | ||
908 | local_irq_restore(flags); | ||
909 | if (work) | ||
910 | rcu_process_callbacks(NULL); | ||
911 | schedule_timeout_interruptible(1); /* Leave CPU for others. */ | ||
912 | } | ||
913 | |||
914 | return 0; /* Not reached, but needed to shut gcc up. */ | ||
915 | } | ||
916 | |||
917 | /* | ||
918 | * Spawn the kthread that invokes RCU callbacks. | ||
919 | */ | ||
920 | static int __init rcu_spawn_kthreads(void) | ||
921 | { | ||
922 | struct sched_param sp; | ||
923 | |||
924 | rcu_kthread_task = kthread_run(rcu_kthread, NULL, "rcu_kthread"); | ||
925 | sp.sched_priority = RCU_BOOST_PRIO; | ||
926 | sched_setscheduler_nocheck(rcu_kthread_task, SCHED_FIFO, &sp); | ||
927 | return 0; | ||
928 | } | ||
929 | early_initcall(rcu_spawn_kthreads); | ||
930 | |||
931 | #else /* #ifdef CONFIG_RCU_BOOST */ | ||
932 | |||
933 | /* | ||
934 | * Start up softirq processing of callbacks. | ||
935 | */ | ||
936 | void invoke_rcu_callbacks(void) | ||
937 | { | ||
938 | raise_softirq(RCU_SOFTIRQ); | ||
939 | } | ||
940 | |||
941 | void rcu_init(void) | ||
942 | { | ||
943 | open_softirq(RCU_SOFTIRQ, rcu_process_callbacks); | ||
944 | } | ||
945 | |||
946 | #endif /* #else #ifdef CONFIG_RCU_BOOST */ | ||
947 | |||
901 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | 948 | #ifdef CONFIG_DEBUG_LOCK_ALLOC |
902 | #include <linux/kernel_stat.h> | 949 | #include <linux/kernel_stat.h> |
903 | 950 | ||
@@ -913,12 +960,6 @@ void __init rcu_scheduler_starting(void) | |||
913 | 960 | ||
914 | #endif /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */ | 961 | #endif /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */ |
915 | 962 | ||
916 | #ifdef CONFIG_RCU_BOOST | ||
917 | #define RCU_BOOST_PRIO CONFIG_RCU_BOOST_PRIO | ||
918 | #else /* #ifdef CONFIG_RCU_BOOST */ | ||
919 | #define RCU_BOOST_PRIO 1 | ||
920 | #endif /* #else #ifdef CONFIG_RCU_BOOST */ | ||
921 | |||
922 | #ifdef CONFIG_RCU_TRACE | 963 | #ifdef CONFIG_RCU_TRACE |
923 | 964 | ||
924 | #ifdef CONFIG_RCU_BOOST | 965 | #ifdef CONFIG_RCU_BOOST |