[RFC PATCH v2 03/10] arm_mpam: resctrl: Do not fail CPU online when domain setup fails

From: Reinette Chatre

Date: Mon Oct 19 2026 - 18:08:31 EST


When a CPU comes online, mpam_resctrl_online_cpu() adds it to the resctrl
domains of each resource in use, and sets up a new domain when the CPU
is the first of its domain to come online. A failure to set up a domain
is returned as the failure of MPAM's CPU hotplug startup callback.

The CPU hotplug core does not run the teardown callback for a CPU whose
startup callback failed, so everything done for the CPU before the
failure stays in place: the CPU remains in the domains of the resources
that were handled before the failing one, and MPAM's per-MSC state for
the CPU is not undone. If the failure happens when MPAM installs its
CPU hotplug callbacks during enabling, the hotplug core discards the
callbacks, leaving MPAM enabled and resctrl initialized but MPAM no
longer notified of CPU hotplug. If it happens when a CPU comes online
later, the CPU fails to come online.

Setting up a domain only fails if a memory allocation fails or if a
class unexpectedly has no component for the CPU. For such rare failures
losing a resctrl domain is a smaller cost than failing CPU online or
leaving MPAM in an inconsistent state.

Do not report domain setup failures from mpam_resctrl_online_cpu() and
leave the CPU without a domain for that resource. Make
mpam_resctrl_alloc_domain() return nothing since its failures are no
longer reported. Keep adding the CPU to resctrl's default group even
when a domain could not be set up, since the CPU is online and runs
tasks regardless, and resctrl expects every online CPU to belong to a
resource group. Drop the warning when a CPU going offline has no domain,
since a missing domain is now expected.

Only domains that were set up are exposed through resctrl and torn down
when their CPUs go offline. When another CPU of the same domain comes
online, it sets up the domain again, and if that succeeds the domain
does not include the CPU for which setup failed.

Signed-off-by: Reinette Chatre <reinette.chatre@xxxxxxxxx>
---
drivers/resctrl/mpam_devices.c | 2 +-
drivers/resctrl/mpam_internal.h | 4 ++--
drivers/resctrl/mpam_resctrl.c | 31 +++++++++++++++----------------
3 files changed, 18 insertions(+), 19 deletions(-)

diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c
index 48adc49b833c..d17d7a72dba1 100644
--- a/drivers/resctrl/mpam_devices.c
+++ b/drivers/resctrl/mpam_devices.c
@@ -2249,7 +2249,7 @@ static int mpam_cpu_online(unsigned int cpu)
}

if (mpam_resctrl_enabled)
- return mpam_resctrl_online_cpu(cpu);
+ mpam_resctrl_online_cpu(cpu);

return 0;
}
diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
index 1f86cc158100..84c7adbb1a40 100644
--- a/drivers/resctrl/mpam_internal.h
+++ b/drivers/resctrl/mpam_internal.h
@@ -525,13 +525,13 @@ int mpam_get_cpumask_from_cache_id(unsigned long cache_id, u32 cache_level,
#ifdef CONFIG_RESCTRL_FS
int mpam_resctrl_setup(void);
void mpam_resctrl_exit(void);
-int mpam_resctrl_online_cpu(unsigned int cpu);
+void mpam_resctrl_online_cpu(unsigned int cpu);
void mpam_resctrl_offline_cpu(unsigned int cpu);
void mpam_resctrl_teardown_class(struct mpam_class *class);
#else
static inline int mpam_resctrl_setup(void) { return 0; }
static inline void mpam_resctrl_exit(void) { }
-static inline int mpam_resctrl_online_cpu(unsigned int cpu) { return 0; }
+static inline void mpam_resctrl_online_cpu(unsigned int cpu) { }
static inline void mpam_resctrl_offline_cpu(unsigned int cpu) { }
static inline void mpam_resctrl_teardown_class(struct mpam_class *class) { }
#endif /* CONFIG_RESCTRL_FS */
diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index b07e5dd895dd..dc442851fd7e 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -1615,8 +1615,8 @@ static struct mpam_component *find_component(struct mpam_class *class, int cpu)
return NULL;
}

