From: Aaron Tomlin <atomlin@atomlin.com>
To: mingo@redhat.com, peterz@infradead.org, juri.lelli@redhat.com,
vincent.guittot@linaro.org
Cc: dietmar.eggemann@arm.com, rostedt@goodmis.org,
bsegall@google.com, mgorman@suse.de, vschneid@redhat.com,
kprateek.nayak@amd.com, zhanxusheng1024@gmail.com,
neelx@suse.com, chjohnst@mail.com, mproche@mail.com,
sean@ashe.io, steve@abita.co, linux-kernel@vger.kernel.org
Subject: [PATCH v3 3/4] sched/fair: Use list_for_each_entry_rcu() in print_cfs_stats()
Date: Sat, 8 Aug 2026 19:55:21 -0400 [thread overview]
Message-ID: <20260808235522.380038-4-atomlin@atomlin.com> (raw)
In-Reply-To: <20260808235522.380038-1-atomlin@atomlin.com>
In print_cfs_stats(), rq->leaf_cfs_rq_list is traversed using
for_each_leaf_cfs_rq_safe(), which expands to list_for_each_entry_safe().
Although rq->leaf_cfs_rq_list is RCU-protected, list_for_each_entry_safe()
is a non-RCU iteration macro. It dereferences pointer links without
READ_ONCE() and pre-fetches the next pointer.
When a writer concurrently adds a new cfs_rq to the list using
list_add_rcu(), a reader traversing with list_for_each_entry_safe()
lacks READ_ONCE() protection. Without READ_ONCE(), the compiler is free
to re-fetch pointers or reorder instructions. As a result, the reader
can observe a newly inserted cfs_rq's pointer before its internal fields
are fully visible, leading to reading uninitialised data or
dereferencing invalid pointers. This is illustrated below:
CPU 0 CPU 1
Writer (under rq->lock) Reader (print_cfs_stats)
--------------------------- --------------------------
1. Initialise cfs_rq rcu_read_lock()
cfs_rq->tg = tg
cfs_rq->load = 1024
2. list_add_rcu(&cfs_rq->list, ...): 3. for_each_leaf_cfs_rq_safe():
smp_store_release() Reads prev->next (cfs_rq)
prev->next = cfs_rq -----> Missing READ_ONCE()
4. Reads cfs_rq fields; sees
garbage data
cfs_rq->tg
cfs_rq->load
Fix this by introducing for_each_leaf_cfs_rq_rcu(), which expands to
list_for_each_entry_rcu(). This uses READ_ONCE() during list traversal.
Fixes: 0601267ca673 ("sched/fair: Rewrite list_add_leaf_cfs_rq()")
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Signed-off-by: Aaron Tomlin <atomlin@atomlin.com>
---
kernel/sched/fair.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index d78467ec6ee1..25f941ad637a 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -412,6 +412,10 @@ static inline void assert_list_leaf_cfs_rq(struct rq *rq)
list_for_each_entry_safe(cfs_rq, pos, &rq->leaf_cfs_rq_list, \
leaf_cfs_rq_list)
+#define for_each_leaf_cfs_rq_rcu(rq, cfs_rq) \
+ list_for_each_entry_rcu(cfs_rq, &(rq)->leaf_cfs_rq_list, \
+ leaf_cfs_rq_list)
+
/* Do the two (enqueued) entities belong to the same group ? */
static inline struct cfs_rq *
is_same_group(struct sched_entity *se, struct sched_entity *pse)
@@ -497,6 +501,9 @@ static inline void assert_list_leaf_cfs_rq(struct rq *rq)
#define for_each_leaf_cfs_rq_safe(rq, cfs_rq, pos) \
for (cfs_rq = &rq->cfs, pos = NULL; cfs_rq; cfs_rq = pos)
+#define for_each_leaf_cfs_rq_rcu(rq, cfs_rq) \
+ for (cfs_rq = &rq->cfs; cfs_rq; cfs_rq = NULL)
+
static inline struct sched_entity *parent_entity(struct sched_entity *se)
{
return NULL;
@@ -15401,10 +15408,10 @@ DEFINE_SCHED_CLASS(fair) = {
void print_cfs_stats(struct seq_file *m, int cpu)
{
- struct cfs_rq *cfs_rq, *pos;
+ struct cfs_rq *cfs_rq;
rcu_read_lock();
- for_each_leaf_cfs_rq_safe(cpu_rq(cpu), cfs_rq, pos)
+ for_each_leaf_cfs_rq_rcu(cpu_rq(cpu), cfs_rq)
print_cfs_rq(m, cpu, cfs_rq);
rcu_read_unlock();
}
--
2.55.0
next prev parent reply other threads:[~2026-08-08 23:55 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-08 23:55 [PATCH v3 0/4] sched/debug: Introduce per-CPU debugfs files Aaron Tomlin
2026-08-08 23:55 ` [PATCH v3 1/4] sched/debug: Protect lockless rq->curr access in print_cpu() Aaron Tomlin
2026-08-08 23:55 ` [PATCH v3 2/4] sched/debug: Protect lockless rq->rd access in print_dl_rq() Aaron Tomlin
2026-08-08 23:55 ` Aaron Tomlin [this message]
2026-08-08 23:55 ` [PATCH v3 4/4] sched/debug: Introduce per-CPU debugfs files Aaron Tomlin
2026-08-10 3:17 ` [PATCH v3 0/4] " Aaron Tomlin
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=20260808235522.380038-4-atomlin@atomlin.com \
--to=atomlin@atomlin.com \
--cc=bsegall@google.com \
--cc=chjohnst@mail.com \
--cc=dietmar.eggemann@arm.com \
--cc=juri.lelli@redhat.com \
--cc=kprateek.nayak@amd.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mgorman@suse.de \
--cc=mingo@redhat.com \
--cc=mproche@mail.com \
--cc=neelx@suse.com \
--cc=peterz@infradead.org \
--cc=rostedt@goodmis.org \
--cc=sean@ashe.io \
--cc=steve@abita.co \
--cc=vincent.guittot@linaro.org \
--cc=vschneid@redhat.com \
--cc=zhanxusheng1024@gmail.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.