diff options
Diffstat (limited to 'kernel/softlockup.c')
-rw-r--r-- | kernel/softlockup.c | 69 |
1 files changed, 42 insertions, 27 deletions
diff --git a/kernel/softlockup.c b/kernel/softlockup.c index 81324d12eb35..4b493f67dcb5 100644 --- a/kernel/softlockup.c +++ b/kernel/softlockup.c | |||
@@ -22,9 +22,10 @@ | |||
22 | 22 | ||
23 | static DEFINE_SPINLOCK(print_lock); | 23 | static DEFINE_SPINLOCK(print_lock); |
24 | 24 | ||
25 | static DEFINE_PER_CPU(unsigned long, touch_timestamp); | 25 | static DEFINE_PER_CPU(unsigned long, softlockup_touch_ts); /* touch timestamp */ |
26 | static DEFINE_PER_CPU(unsigned long, print_timestamp); | 26 | static DEFINE_PER_CPU(unsigned long, softlockup_print_ts); /* print timestamp */ |
27 | static DEFINE_PER_CPU(struct task_struct *, watchdog_task); | 27 | static DEFINE_PER_CPU(struct task_struct *, softlockup_watchdog); |
28 | static DEFINE_PER_CPU(bool, softlock_touch_sync); | ||
28 | 29 | ||
29 | static int __read_mostly did_panic; | 30 | static int __read_mostly did_panic; |
30 | int __read_mostly softlockup_thresh = 60; | 31 | int __read_mostly softlockup_thresh = 60; |
@@ -70,22 +71,28 @@ static void __touch_softlockup_watchdog(void) | |||
70 | { | 71 | { |
71 | int this_cpu = raw_smp_processor_id(); | 72 | int this_cpu = raw_smp_processor_id(); |
72 | 73 | ||
73 | __raw_get_cpu_var(touch_timestamp) = get_timestamp(this_cpu); | 74 | __raw_get_cpu_var(softlockup_touch_ts) = get_timestamp(this_cpu); |
74 | } | 75 | } |
75 | 76 | ||
76 | void touch_softlockup_watchdog(void) | 77 | void touch_softlockup_watchdog(void) |
77 | { | 78 | { |
78 | __raw_get_cpu_var(touch_timestamp) = 0; | 79 | __raw_get_cpu_var(softlockup_touch_ts) = 0; |
79 | } | 80 | } |
80 | EXPORT_SYMBOL(touch_softlockup_watchdog); | 81 | EXPORT_SYMBOL(touch_softlockup_watchdog); |
81 | 82 | ||
83 | void touch_softlockup_watchdog_sync(void) | ||
84 | { | ||
85 | __raw_get_cpu_var(softlock_touch_sync) = true; | ||
86 | __raw_get_cpu_var(softlockup_touch_ts) = 0; | ||
87 | } | ||
88 | |||
82 | void touch_all_softlockup_watchdogs(void) | 89 | void touch_all_softlockup_watchdogs(void) |
83 | { | 90 | { |
84 | int cpu; | 91 | int cpu; |
85 | 92 | ||
86 | /* Cause each CPU to re-update its timestamp rather than complain */ | 93 | /* Cause each CPU to re-update its timestamp rather than complain */ |
87 | for_each_online_cpu(cpu) | 94 | for_each_online_cpu(cpu) |
88 | per_cpu(touch_timestamp, cpu) = 0; | 95 | per_cpu(softlockup_touch_ts, cpu) = 0; |
89 | } | 96 | } |
90 | EXPORT_SYMBOL(touch_all_softlockup_watchdogs); | 97 | EXPORT_SYMBOL(touch_all_softlockup_watchdogs); |
91 | 98 | ||
@@ -104,28 +111,36 @@ int proc_dosoftlockup_thresh(struct ctl_table *table, int write, | |||
104 | void softlockup_tick(void) | 111 | void softlockup_tick(void) |
105 | { | 112 | { |
106 | int this_cpu = smp_processor_id(); | 113 | int this_cpu = smp_processor_id(); |
107 | unsigned long touch_timestamp = per_cpu(touch_timestamp, this_cpu); | 114 | unsigned long touch_ts = per_cpu(softlockup_touch_ts, this_cpu); |
108 | unsigned long print_timestamp; | 115 | unsigned long print_ts; |
109 | struct pt_regs *regs = get_irq_regs(); | 116 | struct pt_regs *regs = get_irq_regs(); |
110 | unsigned long now; | 117 | unsigned long now; |
111 | 118 | ||
112 | /* Is detection switched off? */ | 119 | /* Is detection switched off? */ |
113 | if (!per_cpu(watchdog_task, this_cpu) || softlockup_thresh <= 0) { | 120 | if (!per_cpu(softlockup_watchdog, this_cpu) || softlockup_thresh <= 0) { |
114 | /* Be sure we don't false trigger if switched back on */ | 121 | /* Be sure we don't false trigger if switched back on */ |
115 | if (touch_timestamp) | 122 | if (touch_ts) |
116 | per_cpu(touch_timestamp, this_cpu) = 0; | 123 | per_cpu(softlockup_touch_ts, this_cpu) = 0; |
117 | return; | 124 | return; |
118 | } | 125 | } |
119 | 126 | ||
120 | if (touch_timestamp == 0) { | 127 | if (touch_ts == 0) { |
128 | if (unlikely(per_cpu(softlock_touch_sync, this_cpu))) { | ||
129 | /* | ||
130 | * If the time stamp was touched atomically | ||
131 | * make sure the scheduler tick is up to date. | ||
132 | */ | ||
133 | per_cpu(softlock_touch_sync, this_cpu) = false; | ||
134 | sched_clock_tick(); | ||
135 | } | ||
121 | __touch_softlockup_watchdog(); | 136 | __touch_softlockup_watchdog(); |
122 | return; | 137 | return; |
123 | } | 138 | } |
124 | 139 | ||
125 | print_timestamp = per_cpu(print_timestamp, this_cpu); | 140 | print_ts = per_cpu(softlockup_print_ts, this_cpu); |
126 | 141 | ||
127 | /* report at most once a second */ | 142 | /* report at most once a second */ |
128 | if (print_timestamp == touch_timestamp || did_panic) | 143 | if (print_ts == touch_ts || did_panic) |
129 | return; | 144 | return; |
130 | 145 | ||
131 | /* do not print during early bootup: */ | 146 | /* do not print during early bootup: */ |
@@ -140,18 +155,18 @@ void softlockup_tick(void) | |||
140 | * Wake up the high-prio watchdog task twice per | 155 | * Wake up the high-prio watchdog task twice per |
141 | * threshold timespan. | 156 | * threshold timespan. |
142 | */ | 157 | */ |
143 | if (now > touch_timestamp + softlockup_thresh/2) | 158 | if (time_after(now - softlockup_thresh/2, touch_ts)) |
144 | wake_up_process(per_cpu(watchdog_task, this_cpu)); | 159 | wake_up_process(per_cpu(softlockup_watchdog, this_cpu)); |
145 | 160 | ||
146 | /* Warn about unreasonable delays: */ | 161 | /* Warn about unreasonable delays: */ |
147 | if (now <= (touch_timestamp + softlockup_thresh)) | 162 | if (time_before_eq(now - softlockup_thresh, touch_ts)) |
148 | return; | 163 | return; |
149 | 164 | ||
150 | per_cpu(print_timestamp, this_cpu) = touch_timestamp; | 165 | per_cpu(softlockup_print_ts, this_cpu) = touch_ts; |
151 | 166 | ||
152 | spin_lock(&print_lock); | 167 | spin_lock(&print_lock); |
153 | printk(KERN_ERR "BUG: soft lockup - CPU#%d stuck for %lus! [%s:%d]\n", | 168 | printk(KERN_ERR "BUG: soft lockup - CPU#%d stuck for %lus! [%s:%d]\n", |
154 | this_cpu, now - touch_timestamp, | 169 | this_cpu, now - touch_ts, |
155 | current->comm, task_pid_nr(current)); | 170 | current->comm, task_pid_nr(current)); |
156 | print_modules(); | 171 | print_modules(); |
157 | print_irqtrace_events(current); | 172 | print_irqtrace_events(current); |
@@ -209,32 +224,32 @@ cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) | |||
209 | switch (action) { | 224 | switch (action) { |
210 | case CPU_UP_PREPARE: | 225 | case CPU_UP_PREPARE: |
211 | case CPU_UP_PREPARE_FROZEN: | 226 | case CPU_UP_PREPARE_FROZEN: |
212 | BUG_ON(per_cpu(watchdog_task, hotcpu)); | 227 | BUG_ON(per_cpu(softlockup_watchdog, hotcpu)); |
213 | p = kthread_create(watchdog, hcpu, "watchdog/%d", hotcpu); | 228 | p = kthread_create(watchdog, hcpu, "watchdog/%d", hotcpu); |
214 | if (IS_ERR(p)) { | 229 | if (IS_ERR(p)) { |
215 | printk(KERN_ERR "watchdog for %i failed\n", hotcpu); | 230 | printk(KERN_ERR "watchdog for %i failed\n", hotcpu); |
216 | return NOTIFY_BAD; | 231 | return NOTIFY_BAD; |
217 | } | 232 | } |
218 | per_cpu(touch_timestamp, hotcpu) = 0; | 233 | per_cpu(softlockup_touch_ts, hotcpu) = 0; |
219 | per_cpu(watchdog_task, hotcpu) = p; | 234 | per_cpu(softlockup_watchdog, hotcpu) = p; |
220 | kthread_bind(p, hotcpu); | 235 | kthread_bind(p, hotcpu); |
221 | break; | 236 | break; |
222 | case CPU_ONLINE: | 237 | case CPU_ONLINE: |
223 | case CPU_ONLINE_FROZEN: | 238 | case CPU_ONLINE_FROZEN: |
224 | wake_up_process(per_cpu(watchdog_task, hotcpu)); | 239 | wake_up_process(per_cpu(softlockup_watchdog, hotcpu)); |
225 | break; | 240 | break; |
226 | #ifdef CONFIG_HOTPLUG_CPU | 241 | #ifdef CONFIG_HOTPLUG_CPU |
227 | case CPU_UP_CANCELED: | 242 | case CPU_UP_CANCELED: |
228 | case CPU_UP_CANCELED_FROZEN: | 243 | case CPU_UP_CANCELED_FROZEN: |
229 | if (!per_cpu(watchdog_task, hotcpu)) | 244 | if (!per_cpu(softlockup_watchdog, hotcpu)) |
230 | break; | 245 | break; |
231 | /* Unbind so it can run. Fall thru. */ | 246 | /* Unbind so it can run. Fall thru. */ |
232 | kthread_bind(per_cpu(watchdog_task, hotcpu), | 247 | kthread_bind(per_cpu(softlockup_watchdog, hotcpu), |
233 | cpumask_any(cpu_online_mask)); | 248 | cpumask_any(cpu_online_mask)); |
234 | case CPU_DEAD: | 249 | case CPU_DEAD: |
235 | case CPU_DEAD_FROZEN: | 250 | case CPU_DEAD_FROZEN: |
236 | p = per_cpu(watchdog_task, hotcpu); | 251 | p = per_cpu(softlockup_watchdog, hotcpu); |
237 | per_cpu(watchdog_task, hotcpu) = NULL; | 252 | per_cpu(softlockup_watchdog, hotcpu) = NULL; |
238 | kthread_stop(p); | 253 | kthread_stop(p); |
239 | break; | 254 | break; |
240 | #endif /* CONFIG_HOTPLUG_CPU */ | 255 | #endif /* CONFIG_HOTPLUG_CPU */ |