diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/rcu.h | 7 | ||||
-rw-r--r-- | kernel/rcupdate.c | 51 | ||||
-rw-r--r-- | kernel/rcutiny.c | 6 | ||||
-rw-r--r-- | kernel/rcutiny_plugin.h | 56 | ||||
-rw-r--r-- | kernel/rcutree.c | 46 | ||||
-rw-r--r-- | kernel/rcutree.h | 5 |
6 files changed, 121 insertions, 50 deletions
diff --git a/kernel/rcu.h b/kernel/rcu.h index 20dfba576c2b..7f8e7590e3e5 100644 --- a/kernel/rcu.h +++ b/kernel/rcu.h | |||
@@ -111,4 +111,11 @@ static inline bool __rcu_reclaim(char *rn, struct rcu_head *head) | |||
111 | 111 | ||
112 | extern int rcu_expedited; | 112 | extern int rcu_expedited; |
113 | 113 | ||
114 | #ifdef CONFIG_RCU_STALL_COMMON | ||
115 | |||
116 | extern int rcu_cpu_stall_suppress; | ||
117 | int rcu_jiffies_till_stall_check(void); | ||
118 | |||
119 | #endif /* #ifdef CONFIG_RCU_STALL_COMMON */ | ||
120 | |||
114 | #endif /* __LINUX_RCU_H */ | 121 | #endif /* __LINUX_RCU_H */ |
diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c index a2cf76177b44..076730d95acc 100644 --- a/kernel/rcupdate.c +++ b/kernel/rcupdate.c | |||
@@ -412,3 +412,54 @@ EXPORT_SYMBOL_GPL(do_trace_rcu_torture_read); | |||
412 | #else | 412 | #else |
413 | #define do_trace_rcu_torture_read(rcutorturename, rhp) do { } while (0) | 413 | #define do_trace_rcu_torture_read(rcutorturename, rhp) do { } while (0) |
414 | #endif | 414 | #endif |
415 | |||
416 | #ifdef CONFIG_RCU_STALL_COMMON | ||
417 | |||
418 | #ifdef CONFIG_PROVE_RCU | ||
419 | #define RCU_STALL_DELAY_DELTA (5 * HZ) | ||
420 | #else | ||
421 | #define RCU_STALL_DELAY_DELTA 0 | ||
422 | #endif | ||
423 | |||
424 | int rcu_cpu_stall_suppress __read_mostly; /* 1 = suppress stall warnings. */ | ||
425 | int rcu_cpu_stall_timeout __read_mostly = CONFIG_RCU_CPU_STALL_TIMEOUT; | ||
426 | |||
427 | module_param(rcu_cpu_stall_suppress, int, 0644); | ||
428 | module_param(rcu_cpu_stall_timeout, int, 0644); | ||
429 | |||
430 | int rcu_jiffies_till_stall_check(void) | ||
431 | { | ||
432 | int till_stall_check = ACCESS_ONCE(rcu_cpu_stall_timeout); | ||
433 | |||
434 | /* | ||
435 | * Limit check must be consistent with the Kconfig limits | ||
436 | * for CONFIG_RCU_CPU_STALL_TIMEOUT. | ||
437 | */ | ||
438 | if (till_stall_check < 3) { | ||
439 | ACCESS_ONCE(rcu_cpu_stall_timeout) = 3; | ||
440 | till_stall_check = 3; | ||
441 | } else if (till_stall_check > 300) { | ||
442 | ACCESS_ONCE(rcu_cpu_stall_timeout) = 300; | ||
443 | till_stall_check = 300; | ||
444 | } | ||
445 | return till_stall_check * HZ + RCU_STALL_DELAY_DELTA; | ||
446 | } | ||
447 | |||
448 | static int rcu_panic(struct notifier_block *this, unsigned long ev, void *ptr) | ||
449 | { | ||
450 | rcu_cpu_stall_suppress = 1; | ||
451 | return NOTIFY_DONE; | ||
452 | } | ||
453 | |||
454 | static struct notifier_block rcu_panic_block = { | ||
455 | .notifier_call = rcu_panic, | ||
456 | }; | ||
457 | |||
458 | static int __init check_cpu_stall_init(void) | ||
459 | { | ||
460 | atomic_notifier_chain_register(&panic_notifier_list, &rcu_panic_block); | ||
461 | return 0; | ||
462 | } | ||
463 | early_initcall(check_cpu_stall_init); | ||
464 | |||
465 | #endif /* #ifdef CONFIG_RCU_STALL_COMMON */ | ||
diff --git a/kernel/rcutiny.c b/kernel/rcutiny.c index e7dce58f9c2a..b899df317edc 100644 --- a/kernel/rcutiny.c +++ b/kernel/rcutiny.c | |||
@@ -51,10 +51,10 @@ static void __call_rcu(struct rcu_head *head, | |||
51 | void (*func)(struct rcu_head *rcu), | 51 | void (*func)(struct rcu_head *rcu), |
52 | struct rcu_ctrlblk *rcp); | 52 | struct rcu_ctrlblk *rcp); |
53 | 53 | ||
54 | #include "rcutiny_plugin.h" | ||
55 | |||
56 | static long long rcu_dynticks_nesting = DYNTICK_TASK_EXIT_IDLE; | 54 | static long long rcu_dynticks_nesting = DYNTICK_TASK_EXIT_IDLE; |
57 | 55 | ||
56 | #include "rcutiny_plugin.h" | ||
57 | |||
58 | /* Common code for rcu_idle_enter() and rcu_irq_exit(), see kernel/rcutree.c. */ | 58 | /* Common code for rcu_idle_enter() and rcu_irq_exit(), see kernel/rcutree.c. */ |
59 | static void rcu_idle_enter_common(long long newval) | 59 | static void rcu_idle_enter_common(long long newval) |
60 | { | 60 | { |
@@ -205,6 +205,7 @@ int rcu_is_cpu_rrupt_from_idle(void) | |||
205 | */ | 205 | */ |
206 | static int rcu_qsctr_help(struct rcu_ctrlblk *rcp) | 206 | static int rcu_qsctr_help(struct rcu_ctrlblk *rcp) |
207 | { | 207 | { |
208 | reset_cpu_stall_ticks(rcp); | ||
208 | if (rcp->rcucblist != NULL && | 209 | if (rcp->rcucblist != NULL && |
209 | rcp->donetail != rcp->curtail) { | 210 | rcp->donetail != rcp->curtail) { |
210 | rcp->donetail = rcp->curtail; | 211 | rcp->donetail = rcp->curtail; |
@@ -251,6 +252,7 @@ void rcu_bh_qs(int cpu) | |||
251 | */ | 252 | */ |
252 | void rcu_check_callbacks(int cpu, int user) | 253 | void rcu_check_callbacks(int cpu, int user) |
253 | { | 254 | { |
255 | check_cpu_stalls(); | ||
254 | if (user || rcu_is_cpu_rrupt_from_idle()) | 256 | if (user || rcu_is_cpu_rrupt_from_idle()) |
255 | rcu_sched_qs(cpu); | 257 | rcu_sched_qs(cpu); |
256 | else if (!in_softirq()) | 258 | else if (!in_softirq()) |
diff --git a/kernel/rcutiny_plugin.h b/kernel/rcutiny_plugin.h index f85016a2309b..8a233002faeb 100644 --- a/kernel/rcutiny_plugin.h +++ b/kernel/rcutiny_plugin.h | |||
@@ -33,6 +33,9 @@ struct rcu_ctrlblk { | |||
33 | struct rcu_head **donetail; /* ->next pointer of last "done" CB. */ | 33 | struct rcu_head **donetail; /* ->next pointer of last "done" CB. */ |
34 | struct rcu_head **curtail; /* ->next pointer of last CB. */ | 34 | struct rcu_head **curtail; /* ->next pointer of last CB. */ |
35 | RCU_TRACE(long qlen); /* Number of pending CBs. */ | 35 | RCU_TRACE(long qlen); /* Number of pending CBs. */ |
36 | RCU_TRACE(unsigned long gp_start); /* Start time for stalls. */ | ||
37 | RCU_TRACE(unsigned long ticks_this_gp); /* Statistic for stalls. */ | ||
38 | RCU_TRACE(unsigned long jiffies_stall); /* Jiffies at next stall. */ | ||
36 | RCU_TRACE(char *name); /* Name of RCU type. */ | 39 | RCU_TRACE(char *name); /* Name of RCU type. */ |
37 | }; | 40 | }; |
38 | 41 | ||
@@ -54,6 +57,51 @@ int rcu_scheduler_active __read_mostly; | |||
54 | EXPORT_SYMBOL_GPL(rcu_scheduler_active); | 57 | EXPORT_SYMBOL_GPL(rcu_scheduler_active); |
55 | #endif /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */ | 58 | #endif /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */ |
56 | 59 | ||
60 | #ifdef CONFIG_RCU_TRACE | ||
61 | |||
62 | static void check_cpu_stall(struct rcu_ctrlblk *rcp) | ||
63 | { | ||
64 | unsigned long j; | ||
65 | unsigned long js; | ||
66 | |||
67 | if (rcu_cpu_stall_suppress) | ||
68 | return; | ||
69 | rcp->ticks_this_gp++; | ||
70 | j = jiffies; | ||
71 | js = rcp->jiffies_stall; | ||
72 | if (*rcp->curtail && ULONG_CMP_GE(j, js)) { | ||
73 | pr_err("INFO: %s stall on CPU (%lu ticks this GP) idle=%llx (t=%lu jiffies q=%ld)\n", | ||
74 | rcp->name, rcp->ticks_this_gp, rcu_dynticks_nesting, | ||
75 | jiffies - rcp->gp_start, rcp->qlen); | ||
76 | dump_stack(); | ||
77 | } | ||
78 | if (*rcp->curtail && ULONG_CMP_GE(j, js)) | ||
79 | rcp->jiffies_stall = jiffies + | ||
80 | 3 * rcu_jiffies_till_stall_check() + 3; | ||
81 | else if (ULONG_CMP_GE(j, js)) | ||
82 | rcp->jiffies_stall = jiffies + rcu_jiffies_till_stall_check(); | ||
83 | } | ||
84 | |||
85 | static void check_cpu_stall_preempt(void); | ||
86 | |||
87 | #endif /* #ifdef CONFIG_RCU_TRACE */ | ||
88 | |||
89 | static void reset_cpu_stall_ticks(struct rcu_ctrlblk *rcp) | ||
90 | { | ||
91 | #ifdef CONFIG_RCU_TRACE | ||
92 | rcp->ticks_this_gp = 0; | ||
93 | rcp->gp_start = jiffies; | ||
94 | rcp->jiffies_stall = jiffies + rcu_jiffies_till_stall_check(); | ||
95 | #endif /* #ifdef CONFIG_RCU_TRACE */ | ||
96 | } | ||
97 | |||
98 | static void check_cpu_stalls(void) | ||
99 | { | ||
100 | RCU_TRACE(check_cpu_stall(&rcu_bh_ctrlblk)); | ||
101 | RCU_TRACE(check_cpu_stall(&rcu_sched_ctrlblk)); | ||
102 | RCU_TRACE(check_cpu_stall_preempt()); | ||
103 | } | ||
104 | |||
57 | #ifdef CONFIG_TINY_PREEMPT_RCU | 105 | #ifdef CONFIG_TINY_PREEMPT_RCU |
58 | 106 | ||
59 | #include <linux/delay.h> | 107 | #include <linux/delay.h> |
@@ -448,6 +496,7 @@ static void rcu_preempt_start_gp(void) | |||
448 | /* Official start of GP. */ | 496 | /* Official start of GP. */ |
449 | rcu_preempt_ctrlblk.gpnum++; | 497 | rcu_preempt_ctrlblk.gpnum++; |
450 | RCU_TRACE(rcu_preempt_ctrlblk.n_grace_periods++); | 498 | RCU_TRACE(rcu_preempt_ctrlblk.n_grace_periods++); |
499 | reset_cpu_stall_ticks(&rcu_preempt_ctrlblk.rcb); | ||
451 | 500 | ||
452 | /* Any blocked RCU readers block new GP. */ | 501 | /* Any blocked RCU readers block new GP. */ |
453 | if (rcu_preempt_blocked_readers_any()) | 502 | if (rcu_preempt_blocked_readers_any()) |
@@ -1054,4 +1103,11 @@ MODULE_AUTHOR("Paul E. McKenney"); | |||
1054 | MODULE_DESCRIPTION("Read-Copy Update tracing for tiny implementation"); | 1103 | MODULE_DESCRIPTION("Read-Copy Update tracing for tiny implementation"); |
1055 | MODULE_LICENSE("GPL"); | 1104 | MODULE_LICENSE("GPL"); |
1056 | 1105 | ||
1106 | static void check_cpu_stall_preempt(void) | ||
1107 | { | ||
1108 | #ifdef CONFIG_TINY_PREEMPT_RCU | ||
1109 | check_cpu_stall(&rcu_preempt_ctrlblk.rcb); | ||
1110 | #endif /* #ifdef CONFIG_TINY_PREEMPT_RCU */ | ||
1111 | } | ||
1112 | |||
1057 | #endif /* #ifdef CONFIG_RCU_TRACE */ | 1113 | #endif /* #ifdef CONFIG_RCU_TRACE */ |
diff --git a/kernel/rcutree.c b/kernel/rcutree.c index e441b77b614e..d069430f0974 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c | |||
@@ -217,12 +217,6 @@ module_param(blimit, long, 0444); | |||
217 | module_param(qhimark, long, 0444); | 217 | module_param(qhimark, long, 0444); |
218 | module_param(qlowmark, long, 0444); | 218 | module_param(qlowmark, long, 0444); |
219 | 219 | ||
220 | int rcu_cpu_stall_suppress __read_mostly; /* 1 = suppress stall warnings. */ | ||
221 | int rcu_cpu_stall_timeout __read_mostly = CONFIG_RCU_CPU_STALL_TIMEOUT; | ||
222 | |||
223 | module_param(rcu_cpu_stall_suppress, int, 0644); | ||
224 | module_param(rcu_cpu_stall_timeout, int, 0644); | ||
225 | |||
226 | static ulong jiffies_till_first_fqs = RCU_JIFFIES_TILL_FORCE_QS; | 220 | static ulong jiffies_till_first_fqs = RCU_JIFFIES_TILL_FORCE_QS; |
227 | static ulong jiffies_till_next_fqs = RCU_JIFFIES_TILL_FORCE_QS; | 221 | static ulong jiffies_till_next_fqs = RCU_JIFFIES_TILL_FORCE_QS; |
228 | 222 | ||
@@ -793,28 +787,10 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp) | |||
793 | return 0; | 787 | return 0; |
794 | } | 788 | } |
795 | 789 | ||
796 | static int jiffies_till_stall_check(void) | ||
797 | { | ||
798 | int till_stall_check = ACCESS_ONCE(rcu_cpu_stall_timeout); | ||
799 | |||
800 | /* | ||
801 | * Limit check must be consistent with the Kconfig limits | ||
802 | * for CONFIG_RCU_CPU_STALL_TIMEOUT. | ||
803 | */ | ||
804 | if (till_stall_check < 3) { | ||
805 | ACCESS_ONCE(rcu_cpu_stall_timeout) = 3; | ||
806 | till_stall_check = 3; | ||
807 | } else if (till_stall_check > 300) { | ||
808 | ACCESS_ONCE(rcu_cpu_stall_timeout) = 300; | ||
809 | till_stall_check = 300; | ||
810 | } | ||
811 | return till_stall_check * HZ + RCU_STALL_DELAY_DELTA; | ||
812 | } | ||
813 | |||
814 | static void record_gp_stall_check_time(struct rcu_state *rsp) | 790 | static void record_gp_stall_check_time(struct rcu_state *rsp) |
815 | { | 791 | { |
816 | rsp->gp_start = jiffies; | 792 | rsp->gp_start = jiffies; |
817 | rsp->jiffies_stall = jiffies + jiffies_till_stall_check(); | 793 | rsp->jiffies_stall = jiffies + rcu_jiffies_till_stall_check(); |
818 | } | 794 | } |
819 | 795 | ||
820 | /* | 796 | /* |
@@ -857,7 +833,7 @@ static void print_other_cpu_stall(struct rcu_state *rsp) | |||
857 | raw_spin_unlock_irqrestore(&rnp->lock, flags); | 833 | raw_spin_unlock_irqrestore(&rnp->lock, flags); |
858 | return; | 834 | return; |
859 | } | 835 | } |
860 | rsp->jiffies_stall = jiffies + 3 * jiffies_till_stall_check() + 3; | 836 | rsp->jiffies_stall = jiffies + 3 * rcu_jiffies_till_stall_check() + 3; |
861 | raw_spin_unlock_irqrestore(&rnp->lock, flags); | 837 | raw_spin_unlock_irqrestore(&rnp->lock, flags); |
862 | 838 | ||
863 | /* | 839 | /* |
@@ -935,7 +911,7 @@ static void print_cpu_stall(struct rcu_state *rsp) | |||
935 | raw_spin_lock_irqsave(&rnp->lock, flags); | 911 | raw_spin_lock_irqsave(&rnp->lock, flags); |
936 | if (ULONG_CMP_GE(jiffies, rsp->jiffies_stall)) | 912 | if (ULONG_CMP_GE(jiffies, rsp->jiffies_stall)) |
937 | rsp->jiffies_stall = jiffies + | 913 | rsp->jiffies_stall = jiffies + |
938 | 3 * jiffies_till_stall_check() + 3; | 914 | 3 * rcu_jiffies_till_stall_check() + 3; |
939 | raw_spin_unlock_irqrestore(&rnp->lock, flags); | 915 | raw_spin_unlock_irqrestore(&rnp->lock, flags); |
940 | 916 | ||
941 | set_need_resched(); /* kick ourselves to get things going. */ | 917 | set_need_resched(); /* kick ourselves to get things going. */ |
@@ -966,12 +942,6 @@ static void check_cpu_stall(struct rcu_state *rsp, struct rcu_data *rdp) | |||
966 | } | 942 | } |
967 | } | 943 | } |
968 | 944 | ||
969 | static int rcu_panic(struct notifier_block *this, unsigned long ev, void *ptr) | ||
970 | { | ||
971 | rcu_cpu_stall_suppress = 1; | ||
972 | return NOTIFY_DONE; | ||
973 | } | ||
974 | |||
975 | /** | 945 | /** |
976 | * rcu_cpu_stall_reset - prevent further stall warnings in current grace period | 946 | * rcu_cpu_stall_reset - prevent further stall warnings in current grace period |
977 | * | 947 | * |
@@ -989,15 +959,6 @@ void rcu_cpu_stall_reset(void) | |||
989 | rsp->jiffies_stall = jiffies + ULONG_MAX / 2; | 959 | rsp->jiffies_stall = jiffies + ULONG_MAX / 2; |
990 | } | 960 | } |
991 | 961 | ||
992 | static struct notifier_block rcu_panic_block = { | ||
993 | .notifier_call = rcu_panic, | ||
994 | }; | ||
995 | |||
996 | static void __init check_cpu_stall_init(void) | ||
997 | { | ||
998 | atomic_notifier_chain_register(&panic_notifier_list, &rcu_panic_block); | ||
999 | } | ||
1000 | |||
1001 | /* | 962 | /* |
1002 | * Update CPU-local rcu_data state to record the newly noticed grace period. | 963 | * Update CPU-local rcu_data state to record the newly noticed grace period. |
1003 | * This is used both when we started the grace period and when we notice | 964 | * This is used both when we started the grace period and when we notice |
@@ -3074,7 +3035,6 @@ void __init rcu_init(void) | |||
3074 | cpu_notifier(rcu_cpu_notify, 0); | 3035 | cpu_notifier(rcu_cpu_notify, 0); |
3075 | for_each_online_cpu(cpu) | 3036 | for_each_online_cpu(cpu) |
3076 | rcu_cpu_notify(NULL, CPU_UP_PREPARE, (void *)(long)cpu); | 3037 | rcu_cpu_notify(NULL, CPU_UP_PREPARE, (void *)(long)cpu); |
3077 | check_cpu_stall_init(); | ||
3078 | } | 3038 | } |
3079 | 3039 | ||
3080 | #include "rcutree_plugin.h" | 3040 | #include "rcutree_plugin.h" |
diff --git a/kernel/rcutree.h b/kernel/rcutree.h index 4b69291b093d..db9bec83fe3f 100644 --- a/kernel/rcutree.h +++ b/kernel/rcutree.h | |||
@@ -343,11 +343,6 @@ struct rcu_data { | |||
343 | 343 | ||
344 | #define RCU_JIFFIES_TILL_FORCE_QS 3 /* for rsp->jiffies_force_qs */ | 344 | #define RCU_JIFFIES_TILL_FORCE_QS 3 /* for rsp->jiffies_force_qs */ |
345 | 345 | ||
346 | #ifdef CONFIG_PROVE_RCU | ||
347 | #define RCU_STALL_DELAY_DELTA (5 * HZ) | ||
348 | #else | ||
349 | #define RCU_STALL_DELAY_DELTA 0 | ||
350 | #endif | ||
351 | #define RCU_STALL_RAT_DELAY 2 /* Allow other CPUs time */ | 346 | #define RCU_STALL_RAT_DELAY 2 /* Allow other CPUs time */ |
352 | /* to take at least one */ | 347 | /* to take at least one */ |
353 | /* scheduling clock irq */ | 348 | /* scheduling clock irq */ |