[<prev] [next>] [day] [month] [year] [list]
Message-ID: <166435241084.401.18105248631464873710.tip-bot2@tip-bot2>
Date: Wed, 28 Sep 2022 08:06:50 -0000
From: "tip-bot2 for Peter Zijlstra" <tip-bot2@...utronix.de>
To: linux-tip-commits@...r.kernel.org
Cc: Christian Borntraeger <borntraeger@...ux.ibm.com>,
"Peter Zijlstra (Intel)" <peterz@...radead.org>, x86@...nel.org,
linux-kernel@...r.kernel.org
Subject: [tip: sched/core] sched: Fix TASK_state comparisons
The following commit has been merged into the sched/core branch of tip:
Commit-ID: 5aec788aeb8eb74282b75ac1b317beb0fbb69a42
Gitweb: https://git.kernel.org/tip/5aec788aeb8eb74282b75ac1b317beb0fbb69a42
Author: Peter Zijlstra <peterz@...radead.org>
AuthorDate: Tue, 27 Sep 2022 21:02:34 +02:00
Committer: Peter Zijlstra <peterz@...radead.org>
CommitterDate: Wed, 28 Sep 2022 10:00:16 +02:00
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: f5d39b020809 ("freezer,sched: Rewrite core freezer logic")
Reported-by: Christian Borntraeger <borntraeger@...ux.ibm.com>
Debugged-by: Christian Borntraeger <borntraeger@...ux.ibm.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@...radead.org>
Tested-by: Christian Borntraeger <borntraeger@...ux.ibm.com>
---
include/linux/wait.h | 2 +-
kernel/hung_task.c | 8 ++++++--
kernel/sched/core.c | 2 +-
3 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/include/linux/wait.h b/include/linux/wait.h
index 14ad8a0..7f5a51a 100644
--- a/include/linux/wait.h
+++ b/include/linux/wait.h
@@ -281,7 +281,7 @@ static inline void wake_up_pollfree(struct wait_queue_head *wq_head)
#define ___wait_is_interruptible(state) \
(!__builtin_constant_p(state) || \
- state == TASK_INTERRUPTIBLE || state == TASK_KILLABLE) \
+ (state & (TASK_INTERRUPTIBLE | TASK_WAKEKILL)))
extern void init_wait_entry(struct wait_queue_entry *wq_entry, int flags);
diff --git a/kernel/hung_task.c b/kernel/hung_task.c
index f1321c0..3a15169 100644
--- a/kernel/hung_task.c
+++ b/kernel/hung_task.c
@@ -191,6 +191,8 @@ static void check_hung_uninterruptible_tasks(unsigned long timeout)
hung_task_show_lock = false;
rcu_read_lock();
for_each_process_thread(g, t) {
+ unsigned int state;
+
if (!max_count--)
goto unlock;
if (time_after(jiffies, last_break + HUNG_TASK_LOCK_BREAK)) {
@@ -198,8 +200,10 @@ static void check_hung_uninterruptible_tasks(unsigned long timeout)
goto unlock;
last_break = jiffies;
}
- /* use "==" to skip the TASK_KILLABLE tasks waiting on NFS */
- if (READ_ONCE(t->__state) == TASK_UNINTERRUPTIBLE)
+ /* skip the TASK_KILLABLE tasks -- these can be killed */
+ state = READ_ONCE(t->__state);
+ if ((state & TASK_UNINTERRUPTIBLE) &&
+ !(state & TASK_WAKEKILL))
check_hung_task(t, timeout);
}
unlock:
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 4fa4a3d..02dc1b8 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -8884,7 +8884,7 @@ state_filter_match(unsigned long state_filter, struct task_struct *p)
* When looking for TASK_UNINTERRUPTIBLE skip TASK_IDLE (allows
* TASK_KILLABLE).
*/
- if (state_filter == TASK_UNINTERRUPTIBLE && state == TASK_IDLE)
+ if (state_filter == TASK_UNINTERRUPTIBLE && (state & TASK_NOLOAD))
return false;
return true;
Powered by blists - more mailing lists