.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Detect Hung Task |
---|
3 | 4 | * |
---|
.. | .. |
---|
19 | 20 | #include <linux/utsname.h> |
---|
20 | 21 | #include <linux/sched/signal.h> |
---|
21 | 22 | #include <linux/sched/debug.h> |
---|
| 23 | +#include <linux/sched/sysctl.h> |
---|
22 | 24 | |
---|
23 | 25 | #include <trace/events/sched.h> |
---|
| 26 | +#undef CREATE_TRACE_POINTS |
---|
| 27 | +#include <trace/hooks/hung_task.h> |
---|
24 | 28 | |
---|
25 | 29 | /* |
---|
26 | 30 | * The number of tasks checked: |
---|
.. | .. |
---|
51 | 55 | static int __read_mostly did_panic; |
---|
52 | 56 | static bool hung_task_show_lock; |
---|
53 | 57 | static bool hung_task_call_panic; |
---|
| 58 | +static bool hung_task_show_all_bt; |
---|
54 | 59 | |
---|
55 | 60 | static struct task_struct *watchdog_task; |
---|
| 61 | + |
---|
| 62 | +#ifdef CONFIG_SMP |
---|
| 63 | +/* |
---|
| 64 | + * Should we dump all CPUs backtraces in a hung task event? |
---|
| 65 | + * Defaults to 0, can be changed via sysctl. |
---|
| 66 | + */ |
---|
| 67 | +unsigned int __read_mostly sysctl_hung_task_all_cpu_backtrace; |
---|
| 68 | +#endif /* CONFIG_SMP */ |
---|
56 | 69 | |
---|
57 | 70 | /* |
---|
58 | 71 | * Should we panic (and reboot, if panic_timeout= is set) when a |
---|
.. | .. |
---|
60 | 73 | */ |
---|
61 | 74 | unsigned int __read_mostly sysctl_hung_task_panic = |
---|
62 | 75 | CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE; |
---|
63 | | - |
---|
64 | | -static int __init hung_task_panic_setup(char *str) |
---|
65 | | -{ |
---|
66 | | - int rc = kstrtouint(str, 0, &sysctl_hung_task_panic); |
---|
67 | | - |
---|
68 | | - if (rc) |
---|
69 | | - return rc; |
---|
70 | | - return 1; |
---|
71 | | -} |
---|
72 | | -__setup("hung_task_panic=", hung_task_panic_setup); |
---|
73 | 76 | |
---|
74 | 77 | static int |
---|
75 | 78 | hung_task_panic(struct notifier_block *this, unsigned long event, void *ptr) |
---|
.. | .. |
---|
91 | 94 | * Ensure the task is not frozen. |
---|
92 | 95 | * Also, skip vfork and any other user process that freezer should skip. |
---|
93 | 96 | */ |
---|
94 | | - if (unlikely(t->flags & (PF_FROZEN | PF_FREEZER_SKIP))) |
---|
95 | | - return; |
---|
| 97 | + if (unlikely(frozen_or_skipped(t))) |
---|
| 98 | + return; |
---|
96 | 99 | |
---|
97 | 100 | /* |
---|
98 | 101 | * When a freshly created task is scheduled once, changes its state to |
---|
.. | .. |
---|
126 | 129 | if (sysctl_hung_task_warnings > 0) |
---|
127 | 130 | sysctl_hung_task_warnings--; |
---|
128 | 131 | pr_err("INFO: task %s:%d blocked for more than %ld seconds.\n", |
---|
129 | | - t->comm, t->pid, timeout); |
---|
| 132 | + t->comm, t->pid, (jiffies - t->last_switch_time) / HZ); |
---|
130 | 133 | pr_err(" %s %s %.*s\n", |
---|
131 | 134 | print_tainted(), init_utsname()->release, |
---|
132 | 135 | (int)strcspn(init_utsname()->version, " "), |
---|
.. | .. |
---|
135 | 138 | " disables this message.\n"); |
---|
136 | 139 | sched_show_task(t); |
---|
137 | 140 | hung_task_show_lock = true; |
---|
| 141 | + |
---|
| 142 | + if (sysctl_hung_task_all_cpu_backtrace) |
---|
| 143 | + hung_task_show_all_bt = true; |
---|
138 | 144 | } |
---|
139 | 145 | |
---|
140 | 146 | touch_nmi_watchdog(); |
---|
.. | .. |
---|
173 | 179 | int max_count = sysctl_hung_task_check_count; |
---|
174 | 180 | unsigned long last_break = jiffies; |
---|
175 | 181 | struct task_struct *g, *t; |
---|
| 182 | + bool need_check = true; |
---|
176 | 183 | |
---|
177 | 184 | /* |
---|
178 | 185 | * If the system crashed already then all bets are off, |
---|
.. | .. |
---|
191 | 198 | goto unlock; |
---|
192 | 199 | last_break = jiffies; |
---|
193 | 200 | } |
---|
194 | | - /* use "==" to skip the TASK_KILLABLE tasks waiting on NFS */ |
---|
195 | | - if (t->state == TASK_UNINTERRUPTIBLE) |
---|
196 | | - check_hung_task(t, timeout); |
---|
| 201 | + trace_android_vh_check_uninterruptible_tasks(t, timeout, &need_check); |
---|
| 202 | + if (need_check) |
---|
| 203 | + /* use "==" to skip the TASK_KILLABLE tasks waiting on NFS */ |
---|
| 204 | + if (t->state == TASK_UNINTERRUPTIBLE) |
---|
| 205 | + check_hung_task(t, timeout); |
---|
197 | 206 | } |
---|
| 207 | + trace_android_vh_check_uninterruptible_tasks_dn(NULL); |
---|
198 | 208 | unlock: |
---|
199 | 209 | rcu_read_unlock(); |
---|
200 | 210 | if (hung_task_show_lock) |
---|
201 | 211 | debug_show_all_locks(); |
---|
202 | | - if (hung_task_call_panic) { |
---|
| 212 | + |
---|
| 213 | + if (hung_task_show_all_bt) { |
---|
| 214 | + hung_task_show_all_bt = false; |
---|
203 | 215 | trigger_all_cpu_backtrace(); |
---|
204 | | - panic("hung_task: blocked tasks"); |
---|
205 | 216 | } |
---|
| 217 | + |
---|
| 218 | + if (hung_task_call_panic) |
---|
| 219 | + panic("hung_task: blocked tasks"); |
---|
206 | 220 | } |
---|
207 | 221 | |
---|
208 | 222 | static long hung_timeout_jiffies(unsigned long last_checked, |
---|
.. | .. |
---|
217 | 231 | * Process updating of timeout sysctl |
---|
218 | 232 | */ |
---|
219 | 233 | int proc_dohung_task_timeout_secs(struct ctl_table *table, int write, |
---|
220 | | - void __user *buffer, |
---|
221 | | - size_t *lenp, loff_t *ppos) |
---|
| 234 | + void *buffer, size_t *lenp, loff_t *ppos) |
---|
222 | 235 | { |
---|
223 | 236 | int ret; |
---|
224 | 237 | |
---|