|
@@ -40,6 +40,11 @@ int __read_mostly sysctl_hung_task_check_count = PID_MAX_LIMIT;
|
|
*/
|
|
*/
|
|
unsigned long __read_mostly sysctl_hung_task_timeout_secs = CONFIG_DEFAULT_HUNG_TASK_TIMEOUT;
|
|
unsigned long __read_mostly sysctl_hung_task_timeout_secs = CONFIG_DEFAULT_HUNG_TASK_TIMEOUT;
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * Zero (default value) means use sysctl_hung_task_timeout_secs:
|
|
|
|
+ */
|
|
|
|
+unsigned long __read_mostly sysctl_hung_task_check_interval_secs;
|
|
|
|
+
|
|
int __read_mostly sysctl_hung_task_warnings = 10;
|
|
int __read_mostly sysctl_hung_task_warnings = 10;
|
|
|
|
|
|
static int __read_mostly did_panic;
|
|
static int __read_mostly did_panic;
|
|
@@ -98,8 +103,11 @@ static void check_hung_task(struct task_struct *t, unsigned long timeout)
|
|
|
|
|
|
if (switch_count != t->last_switch_count) {
|
|
if (switch_count != t->last_switch_count) {
|
|
t->last_switch_count = switch_count;
|
|
t->last_switch_count = switch_count;
|
|
|
|
+ t->last_switch_time = jiffies;
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
+ if (time_is_after_jiffies(t->last_switch_time + timeout * HZ))
|
|
|
|
+ return;
|
|
|
|
|
|
trace_sched_process_hang(t);
|
|
trace_sched_process_hang(t);
|
|
|
|
|
|
@@ -245,8 +253,13 @@ static int watchdog(void *dummy)
|
|
|
|
|
|
for ( ; ; ) {
|
|
for ( ; ; ) {
|
|
unsigned long timeout = sysctl_hung_task_timeout_secs;
|
|
unsigned long timeout = sysctl_hung_task_timeout_secs;
|
|
- long t = hung_timeout_jiffies(hung_last_checked, timeout);
|
|
|
|
|
|
+ unsigned long interval = sysctl_hung_task_check_interval_secs;
|
|
|
|
+ long t;
|
|
|
|
|
|
|
|
+ if (interval == 0)
|
|
|
|
+ interval = timeout;
|
|
|
|
+ interval = min_t(unsigned long, interval, timeout);
|
|
|
|
+ t = hung_timeout_jiffies(hung_last_checked, interval);
|
|
if (t <= 0) {
|
|
if (t <= 0) {
|
|
if (!atomic_xchg(&reset_hung_task, 0))
|
|
if (!atomic_xchg(&reset_hung_task, 0))
|
|
check_hung_uninterruptible_tasks(timeout);
|
|
check_hung_uninterruptible_tasks(timeout);
|