Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 27922b4260f65d317aabda37e42bbbff > files > 1941

kernel-2.6.18-238.el5.src.rpm

From: Jerome Marchand <jmarchan@redhat.com>
Date: Fri, 18 Jun 2010 15:15:51 -0400
Subject: [misc] handle dead hung uninterruptible tasks correctly
Message-id: <4C1B8DA7.1020805@redhat.com>
Patchwork-id: 26315
O-Subject: [RHEL5.6 PATCH] handle correctly dead tasks in
	check_hung_uninterruptible_tasks()
Bugzilla: 582237
RH-Acked-by: Don Zickus <dzickus@redhat.com>
RH-Acked-by: Amerigo Wang <amwang@redhat.com>
RH-Acked-by: Oleg Nesterov <oleg@redhat.com>

Bugzilla:
https://bugzilla.redhat.com/show_bug.cgi?id=582237

Description:
A few lines of code have been lost in the backport of the hung task
detection feature (from check_hung_uninterruptible_tasks()):

        do_each_thread(g, t) {
                if (!max_count--)
                        goto unlock;
                if (!--batch_count) {
                        batch_count = HUNG_TASK_BATCHING;
                        rcu_lock_break(g, t);
>>>                     /* Exit if t or g was unhashed during refresh. */
>>>                     if (t->state == TASK_DEAD || g->state == TASK_DEAD)
>>>                             goto unlock;
                }
                /* use "==" to skip the TASK_KILLABLE tasks waiting on NFS */
                if (t->state == TASK_UNINTERRUPTIBLE)
                        check_hung_task(t, timeout);
        } while_each_thread(g, t);

Without that bit of code we could end up working with non consistent
data.

Test status:
Built and booted. I was not able to trigger a bug with the unpatched
kernel, so I can't say I've tested the bugfix.

Regards,
Jerome


diff --git a/kernel/hung_task.c b/kernel/hung_task.c
index 0fc6038..59dcfe9 100644
--- a/kernel/hung_task.c
+++ b/kernel/hung_task.c
@@ -148,6 +148,10 @@ static void check_hung_uninterruptible_tasks(unsigned long timeout)
 		if (!--batch_count) {
 			batch_count = HUNG_TASK_BATCHING;
 			rcu_lock_break(g, t);
+			/* Exit if t or g was unhashed during refresh. */
+			if (t->flags & PF_DEAD || g->flags & PF_DEAD)
+				goto unlock;
+
 		}
 		/* use "==" to skip the TASK_KILLABLE tasks waiting on NFS */
 		if (t->state == TASK_UNINTERRUPTIBLE)