-static struct mpam_resctrl_dom *
-mpam_resctrl_alloc_domain(unsigned int cpu, struct mpam_resctrl_res *res)
+static void mpam_resctrl_alloc_domain(unsigned int cpu,
+ struct mpam_resctrl_res *res)
{
int err;
struct mpam_resctrl_dom *dom;
@@ -1631,11 +1631,11 @@ mpam_resctrl_alloc_domain(unsigned int cpu, struct mpam_resctrl_res *res)
comp = find_component(class, cpu);
/* class has no component for this CPU */
if (WARN_ON_ONCE(!comp))
- return ERR_PTR(-EINVAL);
+ return;

dom = kzalloc_node(sizeof(*dom), GFP_KERNEL, cpu_to_node(cpu));
if (!dom)
- return ERR_PTR(-ENOMEM);
+ return;

if (r->alloc_capable) {
dom->ctrl_comp = comp;
@@ -1678,7 +1678,6 @@ mpam_resctrl_alloc_domain(unsigned int cpu, struct mpam_resctrl_res *res)
}
if (!any_mon_comp) {
WARN_ON_ONCE(0);
- err = -EFAULT;
goto offline_ctrl_domain;
}

@@ -1694,7 +1693,7 @@ mpam_resctrl_alloc_domain(unsigned int cpu, struct mpam_resctrl_res *res)
pr_debug("Skipped monitor domain online - no monitors\n");
}

- return dom;
+ return;

offline_ctrl_domain:
if (r->alloc_capable) {
@@ -1703,9 +1702,6 @@ mpam_resctrl_alloc_domain(unsigned int cpu, struct mpam_resctrl_res *res)
}
free_domain:
kfree(dom);
- dom = ERR_PTR(err);
-
- return dom;
}

/*
@@ -1757,7 +1753,7 @@ mpam_resctrl_get_domain_from_cpu(int cpu, struct mpam_resctrl_res *res)
return mpam_resctrl_get_mon_domain_from_cpu(cpu);
}

-int mpam_resctrl_online_cpu(unsigned int cpu)
+void mpam_resctrl_online_cpu(unsigned int cpu)
{
struct mpam_resctrl_res *res;
enum resctrl_res_level rid;
@@ -1772,9 +1768,13 @@ int mpam_resctrl_online_cpu(unsigned int cpu)

dom = mpam_resctrl_get_domain_from_cpu(cpu, res);
if (!dom) {
- dom = mpam_resctrl_alloc_domain(cpu, res);
- if (IS_ERR(dom))
- return PTR_ERR(dom);
+ /*
+ * On failure the CPU is left without a domain for this
+ * resource, which mpam_resctrl_offline_cpu() tolerates.
+ * resctrl_online_cpu() still adds the CPU to the default
+ * group because the CPU is online and runs tasks.
+ */
+ mpam_resctrl_alloc_domain(cpu, res);
} else {
if (r->alloc_capable) {
struct rdt_ctrl_domain *ctrl_d = &dom->resctrl_ctrl_dom;
@@ -1790,8 +1790,6 @@ int mpam_resctrl_online_cpu(unsigned int cpu)
}

resctrl_online_cpu(cpu);
-
- return 0;
}

void mpam_resctrl_offline_cpu(unsigned int cpu)
@@ -1812,8 +1810,9 @@ void mpam_resctrl_offline_cpu(unsigned int cpu)
if (!res->class)
continue; // dummy resource

+ /* The domain may be missing if its setup failed. */
dom = mpam_resctrl_get_domain_from_cpu(cpu, res);
- if (WARN_ON_ONCE(!dom))
+ if (!dom)
continue;

if (r->alloc_capable) {
--
2.55.0