/* * The number of tasks checked:
*/ staticint __read_mostly sysctl_hung_task_check_count = PID_MAX_LIMIT;
/* * Total number of tasks detected as hung since boot:
*/ staticunsignedlong __read_mostly sysctl_hung_task_detect_count;
/* * Limit number of tasks checked in a batch. * * This value controls the preemptibility of khungtaskd since preemption * is disabled during the critical section. It also controls the size of * the RCU grace period. So it needs to be upper-bound.
*/ #define HUNG_TASK_LOCK_BREAK (HZ / 10)
/* * Zero means infinite timeout - no checking done:
*/ unsignedlong __read_mostly sysctl_hung_task_timeout_secs = CONFIG_DEFAULT_HUNG_TASK_TIMEOUT;
EXPORT_SYMBOL_GPL(sysctl_hung_task_timeout_secs);
/* * Zero (default value) means use sysctl_hung_task_timeout_secs:
*/ staticunsignedlong __read_mostly sysctl_hung_task_check_interval_secs;
#ifdef CONFIG_SMP /* * Should we dump all CPUs backtraces in a hung task event? * Defaults to 0, can be changed via sysctl.
*/ staticunsignedint __read_mostly sysctl_hung_task_all_cpu_backtrace; #else #define sysctl_hung_task_all_cpu_backtrace 0 #endif/* CONFIG_SMP */
/* * Should we panic (and reboot, if panic_timeout= is set) when a * hung task is detected:
*/ staticunsignedint __read_mostly sysctl_hung_task_panic =
IS_ENABLED(CONFIG_BOOTPARAM_HUNG_TASK_PANIC);
if (unlikely(!owner)) { switch (blocker_type) { case BLOCKER_TYPE_MUTEX:
pr_err("INFO: task %s:%d is blocked on a mutex, but the owner is not found.\n",
task->comm, task->pid); break; case BLOCKER_TYPE_SEM:
pr_err("INFO: task %s:%d is blocked on a semaphore, but the last holder is not found.\n",
task->comm, task->pid); break; case BLOCKER_TYPE_RWSEM_READER: case BLOCKER_TYPE_RWSEM_WRITER:
pr_err("INFO: task %s:%d is blocked on an rw-semaphore, but the owner is not found.\n",
task->comm, task->pid); break;
} return;
}
/* Ensure the owner information is correct. */
for_each_process_thread(g, t) { if ((unsignedlong)t != owner) continue;
switch (blocker_type) { case BLOCKER_TYPE_MUTEX:
pr_err("INFO: task %s:%d is blocked on a mutex likely owned by task %s:%d.\n",
task->comm, task->pid, t->comm, t->pid); break; case BLOCKER_TYPE_SEM:
pr_err("INFO: task %s:%d blocked on a semaphore likely last held by task %s:%d\n",
task->comm, task->pid, t->comm, t->pid); break; case BLOCKER_TYPE_RWSEM_READER: case BLOCKER_TYPE_RWSEM_WRITER:
pr_err("INFO: task %s:%d <%s> blocked on an rw-semaphore likely owned by task %s:%d <%s>\n",
task->comm, task->pid, rwsem_blocked_as, t->comm,
t->pid, rwsem_blocked_by); break;
}
sched_show_task(t); return;
}
} #else staticinlinevoid debug_show_blocker(struct task_struct *task)
{
} #endif
/* * Ensure the task is not frozen. * Also, skip vfork and any other user process that freezer should skip.
*/ if (unlikely(READ_ONCE(t->__state) & TASK_FROZEN)) return;
/* * When a freshly created task is scheduled once, changes its state to * TASK_UNINTERRUPTIBLE without having ever been switched out once, it * musn't be checked.
*/ if (unlikely(!switch_count)) return;
if (switch_count != t->last_switch_count) {
t->last_switch_count = switch_count;
t->last_switch_time = jiffies; return;
} if (time_is_after_jiffies(t->last_switch_time + timeout * HZ)) return;
/* * This counter tracks the total number of tasks detected as hung * since boot.
*/
sysctl_hung_task_detect_count++;
/* * Ok, the task did not get scheduled for more than 2 minutes, * complain:
*/ if (sysctl_hung_task_warnings || hung_task_call_panic) { if (sysctl_hung_task_warnings > 0)
sysctl_hung_task_warnings--;
pr_err("INFO: task %s:%d blocked for more than %ld seconds.\n",
t->comm, t->pid, (jiffies - t->last_switch_time) / HZ);
pr_err(" %s %s %.*s\n",
print_tainted(), init_utsname()->release,
(int)strcspn(init_utsname()->version, " "),
init_utsname()->version); if (t->flags & PF_POSTCOREDUMP)
pr_err(" Blocked by coredump.\n");
pr_err("\"echo 0 > /proc/sys/kernel/hung_task_timeout_secs\"" " disables this message.\n");
sched_show_task(t);
debug_show_blocker(t);
hung_task_show_lock = true;
if (sysctl_hung_task_all_cpu_backtrace)
hung_task_show_all_bt = true; if (!sysctl_hung_task_warnings)
pr_info("Future hung task reports are suppressed, see sysctl kernel.hung_task_warnings\n");
}
touch_nmi_watchdog();
}
/* * To avoid extending the RCU grace period for an unbounded amount of time, * periodically exit the critical section and enter a new one. * * For preemptible RCU it is sufficient to call rcu_read_unlock in order * to exit the grace period. For classic RCU, a reschedule is required.
*/ staticbool rcu_lock_break(struct task_struct *g, struct task_struct *t)
{ bool can_cont;
/* * Check whether a TASK_UNINTERRUPTIBLE does not get woken up for * a really long time (120 seconds). If that happens, print out * a warning.
*/ staticvoid check_hung_uninterruptible_tasks(unsignedlong timeout)
{ int max_count = sysctl_hung_task_check_count; unsignedlong last_break = jiffies; struct task_struct *g, *t;
/* * If the system crashed already then all bets are off, * do not report extra hung tasks:
*/ if (test_taint(TAINT_DIE) || did_panic) return;
if (!max_count--) goto unlock; if (time_after(jiffies, last_break + HUNG_TASK_LOCK_BREAK)) { if (!rcu_lock_break(g, t)) goto unlock;
last_break = jiffies;
} /* * skip the TASK_KILLABLE tasks -- these can be killed * skip the TASK_IDLE tasks -- those are genuinely idle
*/
state = READ_ONCE(t->__state); if ((state & TASK_UNINTERRUPTIBLE) &&
!(state & TASK_WAKEKILL) &&
!(state & TASK_NOLOAD))
check_hung_task(t, timeout);
}
unlock:
rcu_read_unlock(); if (hung_task_show_lock)
debug_show_all_locks();
if (hung_task_show_all_bt) {
hung_task_show_all_bt = false;
trigger_all_cpu_backtrace();
}
if (hung_task_call_panic)
panic("hung_task: blocked tasks");
}
staticlong hung_timeout_jiffies(unsignedlong last_checked, unsignedlong timeout)
{ /* timeout of 0 will disable the watchdog */ return timeout ? last_checked - jiffies + timeout * HZ :
MAX_SCHEDULE_TIMEOUT;
}
#ifdef CONFIG_SYSCTL /* * Process updating of timeout sysctl
*/ staticint proc_dohung_task_timeout_secs(conststruct ctl_table *table, int write, void *buffer,
size_t *lenp, loff_t *ppos)
{ int ret;
ret = proc_doulongvec_minmax(table, write, buffer, lenp, ppos);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.