aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>2016-03-22 17:24:39 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-03-22 18:36:02 -0400
commitb4aa14a63cb3194d8eab355fcee194838ab09121 (patch)
tree84e104cac5b6ed9a629ea5c5d3e9c56e2c332db4
parent3f2b1a04f44933f2d6fe0a9bf9a9c1c452df23f7 (diff)
kernel/hung_task.c: use timeout diff when timeout is updated
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>
-rw-r--r--kernel/hung_task.c21
1 files changed, 13 insertions, 8 deletions
diff --git a/kernel/hung_task.c b/kernel/hung_task.c
index e0f90c2b57aa..d234022805dc 100644
--- a/kernel/hung_task.c
+++ b/kernel/hung_task.c
@@ -185,10 +185,12 @@ static void check_hung_uninterruptible_tasks(unsigned long timeout)
185 rcu_read_unlock(); 185 rcu_read_unlock();
186} 186}
187 187
188static unsigned long timeout_jiffies(unsigned long timeout) 188static long hung_timeout_jiffies(unsigned long last_checked,
189 unsigned long timeout)
189{ 190{
190 /* timeout of 0 will disable the watchdog */ 191 /* timeout of 0 will disable the watchdog */
191 return timeout ? timeout * HZ : MAX_SCHEDULE_TIMEOUT; 192 return timeout ? last_checked - jiffies + timeout * HZ :
193 MAX_SCHEDULE_TIMEOUT;
192} 194}
193 195
194/* 196/*
@@ -224,18 +226,21 @@ EXPORT_SYMBOL_GPL(reset_hung_task_detector);
224 */ 226 */
225static int watchdog(void *dummy) 227static int watchdog(void *dummy)
226{ 228{
229 unsigned long hung_last_checked = jiffies;
230
227 set_user_nice(current, 0); 231 set_user_nice(current, 0);
228 232
229 for ( ; ; ) { 233 for ( ; ; ) {
230 unsigned long timeout = sysctl_hung_task_timeout_secs; 234 unsigned long timeout = sysctl_hung_task_timeout_secs;
235 long t = hung_timeout_jiffies(hung_last_checked, timeout);
231 236
232 while (schedule_timeout_interruptible(timeout_jiffies(timeout))) 237 if (t <= 0) {
233 timeout = sysctl_hung_task_timeout_secs; 238 if (!atomic_xchg(&reset_hung_task, 0))
234 239 check_hung_uninterruptible_tasks(timeout);
235 if (atomic_xchg(&reset_hung_task, 0)) 240 hung_last_checked = jiffies;
236 continue; 241 continue;
237 242 }
238 check_hung_uninterruptible_tasks(timeout); 243 schedule_timeout_interruptible(t);
239 } 244 }
240 245
241 return 0; 246 return 0;