diff --git a/include/linux/sched.h b/include/linux/sched.h index a2cd1585..51441b2 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -851,6 +851,7 @@ struct task_struct { unsigned long last_switch_count; unsigned long last_switch_time; #endif + unsigned long last_sigkill_time; /* Filesystem information: */ struct fs_struct *fs; diff --git a/kernel/hung_task.c b/kernel/hung_task.c index f108a95..74d381c 100644 --- a/kernel/hung_task.c +++ b/kernel/hung_task.c @@ -164,6 +164,23 @@ static bool rcu_lock_break(struct task_struct *g, struct task_struct *t) return can_cont; } +static void print_all_running_threads(void) +{ +#ifdef CONFIG_SMP + struct task_struct *g; + struct task_struct *t; + + rcu_read_lock(); + for_each_process_thread(g, t) { + if (!t->on_cpu || t == current) + continue; + pr_err("INFO: Currently running\n"); + sched_show_task(t); + } + rcu_read_unlock(); +#endif +} + /* * Check whether a TASK_UNINTERRUPTIBLE does not get woken up for * a really long time (120 seconds). If that happens, print out @@ -192,6 +209,13 @@ static void check_hung_uninterruptible_tasks(unsigned long timeout) goto unlock; last_break = jiffies; } + if (unlikely(t->last_sigkill_time && + time_after(jiffies, t->last_sigkill_time + 10 * HZ) && + !(t->flags & PF_EXITING))) { + pr_err("INFO: task %s:%d can't die for more than %ld seconds.\n", + t->comm, t->pid, (jiffies - t->last_sigkill_time) / HZ); + sched_show_task(t); + } /* use "==" to skip the TASK_KILLABLE tasks waiting on NFS */ if (t->state == TASK_UNINTERRUPTIBLE) check_hung_task(t, timeout); @@ -201,7 +225,7 @@ static void check_hung_uninterruptible_tasks(unsigned long timeout) if (hung_task_show_lock) debug_show_all_locks(); if (hung_task_call_panic) { - trigger_all_cpu_backtrace(); + print_all_running_threads(); panic("hung_task: blocked tasks"); } } diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c index d06190f..2a84aba 100644 --- a/kernel/locking/lockdep.c +++ b/kernel/locking/lockdep.c @@ -596,12 +596,6 @@ static void lockdep_print_held_locks(struct task_struct *p) else printk("%d lock%s held by %s/%d:\n", depth, depth > 1 ? "s" : "", p->comm, task_pid_nr(p)); - /* - * It's not reliable to print a task's held locks if it's not sleeping - * and it's not the current task. - */ - if (p->state == TASK_RUNNING && p != current) - return; for (i = 0; i < depth; i++) { printk(" #%d: ", i); print_lock(p->held_locks + i); diff --git a/kernel/signal.c b/kernel/signal.c index 62f9aea..98a5c2a 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1036,6 +1036,7 @@ static void complete_signal(int sig, struct task_struct *p, enum pid_type type) do { task_clear_jobctl_pending(t, JOBCTL_PENDING_MASK); sigaddset(&t->pending.signal, SIGKILL); + t->last_sigkill_time = jiffies; signal_wake_up(t, 1); } while_each_thread(p, t); return; @@ -1046,6 +1047,8 @@ static void complete_signal(int sig, struct task_struct *p, enum pid_type type) * The signal is already in the shared-pending queue. * Tell the chosen thread to wake up and dequeue it. */ + if (sig == SIGKILL) + t->last_sigkill_time = jiffies; signal_wake_up(t, sig == SIGKILL); return; } @@ -1320,6 +1323,7 @@ int zap_other_threads(struct task_struct *p) if (t->exit_state) continue; sigaddset(&t->pending.signal, SIGKILL); + t->last_sigkill_time = jiffies; signal_wake_up(t, 1); }