Skip to content

Commit 5aec788

Browse files
author
Peter Zijlstra
committed
sched: Fix TASK_state comparisons
Task state is fundamentally a bitmask; direct comparisons are probably not working as intended. Specifically the normal wait-state have a number of possible modifiers: TASK_UNINTERRUPTIBLE: TASK_WAKEKILL, TASK_NOLOAD, TASK_FREEZABLE TASK_INTERRUPTIBLE: TASK_FREEZABLE Specifically, the addition of TASK_FREEZABLE wrecked __wait_is_interruptible(). This however led to an audit of direct comparisons yielding the rest of the changes. Fixes: f5d39b0 ("freezer,sched: Rewrite core freezer logic") Reported-by: Christian Borntraeger <borntraeger@linux.ibm.com> Debugged-by: Christian Borntraeger <borntraeger@linux.ibm.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Tested-by: Christian Borntraeger <borntraeger@linux.ibm.com>
1 parent 7e9518b commit 5aec788

File tree

3 files changed

+8
-4
lines changed

3 files changed

+8
-4
lines changed

include/linux/wait.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ static inline void wake_up_pollfree(struct wait_queue_head *wq_head)
281281

282282
#define ___wait_is_interruptible(state) \
283283
(!__builtin_constant_p(state) || \
284-
state == TASK_INTERRUPTIBLE || state == TASK_KILLABLE) \
284+
(state & (TASK_INTERRUPTIBLE | TASK_WAKEKILL)))
285285

286286
extern void init_wait_entry(struct wait_queue_entry *wq_entry, int flags);
287287

kernel/hung_task.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -191,15 +191,19 @@ static void check_hung_uninterruptible_tasks(unsigned long timeout)
191191
hung_task_show_lock = false;
192192
rcu_read_lock();
193193
for_each_process_thread(g, t) {
194+
unsigned int state;
195+
194196
if (!max_count--)
195197
goto unlock;
196198
if (time_after(jiffies, last_break + HUNG_TASK_LOCK_BREAK)) {
197199
if (!rcu_lock_break(g, t))
198200
goto unlock;
199201
last_break = jiffies;
200202
}
201-
/* use "==" to skip the TASK_KILLABLE tasks waiting on NFS */
202-
if (READ_ONCE(t->__state) == TASK_UNINTERRUPTIBLE)
203+
/* skip the TASK_KILLABLE tasks -- these can be killed */
204+
state = READ_ONCE(t->__state);
205+
if ((state & TASK_UNINTERRUPTIBLE) &&
206+
!(state & TASK_WAKEKILL))
203207
check_hung_task(t, timeout);
204208
}
205209
unlock:

kernel/sched/core.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8884,7 +8884,7 @@ state_filter_match(unsigned long state_filter, struct task_struct *p)
88848884
* When looking for TASK_UNINTERRUPTIBLE skip TASK_IDLE (allows
88858885
* TASK_KILLABLE).
88868886
*/
8887-
if (state_filter == TASK_UNINTERRUPTIBLE && state == TASK_IDLE)
8887+
if (state_filter == TASK_UNINTERRUPTIBLE && (state & TASK_NOLOAD))
88888888
return false;
88898889

88908890
return true;

0 commit comments

Comments
 (0)