aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorMandeep Singh Baines <msb@google.com>2009-02-04 23:35:48 -0500
committerIngo Molnar <mingo@elte.hu>2009-02-05 13:54:57 -0500
commitce9dbe244bf2063c41792e40dae7745957b118e0 (patch)
treea6278f5f012d2284aecbeb17bf5371d4864963d3 /kernel
parent5e54f5986a579b8445aa1d5ad3435c2cf7568bed (diff)
softlockup: check all tasks in hung_task
Impact: extend the scope of hung-task checks Changed the default value of hung_task_check_count to PID_MAX_LIMIT. hung_task_batch_count added to put an upper bound on the critical section. Every hung_task_batch_count checks, the rcu lock is never held for a too long time. Keeping the critical section small minimizes time preemption is disabled and keeps rcu grace periods small. To prevent following a stale pointer, get_task_struct is called on g and t. To verify that g and t have not been unhashed while outside the critical section, the task states are checked. The design was proposed by Frédéric Weisbecker. Signed-off-by: Mandeep Singh Baines <msb@google.com> Suggested-by: Frédéric Weisbecker <fweisbec@gmail.com> Acked-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/hung_task.c39
1 files changed, 37 insertions, 2 deletions
diff --git a/kernel/hung_task.c b/kernel/hung_task.c
index ba8ccd432963..481ca8b5c2bc 100644
--- a/kernel/hung_task.c
+++ b/kernel/hung_task.c
@@ -17,9 +17,18 @@
17#include <linux/sysctl.h> 17#include <linux/sysctl.h>
18 18
19/* 19/*
20 * Have a reasonable limit on the number of tasks checked: 20 * The number of tasks checked:
21 */ 21 */
22unsigned long __read_mostly sysctl_hung_task_check_count = 1024; 22unsigned long __read_mostly sysctl_hung_task_check_count = PID_MAX_LIMIT;
23
24/*
25 * Limit number of tasks checked in a batch.
26 *
27 * This value controls the preemptibility of khungtaskd since preemption
28 * is disabled during the critical section. It also controls the size of
29 * the RCU grace period. So it needs to be upper-bound.
30 */
31#define HUNG_TASK_BATCHING 1024
23 32
24/* 33/*
25 * Zero means infinite timeout - no checking done: 34 * Zero means infinite timeout - no checking done:
@@ -110,6 +119,24 @@ static void check_hung_task(struct task_struct *t, unsigned long now,
110} 119}
111 120
112/* 121/*
122 * To avoid extending the RCU grace period for an unbounded amount of time,
123 * periodically exit the critical section and enter a new one.
124 *
125 * For preemptible RCU it is sufficient to call rcu_read_unlock in order
126 * exit the grace period. For classic RCU, a reschedule is required.
127 */
128static void rcu_lock_break(struct task_struct *g, struct task_struct *t)
129{
130 get_task_struct(g);
131 get_task_struct(t);
132 rcu_read_unlock();
133 cond_resched();
134 rcu_read_lock();
135 put_task_struct(t);
136 put_task_struct(g);
137}
138
139/*
113 * Check whether a TASK_UNINTERRUPTIBLE does not get woken up for 140 * Check whether a TASK_UNINTERRUPTIBLE does not get woken up for
114 * a really long time (120 seconds). If that happens, print out 141 * a really long time (120 seconds). If that happens, print out
115 * a warning. 142 * a warning.
@@ -117,6 +144,7 @@ static void check_hung_task(struct task_struct *t, unsigned long now,
117static void check_hung_uninterruptible_tasks(unsigned long timeout) 144static void check_hung_uninterruptible_tasks(unsigned long timeout)
118{ 145{
119 int max_count = sysctl_hung_task_check_count; 146 int max_count = sysctl_hung_task_check_count;
147 int batch_count = HUNG_TASK_BATCHING;
120 unsigned long now = get_timestamp(); 148 unsigned long now = get_timestamp();
121 struct task_struct *g, *t; 149 struct task_struct *g, *t;
122 150
@@ -131,6 +159,13 @@ static void check_hung_uninterruptible_tasks(unsigned long timeout)
131 do_each_thread(g, t) { 159 do_each_thread(g, t) {
132 if (!--max_count) 160 if (!--max_count)
133 goto unlock; 161 goto unlock;
162 if (!--batch_count) {
163 batch_count = HUNG_TASK_BATCHING;
164 rcu_lock_break(g, t);
165 /* Exit if t or g was unhashed during refresh. */
166 if (t->state == TASK_DEAD || g->state == TASK_DEAD)
167 goto unlock;
168 }
134 /* use "==" to skip the TASK_KILLABLE tasks waiting on NFS */ 169 /* use "==" to skip the TASK_KILLABLE tasks waiting on NFS */
135 if (t->state == TASK_UNINTERRUPTIBLE) 170 if (t->state == TASK_UNINTERRUPTIBLE)
136 check_hung_task(t, now, timeout); 171 check_hung_task(t, now, timeout);