diff options
author | Frederic Weisbecker <fweisbec@gmail.com> | 2009-02-10 16:52:37 +0100 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-02-11 11:04:16 +0100 |
commit | cf2592f59c0e8ed4308adbdb2e0a88655379d579 (patch) | |
tree | 383b30bc13af8ce83e15825b041d8bb791ea4cea /kernel/hung_task.c | |
parent | 17406b82d621930cca8ccc1272cdac9a7dae8e40 (diff) | |
download | lwn-cf2592f59c0e8ed4308adbdb2e0a88655379d579.tar.gz lwn-cf2592f59c0e8ed4308adbdb2e0a88655379d579.zip |
softlockup: ensure the task has been switched out once
When we check if a task has been switched out since the last scan, we might
have a race condition on the following scenario:
- the task is freshly created and scheduled
- it puts its state to TASK_UNINTERRUPTIBLE and is not yet switched out
- check_hung_task() scans this task and will report a false positive because
t->nvcsw + t->nivcsw == t->last_switch_count == 0
Add a check for such cases.
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Acked-by: Mandeep Singh Baines <msb@google.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/hung_task.c')
-rw-r--r-- | kernel/hung_task.c | 8 |
1 files changed, 7 insertions, 1 deletions
diff --git a/kernel/hung_task.c b/kernel/hung_task.c index 0c924de58cb2..022a4927b785 100644 --- a/kernel/hung_task.c +++ b/kernel/hung_task.c @@ -72,7 +72,13 @@ static void check_hung_task(struct task_struct *t, unsigned long timeout) { unsigned long switch_count = t->nvcsw + t->nivcsw; - if (t->flags & PF_FROZEN) + /* + * Ensure the task is not frozen. + * Also, 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(t->flags & PF_FROZEN || !switch_count)) return; if (switch_count != t->last_switch_count) { |