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 |
