Skip to content

Commit

Permalink
kernel/hung_task.c: use timeout diff when timeout is updated
Browse files Browse the repository at this point in the history
When new timeout is written to /proc/sys/kernel/hung_task_timeout_secs,
khungtaskd is interrupted and again sleeps for full timeout duration.

This means that hang task will not be checked if new timeout is written
periodically within old timeout duration and/or checking of hang task
will be delayed for up to previous timeout duration.  Fix this by
remembering last time khungtaskd checked hang task.

This change will allow other watchdog tasks (if any) to share khungtaskd
by sleeping for minimal timeout diff of all watchdog tasks.  Doing more
watchdog tasks from khungtaskd will reduce the possibility of printk()
collisions by multiple watchdog threads.

Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Aaron Tomlin <atomlin@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
  • Loading branch information
Tetsuo Handa authored and torvalds committed Mar 22, 2016
1 parent 3f2b1a0 commit b4aa14a
Showing 1 changed file with 13 additions and 8 deletions.
21 changes: 13 additions & 8 deletions kernel/hung_task.c
Original file line number Diff line number Diff line change
Expand Up @@ -185,10 +185,12 @@ static void check_hung_uninterruptible_tasks(unsigned long timeout)
rcu_read_unlock();
}

static unsigned long timeout_jiffies(unsigned long timeout)
static long hung_timeout_jiffies(unsigned long last_checked,
unsigned long timeout)
{
/* timeout of 0 will disable the watchdog */
return timeout ? timeout * HZ : MAX_SCHEDULE_TIMEOUT;
return timeout ? last_checked - jiffies + timeout * HZ :
MAX_SCHEDULE_TIMEOUT;
}

/*
Expand Down Expand Up @@ -224,18 +226,21 @@ EXPORT_SYMBOL_GPL(reset_hung_task_detector);
*/
static int watchdog(void *dummy)
{
unsigned long hung_last_checked = jiffies;

set_user_nice(current, 0);

for ( ; ; ) {
unsigned long timeout = sysctl_hung_task_timeout_secs;
long t = hung_timeout_jiffies(hung_last_checked, timeout);

while (schedule_timeout_interruptible(timeout_jiffies(timeout)))
timeout = sysctl_hung_task_timeout_secs;

if (atomic_xchg(&reset_hung_task, 0))
if (t <= 0) {
if (!atomic_xchg(&reset_hung_task, 0))
check_hung_uninterruptible_tasks(timeout);
hung_last_checked = jiffies;
continue;

check_hung_uninterruptible_tasks(timeout);
}
schedule_timeout_interruptible(t);
}

return 0;
Expand Down

0 comments on commit b4aa14a

Please sign in to comment.