[PATCH v6 7/9] fs/resctrl: Do not invoke smp_processor_id() in preemptible context
From: Chen Yu
Date: Sat Jul 25 2026 - 05:34:46 EST
From: Tony Luck <tony.luck@xxxxxxxxx>
LLC occupancy can be read on any CPU when the counter is accessed via
MMIO, so such an event is read from task context on whatever CPU the
caller happens to be running on rather than being bounced to a CPU in
the monitoring domain. mon_evt::any_cpu marks these CPU-agnostic events.
__l3_mon_event_count() calls smp_processor_id() to find the CPU to read
from. For an any_cpu event that lookup is unsafe:
the code runs in preemptible task context, so smp_processor_id() emits a
debug warning.
Skip the current-CPU lookup when an event's any_cpu flag is set, events with
this flag do not require execution on a specific CPU. For legacy MSR-based
access, update rmid_read::err if the reading of the event was dispatched to
a wrong CPU, according to the change at:
https://lore.kernel.org/lkml/6b3c66a49788828bd8c04a6911bd74c91ccd56f3.1782857711.git.reinette.chatre@xxxxxxxxx/
Signed-off-by: Tony Luck <tony.luck@xxxxxxxxx>
Signed-off-by: Chen Yu <yu.c.chen@xxxxxxxxx>
Tested-by: Hongyu Ning <hongyu.ning@xxxxxxxxxxxxxxx>
---
v5->v6:
Drop "in a follow-up patch" from the changelog. (Reinette Chatre)
Set rmid_read::err when an MSR based read is dispatched to a CPU
outside the monitoring domain, to align with the conflicting change
at
https://lore.kernel.org/lkml/6b3c66a49788828bd8c04a6911bd74c91ccd56f3.1782857711.git.reinette.chatre@xxxxxxxxx/
(Reinette Chatre)
---
fs/resctrl/monitor.c | 44 ++++++++++++++++++++++++++++++++++----------
1 file changed, 34 insertions(+), 10 deletions(-)
diff --git a/fs/resctrl/monitor.c b/fs/resctrl/monitor.c
index a932a1fea818..c08d2f90d721 100644
--- a/fs/resctrl/monitor.c
+++ b/fs/resctrl/monitor.c
@@ -422,9 +422,37 @@ static void mbm_cntr_free(struct rdt_l3_mon_domain *d, int cntr_id)
memset(&d->cntr_cfg[cntr_id], 0, sizeof(*d->cntr_cfg));
}
+/**
+ * cpu_on_correct_domain() - Check if current CPU is in the correct
+ * domain for the event.
+ * @rr: The rmid_read structure containing event and domain information.
+ *
+ * Context: Preemptible process context when @rr->evt->any_cpu is set.
+ * Non-migratable process context (via smp_call_on_cpu()) or
+ * non-preemptible context (via smp_call_function_any()) when
+ * the event must be read on a specific CPU.
+ * Return: true if the current CPU can read this event, false otherwise.
+ */
+static bool cpu_on_correct_domain(struct rmid_read *rr)
+{
+ int cpu;
+
+ /* Any CPU is OK for this event */
+ if (rr->evt->any_cpu)
+ return true;
+
+ cpu = smp_processor_id();
+
+ /* Single domain. Must be on a CPU in that domain. */
+ if (rr->hdr)
+ return cpumask_test_cpu(cpu, &rr->hdr->cpu_mask);
+
+ /* Summing domains that share a cache, must be on a CPU for that cache. */
+ return cpumask_test_cpu(cpu, &rr->ci->shared_cpu_map);
+}
+
static int __l3_mon_event_count(struct rdtgroup *rdtgrp, struct rmid_read *rr)
{
- int cpu = smp_processor_id();
u32 closid = rdtgrp->closid;
u32 rmid = rdtgrp->mon.rmid;
struct rdt_l3_mon_domain *d;
@@ -457,9 +485,6 @@ static int __l3_mon_event_count(struct rdtgroup *rdtgrp, struct rmid_read *rr)
return 0;
}
- /* Reading a single domain, must be on a CPU in that domain. */
- if (!cpumask_test_cpu(cpu, &d->hdr.cpu_mask))
- return -EINVAL;
if (rr->is_mbm_cntr)
rr->err = resctrl_arch_cntr_read(rr->r, d, closid, rmid, cntr_id,
rr->evt->evtid, &tval);
@@ -477,7 +502,6 @@ static int __l3_mon_event_count(struct rdtgroup *rdtgrp, struct rmid_read *rr)
static int __l3_mon_event_count_sum(struct rdtgroup *rdtgrp, struct rmid_read *rr)
{
- int cpu = smp_processor_id();
u32 closid = rdtgrp->closid;
u32 rmid = rdtgrp->mon.rmid;
struct rdt_l3_mon_domain *d;
@@ -495,10 +519,6 @@ static int __l3_mon_event_count_sum(struct rdtgroup *rdtgrp, struct rmid_read *r
return -EINVAL;
}
- /* Summing domains that share a cache, must be on a CPU for that cache. */
- if (!cpumask_test_cpu(cpu, &rr->ci->shared_cpu_map))
- return -EINVAL;
-
/*
* Legacy files must report the sum of an event across all
* domains that share the same L3 cache instance.
@@ -529,7 +549,11 @@ static int __mon_event_count(struct rdtgroup *rdtgrp, struct rmid_read *rr)
{
switch (rr->r->rid) {
case RDT_RESOURCE_L3:
- WARN_ON_ONCE(rr->evt->any_cpu);
+ if (!cpu_on_correct_domain(rr)) {
+ rr->err = -EIO;
+ return -EINVAL;
+ }
+
if (rr->hdr)
return __l3_mon_event_count(rdtgrp, rr);
else
--
2.25.1