Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

hung_task: dump blocker task if it is not hung

Dump the lock blocker task if it is not hung because if the blocker task
is also hung, it should be dumped by the detector. This will de-duplicate
the same stackdumps if the blocker task is also blocked by another task
(and hung).

Link: https://lkml.kernel.org/r/175391351423.688839.11917911323784986774.stgit@devnote2
Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
Suggested-by: Sergey Senozhatsky <senozhatsky@chromium.org>
Tested-by: Sergey Senozhatsky <senozhatsky@chromium.org>
Acked-by: Lance Yang <lance.yang@linux.dev>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Masami Hiramatsu (Google) and committed by
Andrew Morton
1440648c e6b9dce0

+41 -37
+41 -37
kernel/hung_task.c
··· 95 95 .notifier_call = hung_task_panic, 96 96 }; 97 97 98 + static bool task_is_hung(struct task_struct *t, unsigned long timeout) 99 + { 100 + unsigned long switch_count = t->nvcsw + t->nivcsw; 101 + unsigned int state = READ_ONCE(t->__state); 102 + 103 + /* 104 + * skip the TASK_KILLABLE tasks -- these can be killed 105 + * skip the TASK_IDLE tasks -- those are genuinely idle 106 + * skip the TASK_FROZEN task -- it reasonably stops scheduling by freezer 107 + */ 108 + if (!(state & TASK_UNINTERRUPTIBLE) || 109 + (state & (TASK_WAKEKILL | TASK_NOLOAD | TASK_FROZEN))) 110 + return false; 111 + 112 + /* 113 + * When a freshly created task is scheduled once, changes its state to 114 + * TASK_UNINTERRUPTIBLE without having ever been switched out once, it 115 + * musn't be checked. 116 + */ 117 + if (unlikely(!switch_count)) 118 + return false; 119 + 120 + if (switch_count != t->last_switch_count) { 121 + t->last_switch_count = switch_count; 122 + t->last_switch_time = jiffies; 123 + return false; 124 + } 125 + if (time_is_after_jiffies(t->last_switch_time + timeout * HZ)) 126 + return false; 127 + 128 + return true; 129 + } 98 130 99 131 #ifdef CONFIG_DETECT_HUNG_TASK_BLOCKER 100 - static void debug_show_blocker(struct task_struct *task) 132 + static void debug_show_blocker(struct task_struct *task, unsigned long timeout) 101 133 { 102 134 struct task_struct *g, *t; 103 135 unsigned long owner, blocker, blocker_type; ··· 206 174 t->pid, rwsem_blocked_by); 207 175 break; 208 176 } 209 - sched_show_task(t); 177 + /* Avoid duplicated task dump, skip if the task is also hung. */ 178 + if (!task_is_hung(t, timeout)) 179 + sched_show_task(t); 210 180 return; 211 181 } 212 182 } 213 183 #else 214 - static inline void debug_show_blocker(struct task_struct *task) 184 + static inline void debug_show_blocker(struct task_struct *task, unsigned long timeout) 215 185 { 216 186 } 217 187 #endif 218 188 219 189 static void check_hung_task(struct task_struct *t, unsigned long timeout) 220 190 { 221 - unsigned long switch_count = t->nvcsw + t->nivcsw; 222 - 223 - /* 224 - * Ensure the task is not frozen. 225 - * Also, skip vfork and any other user process that freezer should skip. 226 - */ 227 - if (unlikely(READ_ONCE(t->__state) & TASK_FROZEN)) 228 - return; 229 - 230 - /* 231 - * When a freshly created task is scheduled once, changes its state to 232 - * TASK_UNINTERRUPTIBLE without having ever been switched out once, it 233 - * musn't be checked. 234 - */ 235 - if (unlikely(!switch_count)) 236 - return; 237 - 238 - if (switch_count != t->last_switch_count) { 239 - t->last_switch_count = switch_count; 240 - t->last_switch_time = jiffies; 241 - return; 242 - } 243 - if (time_is_after_jiffies(t->last_switch_time + timeout * HZ)) 191 + if (!task_is_hung(t, timeout)) 244 192 return; 245 193 246 194 /* ··· 255 243 pr_err("\"echo 0 > /proc/sys/kernel/hung_task_timeout_secs\"" 256 244 " disables this message.\n"); 257 245 sched_show_task(t); 258 - debug_show_blocker(t); 246 + debug_show_blocker(t, timeout); 259 247 hung_task_show_lock = true; 260 248 261 249 if (sysctl_hung_task_all_cpu_backtrace) ··· 311 299 hung_task_show_lock = false; 312 300 rcu_read_lock(); 313 301 for_each_process_thread(g, t) { 314 - unsigned int state; 315 302 316 303 if (!max_count--) 317 304 goto unlock; ··· 319 308 goto unlock; 320 309 last_break = jiffies; 321 310 } 322 - /* 323 - * skip the TASK_KILLABLE tasks -- these can be killed 324 - * skip the TASK_IDLE tasks -- those are genuinely idle 325 - */ 326 - state = READ_ONCE(t->__state); 327 - if ((state & TASK_UNINTERRUPTIBLE) && 328 - !(state & TASK_WAKEKILL) && 329 - !(state & TASK_NOLOAD)) 330 - check_hung_task(t, timeout); 311 + 312 + check_hung_task(t, timeout); 331 313 } 332 314 unlock: 333 315 rcu_read_unlock();