[PATCH v3 8/9] fs/resctrl: Wire up rmid expansion and reclaim functions

From: Zeng Heng

Date: Tue Mar 17 2026 - 09:22:35 EST


The previous patch implemented resctrl_arch_rmid_expand() and
resctrl_arch_rmid_reclaim() for ARM MPAM. This patch integrates
these architecture-specific functions into the generic resctrl layer.

Refactor resctrl_find_free_rmid() to support dynamic rmid expansion.
If no free rmid is available for the current closid, attempt to expand
via resctrl_arch_expand_rmid(). On success, retry the rmid allocation.

As this capability is architecture-specific, x86 maintains existing
behavior by returning -ENOSPC when rmid resources are exhausted.

Additionally, invoke resctrl_arch_rmid_reclaim() when rmids are released
to enable architecture-specific resource cleanup.

Signed-off-by: Zeng Heng <zengheng4@xxxxxxxxxx>
---
arch/x86/include/asm/resctrl.h | 7 +++++++
fs/resctrl/monitor.c | 32 ++++++++++++++++++++++++++++++--
2 files changed, 37 insertions(+), 2 deletions(-)

diff --git a/arch/x86/include/asm/resctrl.h b/arch/x86/include/asm/resctrl.h
index 575f8408a9e7..7f8c8d84f2a0 100644
--- a/arch/x86/include/asm/resctrl.h
+++ b/arch/x86/include/asm/resctrl.h
@@ -167,6 +167,13 @@ static inline void resctrl_arch_sched_in(struct task_struct *tsk)
__resctrl_sched_in(tsk);
}

+static inline int resctrl_arch_rmid_expand(u32 closid)
+{
+ return -ENOSPC;
+}
+
+static inline void resctrl_arch_rmid_reclaim(u32 closid, u32 rmid) {}
+
static inline void resctrl_arch_rmid_idx_decode(u32 idx, u32 *closid, u32 *rmid)
{
*rmid = idx;
diff --git a/fs/resctrl/monitor.c b/fs/resctrl/monitor.c
index 4e78fb194c16..c58440eb7cc9 100644
--- a/fs/resctrl/monitor.c
+++ b/fs/resctrl/monitor.c
@@ -122,6 +122,8 @@ static void limbo_release_entry(struct rmid_entry *entry)

if (IS_ENABLED(CONFIG_RESCTRL_RMID_DEPENDS_ON_CLOSID))
closid_num_dirty_rmid[entry->closid]--;
+
+ resctrl_arch_rmid_reclaim(entry->closid, entry->rmid);
}

/*
@@ -197,7 +199,7 @@ bool has_busy_rmid(struct rdt_l3_mon_domain *d)
return find_first_bit(d->rmid_busy_llc, idx_limit) != idx_limit;
}

-static struct rmid_entry *resctrl_find_free_rmid(u32 closid)
+static struct rmid_entry *__resctrl_find_free_rmid(u32 closid)
{
struct rmid_entry *itr;
u32 itr_idx, cmp_idx;
@@ -214,7 +216,12 @@ static struct rmid_entry *resctrl_find_free_rmid(u32 closid)
* very first entry will be returned.
*/
itr_idx = resctrl_arch_rmid_idx_encode(itr->closid, itr->rmid);
+ if (itr_idx == U32_MAX)
+ continue;
+
cmp_idx = resctrl_arch_rmid_idx_encode(closid, itr->rmid);
+ if (cmp_idx == U32_MAX)
+ continue;

if (itr_idx == cmp_idx)
return itr;
@@ -223,6 +230,25 @@ static struct rmid_entry *resctrl_find_free_rmid(u32 closid)
return ERR_PTR(-ENOSPC);
}

+static struct rmid_entry *resctrl_find_free_rmid(u32 closid)
+{
+ struct rmid_entry *err;
+ int ret;
+
+ err = __resctrl_find_free_rmid(closid);
+ if (err == ERR_PTR(-ENOSPC)) {
+ ret = resctrl_arch_rmid_expand(closid);
+ if (ret < 0)
+ /* Out of rmid */
+ goto out;
+
+ /* Try it again */
+ return __resctrl_find_free_rmid(closid);
+ }
+out:
+ return err;
+}
+
/**
* resctrl_find_cleanest_closid() - Find a CLOSID where all the associated
* RMID are clean, or the CLOSID that has
@@ -340,8 +366,10 @@ void free_rmid(u32 closid, u32 rmid)

if (resctrl_is_mon_event_enabled(QOS_L3_OCCUP_EVENT_ID))
add_rmid_to_limbo(entry);
- else
+ else {
list_add_tail(&entry->list, &rmid_free_lru);
+ resctrl_arch_rmid_reclaim(closid, rmid);
+ }
}

bool rmid_is_occupied(u32 closid, u32 rmid)
--
2.25.1