From: Vasileios Almpanis <vasileios.almpanis@virtuozzo.com>
To: Konstantin Khorenko <khorenko@virtuozzo.com>,
Pavel Tikhomirov <ptikhomirov@virtuozzo.com>
Cc: devel@openvz.org
Subject: [Devel] [PATCH hci-8.1 1/4] sched: fix cfs_rq::nr_iowait leak on the remote wakeup path
Date: Wed, 14 Oct 2026 11:16:24 +0000 [thread overview]
Message-ID: <20261014-ct-iowait-v1-1-9d65fe37cf89@virtuozzo.com> (raw)
In-Reply-To: <20261014-ct-iowait-v1-0-9d65fe37cf89@virtuozzo.com>
try_to_wake_up() decrements cfs_rq::nr_iowait only after the
p->on_cpu check. If the task's CPU is still in schedule(), the wakeup
is queued with ttwu_queue_wakelist() and try_to_wake_up() returns
early, so the counter is never decremented. It keeps growing and shows
up as a bogus procs_blocked in the CT's /proc/stat:
# grep procs_blocked /proc/stat
procs_blocked 70
With NO_TTWU_QUEUE the leak goes away.
Fix it by doing the decrement where rq::nr_iowait is handled: in
try_to_wake_up() before set_task_cpu() for migrating wakeups, and in
ttwu_do_activate() for all others, which also covers the wakelist.
This way non migrating wakeups don't take the rq lock for it anymore.
A task on the wakelist is TASK_WAKING but still counted, so add
task_in_nr_iowait() and use it in sched_move_task() instead of
skipping every TASK_WAKING task.
https://virtuozzo.atlassian.net/browse/VSTOR-147823
Fixes: 415fe063c53e ("sched: Account cfs_rq::nr_iowait")
Signed-off-by: Vasileios Almpanis <vasileios.almpanis@virtuozzo.com>
Feature: sched: enhance task states granularity and accounting
---
kernel/sched/core.c | 26 +++++++++++++-------------
kernel/sched/sched.h | 12 ++++++++++++
2 files changed, 25 insertions(+), 13 deletions(-)
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 9275501bc3ad..dc016d264d19 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -3775,6 +3775,8 @@ ttwu_do_activate(struct rq *rq, struct task_struct *p, int wake_flags,
if (p->in_iowait) {
delayacct_blkio_end(p);
atomic_dec(&task_rq(p)->nr_iowait);
+ if (p->sched_class->nr_iowait_dec)
+ p->sched_class->nr_iowait_dec(p);
}
if (p->sched_interruptible_sleep)
@@ -4355,20 +4357,20 @@ int try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags)
*/
smp_cond_load_acquire(&p->on_cpu, !VAL);
- if (p->in_iowait && p->sched_class->nr_iowait_dec) {
- struct rq_flags rf;
- struct rq *rq;
-
- rq = __task_rq_lock(p, &rf);
- p->sched_class->nr_iowait_dec(p);
- __task_rq_unlock(rq, &rf);
- }
-
cpu = select_task_rq(p, p->wake_cpu, &wake_flags);
if (task_cpu(p) != cpu) {
if (p->in_iowait) {
delayacct_blkio_end(p);
atomic_dec(&task_rq(p)->nr_iowait);
+ /* On the old CPU, see also ttwu_do_activate() */
+ if (p->sched_class->nr_iowait_dec) {
+ struct rq_flags rf;
+ struct rq *rq;
+
+ rq = __task_rq_lock(p, &rf);
+ p->sched_class->nr_iowait_dec(p);
+ __task_rq_unlock(rq, &rf);
+ }
}
wake_flags |= WF_MIGRATED;
@@ -9139,8 +9141,7 @@ void sched_move_task(struct task_struct *tsk, bool for_autogroup)
if (queued)
dequeue_task(rq, tsk, queue_flags);
else {
- if (!(READ_ONCE(tsk->__state) == TASK_WAKING) && tsk->in_iowait &&
- tsk->sched_class->nr_iowait_dec)
+ if (task_in_nr_iowait(tsk) && tsk->sched_class->nr_iowait_dec)
tsk->sched_class->nr_iowait_dec(tsk);
if (tsk->sched_contributes_to_load)
@@ -9159,8 +9160,7 @@ void sched_move_task(struct task_struct *tsk, bool for_autogroup)
if (queued)
enqueue_task(rq, tsk, queue_flags);
else {
- if (!(READ_ONCE(tsk->__state) == TASK_WAKING) && tsk->in_iowait &&
- tsk->sched_class->nr_iowait_inc)
+ if (task_in_nr_iowait(tsk) && tsk->sched_class->nr_iowait_inc)
tsk->sched_class->nr_iowait_inc(tsk);
if (tsk->sched_contributes_to_load)
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 2a3f73933456..176077ba4201 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -2337,6 +2337,18 @@ static inline int task_on_rq_queued(struct task_struct *p)
return READ_ONCE(p->on_rq) == TASK_ON_RQ_QUEUED;
}
+/*
+ * A sleeping iowait task stays counted in nr_iowait of its sched class until
+ * it is woken up: a migrating wakeup drops it in try_to_wake_up(), any other
+ * in ttwu_do_activate(), which for a wakelist wakeup runs later while the
+ * task is TASK_WAKING. Called with p->pi_lock and the task's rq lock held.
+ */
+static inline bool task_in_nr_iowait(struct task_struct *p)
+{
+ return p->in_iowait && !task_on_rq_queued(p) &&
+ (READ_ONCE(p->__state) != TASK_WAKING || !p->sched_remote_wakeup);
+}
+
static inline int task_on_rq_migrating(struct task_struct *p)
{
return READ_ONCE(p->on_rq) == TASK_ON_RQ_MIGRATING;
--
2.43.0
_______________________________________________
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel
next prev parent reply other threads:[~2026-10-14 11:18 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-14 11:16 [Devel] [PATCH hci-8.1 0/4] sched: restore Container iowait accounting Vasileios Almpanis
2026-10-14 11:16 ` Vasileios Almpanis [this message]
2026-10-14 11:23 ` [Devel] [PATCH hci-8.1 1/4] sched: fix cfs_rq::nr_iowait leak on the remote wakeup path no-reply
2026-10-14 11:16 ` [Devel] [PATCH hci-8.1 2/4] sched: keep cfs_rq::nr_iowait balanced for throttled and class changing tasks Vasileios Almpanis
2026-10-14 11:24 ` no-reply
2026-10-14 11:16 ` [Devel] [PATCH hci-8.1 3/4] sched: account sleep and block time of a task group entity Vasileios Almpanis
2026-10-14 11:28 ` no-reply
2026-10-14 11:36 ` Vasileios Almpanis
2026-10-14 11:16 ` [Devel] [PATCH hci-8.1 4/4] sched: switch a sleeping task group entity between idle and iowait Vasileios Almpanis
2026-10-14 11:27 ` no-reply
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261014-ct-iowait-v1-1-9d65fe37cf89@virtuozzo.com \
--to=vasileios.almpanis@virtuozzo.com \
--cc=devel@openvz.org \
--cc=khorenko@virtuozzo.com \
--cc=ptikhomirov@virtuozzo.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox