* [PATCH v2 0/2] fs/resctrl: Fix RMID limbo handling
@ 2026-10-30 9:21 Jinjie Ruan
2026-10-30 9:21 ` [PATCH] fs/resctrl: Do not allocate a monitor context when releasing limbo RMIDs Jinjie Ruan
` (2 more replies)
0 siblings, 3 replies; 7+ messages in thread
From: Jinjie Ruan @ 2026-10-30 9:21 UTC (permalink / raw)
To: tony.luck, reinette.chatre, Dave.Martin, james.morse, babu.moger,
bp, tan.shaopeng, x86, linux-kernel
Cc: ruanjinjie
Fix resctrl RMID allocation to report a retryable -EBUSY only when the
target CLOSID actually has RMIDs in limbo, and split the domain-offline
path out so it releases busy RMIDs without allocating a monitor context
it never uses.
These two fixes are split out of the v10 Narrow-PARTID series below.
https://lore.kernel.org/all/20261020134239.3921377-1-ruanjinjie@huawei.com/
Changes in v2
- Update the commit message as Reinette suggested.
- Link to v1: https://lore.kernel.org/all/20261029081513.924019-1-ruanjinjie@huawei.com/
Jinjie Ruan (2):
fs/resctrl: Report a temporary RMID shortage per CLOSID
fs/resctrl: Do not allocate a monitor context when releasing limbo
RMIDs
fs/resctrl/internal.h | 2 +-
fs/resctrl/monitor.c | 87 ++++++++++++++++++++++++++++---------------
fs/resctrl/rdtgroup.c | 2 +-
3 files changed, 60 insertions(+), 31 deletions(-)
--
2.34.1
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH] fs/resctrl: Do not allocate a monitor context when releasing limbo RMIDs
2026-10-30 9:21 [PATCH v2 0/2] fs/resctrl: Fix RMID limbo handling Jinjie Ruan
@ 2026-10-30 9:21 ` Jinjie Ruan
2026-10-30 9:23 ` Jinjie Ruan
2026-10-30 9:21 ` [PATCH v2 1/2] fs/resctrl: Report a temporary RMID shortage per CLOSID Jinjie Ruan
2026-10-30 9:21 ` [PATCH v2 2/2] fs/resctrl: Do not allocate a monitor context when releasing limbo RMIDs Jinjie Ruan
2 siblings, 1 reply; 7+ messages in thread
From: Jinjie Ruan @ 2026-10-30 9:21 UTC (permalink / raw)
To: tony.luck, reinette.chatre, Dave.Martin, james.morse, babu.moger,
bp, tan.shaopeng, x86, linux-kernel
Cc: ruanjinjie
Busy RMIDs of a monitor domain are normally released by the limbo
handler once their cache occupancy drops below the threshold. When a
domain goes offline, its busy RMIDs are released without checking
occupancy, since the domain is going away and the RMIDs must not be
left behind.
On the monitor domain offline path, __check_limbo() allocates
the monitor context that an occupancy check needs before it scans
the busy RMIDs, but without using it, and returns early when that
allocation fails. Then the caller destroys the domain's monitoring state,
including the bitmap that records which RMIDs are busy, so nothing can
clear those bits afterwards and the busy counts never reach zero. Those
RMIDs never return to the free list and, where the RMID depends on
the CLOSID, the dirty count of their CLOSID never decreases. The allocation
can also wait for a monitor to become free, which stalls the CPU offline
path on a context that is not going to be used.
Only MPAM systems are affected. An architecture that can always read an
RMID allocates nothing for the monitor context, so the allocation can
neither fail nor wait there.
So move the release of busy RMIDs into a separate function that does
not take a monitor context and leave the occupancy check to
__check_limbo().
This is not a revert of the fixed commit. It preserves the original fix's
intent of not reading a counter in the offline path.
Fixes: fc16126cc11d ("x86,fs/resctrl: Prevent out-of-bounds access while offlining CPU when SNC enabled")
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
Cc: James Morse <james.morse@arm.com>
Cc: Reinette Chatre <reinette.chatre@intel.com>
Cc: <stable@vger.kernel.org>
---
fs/resctrl/internal.h | 2 +-
fs/resctrl/monitor.c | 72 ++++++++++++++++++++++++++++---------------
fs/resctrl/rdtgroup.c | 2 +-
3 files changed, 49 insertions(+), 27 deletions(-)
diff --git a/fs/resctrl/internal.h b/fs/resctrl/internal.h
index e62a277dee85..1c85e06f09bf 100644
--- a/fs/resctrl/internal.h
+++ b/fs/resctrl/internal.h
@@ -405,7 +405,7 @@ void cqm_handle_limbo(struct work_struct *work);
bool has_busy_rmid(struct rdt_l3_mon_domain *d);
-void __check_limbo(struct rdt_l3_mon_domain *d, bool force_free);
+void release_limbo_rmids(struct rdt_l3_mon_domain *d);
void resctrl_file_fflags_init(const char *config, unsigned long fflags);
diff --git a/fs/resctrl/monitor.c b/fs/resctrl/monitor.c
index 88674e28b2f8..3c9f65888004 100644
--- a/fs/resctrl/monitor.c
+++ b/fs/resctrl/monitor.c
@@ -124,18 +124,42 @@ static void limbo_release_entry(struct rmid_entry *entry)
closid_num_dirty_rmid[entry->closid]--;
}
+/*
+ * Release the RMIDs that are marked as busy for this domain without
+ * checking their LLC occupancy. Cache lines may still be tagged with
+ * these RMIDs and will be accounted to the next user of each RMID.
+ */
+void release_limbo_rmids(struct rdt_l3_mon_domain *d)
+{
+ u32 idx_limit = resctrl_arch_system_num_rmid_idx();
+ struct rmid_entry *entry;
+ u32 idx, cur_idx = 1;
+
+ for (;;) {
+ idx = find_next_bit(d->rmid_busy_llc, idx_limit, cur_idx);
+ if (idx >= idx_limit)
+ break;
+
+ entry = __rmid_entry(idx);
+ clear_bit(idx, d->rmid_busy_llc);
+ if (!--entry->busy)
+ limbo_release_entry(entry);
+ cur_idx = idx + 1;
+ }
+}
+
/*
* Check the RMIDs that are marked as busy for this domain. If the
* reported LLC occupancy is below the threshold clear the busy bit and
* decrement the count. If the busy count gets to zero on an RMID, we
* free the RMID
*/
-void __check_limbo(struct rdt_l3_mon_domain *d, bool force_free)
+static void __check_limbo(struct rdt_l3_mon_domain *d)
{
struct rdt_resource *r = resctrl_arch_get_resource(RDT_RESOURCE_L3);
u32 idx_limit = resctrl_arch_system_num_rmid_idx();
struct rmid_entry *entry;
- bool rmid_dirty = true;
+ bool rmid_dirty;
u32 idx, cur_idx = 1;
void *arch_mon_ctx;
void *arch_priv;
@@ -161,30 +185,28 @@ void __check_limbo(struct rdt_l3_mon_domain *d, bool force_free)
break;
entry = __rmid_entry(idx);
- if (!force_free) {
- if (resctrl_arch_rmid_read(r, &d->hdr, entry->closid,
- entry->rmid, QOS_L3_OCCUP_EVENT_ID,
- arch_priv, &val, arch_mon_ctx)) {
- rmid_dirty = true;
- } else {
- rmid_dirty = (val >= resctrl_rmid_realloc_threshold);
-
- /*
- * x86's CLOSID and RMID are independent numbers,
- * so the entry's CLOSID is an empty CLOSID
- * (X86_RESCTRL_EMPTY_CLOSID). On Arm the RMID
- * (PMG) extends the CLOSID (PARTID) space with
- * bits that aren't used to select the configuration.
- * It is thus necessary to track both CLOSID and
- * RMID because there may be dependencies between
- * them on some architectures.
- */
- trace_mon_llc_occupancy_limbo(entry->closid, entry->rmid,
- d->hdr.id, val);
- }
+ if (resctrl_arch_rmid_read(r, &d->hdr, entry->closid,
+ entry->rmid, QOS_L3_OCCUP_EVENT_ID,
+ arch_priv, &val, arch_mon_ctx)) {
+ rmid_dirty = true;
+ } else {
+ rmid_dirty = (val >= resctrl_rmid_realloc_threshold);
+
+ /*
+ * x86's CLOSID and RMID are independent numbers,
+ * so the entry's CLOSID is an empty CLOSID
+ * (X86_RESCTRL_EMPTY_CLOSID). On Arm the RMID
+ * (PMG) extends the CLOSID (PARTID) space with
+ * bits that aren't used to select the configuration.
+ * It is thus necessary to track both CLOSID and
+ * RMID because there may be dependencies between
+ * them on some architectures.
+ */
+ trace_mon_llc_occupancy_limbo(entry->closid, entry->rmid,
+ d->hdr.id, val);
}
- if (force_free || !rmid_dirty) {
+ if (!rmid_dirty) {
clear_bit(idx, d->rmid_busy_llc);
if (!--entry->busy)
limbo_release_entry(entry);
@@ -843,7 +865,7 @@ void cqm_handle_limbo(struct work_struct *work)
if (cpumask_empty(&d->hdr.cpu_mask))
goto out_unlock;
- __check_limbo(d, false);
+ __check_limbo(d);
if (has_busy_rmid(d)) {
d->cqm_work_cpu = cpumask_any_housekeeping(&d->hdr.cpu_mask,
diff --git a/fs/resctrl/rdtgroup.c b/fs/resctrl/rdtgroup.c
index 5dcbb0a964e8..20c800e678d5 100644
--- a/fs/resctrl/rdtgroup.c
+++ b/fs/resctrl/rdtgroup.c
@@ -4592,7 +4592,7 @@ void resctrl_offline_mon_domain(struct rdt_resource *r, struct rdt_domain_hdr *h
* the RMID as busy creates RMID leaks if the
* package never comes back.
*/
- __check_limbo(d, true);
+ release_limbo_rmids(d);
}
domain_destroy_l3_mon_state(d);
--
2.34.1
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v2 1/2] fs/resctrl: Report a temporary RMID shortage per CLOSID
2026-10-30 9:21 [PATCH v2 0/2] fs/resctrl: Fix RMID limbo handling Jinjie Ruan
2026-10-30 9:21 ` [PATCH] fs/resctrl: Do not allocate a monitor context when releasing limbo RMIDs Jinjie Ruan
@ 2026-10-30 9:21 ` Jinjie Ruan
2026-10-30 18:14 ` Reinette Chatre
2026-10-30 9:21 ` [PATCH v2 2/2] fs/resctrl: Do not allocate a monitor context when releasing limbo RMIDs Jinjie Ruan
2 siblings, 1 reply; 7+ messages in thread
From: Jinjie Ruan @ 2026-10-30 9:21 UTC (permalink / raw)
To: tony.luck, reinette.chatre, Dave.Martin, james.morse, babu.moger,
bp, tan.shaopeng, x86, linux-kernel
Cc: ruanjinjie
An RMID that is freed is held in limbo until its cache occupancy drops
below the threshold, after which it returns to the free list. A request
that fails because of limbo is thus temporary and worth retrying, which
resctrl reports to userspace as -EBUSY. A request that fails because
every RMID is in use is permanent and reported as -ENOSPC.
Where an RMID is only meaningful together with a CLOSID, a request can
only be satisfied by an RMID belonging to the requested CLOSID, so the
distinction has to be drawn per CLOSID. Instead it is drawn system wide.
-ENOSPC is reported when the free list holds no RMID for the requested
CLOSID, even when that CLOSID has RMIDs in limbo. -EBUSY is reported
when the free list is empty and another CLOSID has an RMID in limbo,
even when the requested CLOSID has none. Userspace is thus told to give
up on a shortage that may clear on its own, and to retry one that cannot
clear until it removes a group itself.
Architectures where the RMID is independent of the CLOSID always match
the first entry on the free list, so neither case arises there and only
MPAM systems are affected.
Draw the distinction from the number of RMIDs the requested CLOSID has
in limbo where the RMID depends on the CLOSID, and from the system wide
count otherwise. Drop the separate test for an empty free list, which
the search handles on its own.
Fixes: c4c0376eefe1 ("x86/resctrl: Allow RMID allocation to be scoped by CLOSID")
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
Cc: James Morse <james.morse@arm.com>
Cc: Reinette Chatre <reinette.chatre@intel.com>
Cc: Babu Moger <babu.moger@amd.com>
Cc: <stable@vger.kernel.org> # 7.1.x
---
fs/resctrl/monitor.c | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/fs/resctrl/monitor.c b/fs/resctrl/monitor.c
index 73413cb128ea..88674e28b2f8 100644
--- a/fs/resctrl/monitor.c
+++ b/fs/resctrl/monitor.c
@@ -207,9 +207,6 @@ static struct rmid_entry *resctrl_find_free_rmid(u32 closid)
struct rmid_entry *itr;
u32 itr_idx, cmp_idx;
- if (list_empty(&rmid_free_lru))
- return rmid_limbo_count ? ERR_PTR(-EBUSY) : ERR_PTR(-ENOSPC);
-
list_for_each_entry(itr, &rmid_free_lru, list) {
/*
* Get the index of this free RMID, and the index it would need
@@ -225,7 +222,17 @@ static struct rmid_entry *resctrl_find_free_rmid(u32 closid)
return itr;
}
- return ERR_PTR(-ENOSPC);
+ /*
+ * No free RMID matched. If this CLOSID has RMIDs in limbo, return
+ * -EBUSY so userspace can retry. Otherwise, the CLOSID is genuinely
+ * out of RMIDs. When RMIDs are not per-CLOSID, any RMID in limbo
+ * delays the allocation.
+ */
+ if (IS_ENABLED(CONFIG_RESCTRL_RMID_DEPENDS_ON_CLOSID))
+ return closid_num_dirty_rmid[closid] ? ERR_PTR(-EBUSY) :
+ ERR_PTR(-ENOSPC);
+
+ return rmid_limbo_count ? ERR_PTR(-EBUSY) : ERR_PTR(-ENOSPC);
}
/**
--
2.34.1
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v2 2/2] fs/resctrl: Do not allocate a monitor context when releasing limbo RMIDs
2026-10-30 9:21 [PATCH v2 0/2] fs/resctrl: Fix RMID limbo handling Jinjie Ruan
2026-10-30 9:21 ` [PATCH] fs/resctrl: Do not allocate a monitor context when releasing limbo RMIDs Jinjie Ruan
2026-10-30 9:21 ` [PATCH v2 1/2] fs/resctrl: Report a temporary RMID shortage per CLOSID Jinjie Ruan
@ 2026-10-30 9:21 ` Jinjie Ruan
2026-10-30 18:15 ` Reinette Chatre
2 siblings, 1 reply; 7+ messages in thread
From: Jinjie Ruan @ 2026-10-30 9:21 UTC (permalink / raw)
To: tony.luck, reinette.chatre, Dave.Martin, james.morse, babu.moger,
bp, tan.shaopeng, x86, linux-kernel
Cc: ruanjinjie
Busy RMIDs of a monitor domain are normally released by the limbo
handler once their cache occupancy drops below the threshold. When a
domain goes offline, its busy RMIDs are released without checking
occupancy, since the domain is going away and the RMIDs must not be
left behind.
On the monitor domain offline path, __check_limbo() allocates
the monitor context that an occupancy check needs before it scans
the busy RMIDs, but without using it, and returns early when that
allocation fails. Then the caller destroys the domain's monitoring state,
including the bitmap that records which RMIDs are busy, so nothing can
clear those bits afterwards and the busy counts never reach zero. Those
RMIDs never return to the free list and, where the RMID depends on
the CLOSID, the dirty count of their CLOSID never decreases. The allocation
can also wait for a monitor to become free, which stalls the CPU offline
path on a context that is not going to be used.
Only MPAM systems are affected. An architecture that can always read an
RMID allocates nothing for the monitor context, so the allocation can
neither fail nor wait there.
So move the release of busy RMIDs into a separate function that does
not take a monitor context and leave the occupancy check to
__check_limbo().
This is not a revert of the fixed commit. It preserves the original fix's
intent of not reading a counter in the offline path.
Fixes: fc16126cc11d ("x86,fs/resctrl: Prevent out-of-bounds access while offlining CPU when SNC enabled")
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
Cc: James Morse <james.morse@arm.com>
Cc: Reinette Chatre <reinette.chatre@intel.com>
Cc: <stable@vger.kernel.org>
---
fs/resctrl/internal.h | 2 +-
fs/resctrl/monitor.c | 72 ++++++++++++++++++++++++++++---------------
fs/resctrl/rdtgroup.c | 2 +-
3 files changed, 49 insertions(+), 27 deletions(-)
diff --git a/fs/resctrl/internal.h b/fs/resctrl/internal.h
index e62a277dee85..1c85e06f09bf 100644
--- a/fs/resctrl/internal.h
+++ b/fs/resctrl/internal.h
@@ -405,7 +405,7 @@ void cqm_handle_limbo(struct work_struct *work);
bool has_busy_rmid(struct rdt_l3_mon_domain *d);
-void __check_limbo(struct rdt_l3_mon_domain *d, bool force_free);
+void release_limbo_rmids(struct rdt_l3_mon_domain *d);
void resctrl_file_fflags_init(const char *config, unsigned long fflags);
diff --git a/fs/resctrl/monitor.c b/fs/resctrl/monitor.c
index 88674e28b2f8..3c9f65888004 100644
--- a/fs/resctrl/monitor.c
+++ b/fs/resctrl/monitor.c
@@ -124,18 +124,42 @@ static void limbo_release_entry(struct rmid_entry *entry)
closid_num_dirty_rmid[entry->closid]--;
}
+/*
+ * Release the RMIDs that are marked as busy for this domain without
+ * checking their LLC occupancy. Cache lines may still be tagged with
+ * these RMIDs and will be accounted to the next user of each RMID.
+ */
+void release_limbo_rmids(struct rdt_l3_mon_domain *d)
+{
+ u32 idx_limit = resctrl_arch_system_num_rmid_idx();
+ struct rmid_entry *entry;
+ u32 idx, cur_idx = 1;
+
+ for (;;) {
+ idx = find_next_bit(d->rmid_busy_llc, idx_limit, cur_idx);
+ if (idx >= idx_limit)
+ break;
+
+ entry = __rmid_entry(idx);
+ clear_bit(idx, d->rmid_busy_llc);
+ if (!--entry->busy)
+ limbo_release_entry(entry);
+ cur_idx = idx + 1;
+ }
+}
+
/*
* Check the RMIDs that are marked as busy for this domain. If the
* reported LLC occupancy is below the threshold clear the busy bit and
* decrement the count. If the busy count gets to zero on an RMID, we
* free the RMID
*/
-void __check_limbo(struct rdt_l3_mon_domain *d, bool force_free)
+static void __check_limbo(struct rdt_l3_mon_domain *d)
{
struct rdt_resource *r = resctrl_arch_get_resource(RDT_RESOURCE_L3);
u32 idx_limit = resctrl_arch_system_num_rmid_idx();
struct rmid_entry *entry;
- bool rmid_dirty = true;
+ bool rmid_dirty;
u32 idx, cur_idx = 1;
void *arch_mon_ctx;
void *arch_priv;
@@ -161,30 +185,28 @@ void __check_limbo(struct rdt_l3_mon_domain *d, bool force_free)
break;
entry = __rmid_entry(idx);
- if (!force_free) {
- if (resctrl_arch_rmid_read(r, &d->hdr, entry->closid,
- entry->rmid, QOS_L3_OCCUP_EVENT_ID,
- arch_priv, &val, arch_mon_ctx)) {
- rmid_dirty = true;
- } else {
- rmid_dirty = (val >= resctrl_rmid_realloc_threshold);
-
- /*
- * x86's CLOSID and RMID are independent numbers,
- * so the entry's CLOSID is an empty CLOSID
- * (X86_RESCTRL_EMPTY_CLOSID). On Arm the RMID
- * (PMG) extends the CLOSID (PARTID) space with
- * bits that aren't used to select the configuration.
- * It is thus necessary to track both CLOSID and
- * RMID because there may be dependencies between
- * them on some architectures.
- */
- trace_mon_llc_occupancy_limbo(entry->closid, entry->rmid,
- d->hdr.id, val);
- }
+ if (resctrl_arch_rmid_read(r, &d->hdr, entry->closid,
+ entry->rmid, QOS_L3_OCCUP_EVENT_ID,
+ arch_priv, &val, arch_mon_ctx)) {
+ rmid_dirty = true;
+ } else {
+ rmid_dirty = (val >= resctrl_rmid_realloc_threshold);
+
+ /*
+ * x86's CLOSID and RMID are independent numbers,
+ * so the entry's CLOSID is an empty CLOSID
+ * (X86_RESCTRL_EMPTY_CLOSID). On Arm the RMID
+ * (PMG) extends the CLOSID (PARTID) space with
+ * bits that aren't used to select the configuration.
+ * It is thus necessary to track both CLOSID and
+ * RMID because there may be dependencies between
+ * them on some architectures.
+ */
+ trace_mon_llc_occupancy_limbo(entry->closid, entry->rmid,
+ d->hdr.id, val);
}
- if (force_free || !rmid_dirty) {
+ if (!rmid_dirty) {
clear_bit(idx, d->rmid_busy_llc);
if (!--entry->busy)
limbo_release_entry(entry);
@@ -843,7 +865,7 @@ void cqm_handle_limbo(struct work_struct *work)
if (cpumask_empty(&d->hdr.cpu_mask))
goto out_unlock;
- __check_limbo(d, false);
+ __check_limbo(d);
if (has_busy_rmid(d)) {
d->cqm_work_cpu = cpumask_any_housekeeping(&d->hdr.cpu_mask,
diff --git a/fs/resctrl/rdtgroup.c b/fs/resctrl/rdtgroup.c
index 5dcbb0a964e8..20c800e678d5 100644
--- a/fs/resctrl/rdtgroup.c
+++ b/fs/resctrl/rdtgroup.c
@@ -4592,7 +4592,7 @@ void resctrl_offline_mon_domain(struct rdt_resource *r, struct rdt_domain_hdr *h
* the RMID as busy creates RMID leaks if the
* package never comes back.
*/
- __check_limbo(d, true);
+ release_limbo_rmids(d);
}
domain_destroy_l3_mon_state(d);
--
2.34.1
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] fs/resctrl: Do not allocate a monitor context when releasing limbo RMIDs
2026-10-30 9:21 ` [PATCH] fs/resctrl: Do not allocate a monitor context when releasing limbo RMIDs Jinjie Ruan
@ 2026-10-30 9:23 ` Jinjie Ruan
0 siblings, 0 replies; 7+ messages in thread
From: Jinjie Ruan @ 2026-10-30 9:23 UTC (permalink / raw)
To: tony.luck, reinette.chatre, Dave.Martin, james.morse, babu.moger,
bp, tan.shaopeng, x86, linux-kernel
Please ignore this patch.
在 2026/10/30 17:21, Jinjie Ruan 写道:
> Busy RMIDs of a monitor domain are normally released by the limbo
> handler once their cache occupancy drops below the threshold. When a
> domain goes offline, its busy RMIDs are released without checking
> occupancy, since the domain is going away and the RMIDs must not be
> left behind.
>
> On the monitor domain offline path, __check_limbo() allocates
> the monitor context that an occupancy check needs before it scans
> the busy RMIDs, but without using it, and returns early when that
> allocation fails. Then the caller destroys the domain's monitoring state,
> including the bitmap that records which RMIDs are busy, so nothing can
> clear those bits afterwards and the busy counts never reach zero. Those
> RMIDs never return to the free list and, where the RMID depends on
> the CLOSID, the dirty count of their CLOSID never decreases. The allocation
> can also wait for a monitor to become free, which stalls the CPU offline
> path on a context that is not going to be used.
>
> Only MPAM systems are affected. An architecture that can always read an
> RMID allocates nothing for the monitor context, so the allocation can
> neither fail nor wait there.
>
> So move the release of busy RMIDs into a separate function that does
> not take a monitor context and leave the occupancy check to
> __check_limbo().
>
> This is not a revert of the fixed commit. It preserves the original fix's
> intent of not reading a counter in the offline path.
>
> Fixes: fc16126cc11d ("x86,fs/resctrl: Prevent out-of-bounds access while offlining CPU when SNC enabled")
> Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
> Cc: James Morse <james.morse@arm.com>
> Cc: Reinette Chatre <reinette.chatre@intel.com>
> Cc: <stable@vger.kernel.org>
> ---
> fs/resctrl/internal.h | 2 +-
> fs/resctrl/monitor.c | 72 ++++++++++++++++++++++++++++---------------
> fs/resctrl/rdtgroup.c | 2 +-
> 3 files changed, 49 insertions(+), 27 deletions(-)
>
> diff --git a/fs/resctrl/internal.h b/fs/resctrl/internal.h
> index e62a277dee85..1c85e06f09bf 100644
> --- a/fs/resctrl/internal.h
> +++ b/fs/resctrl/internal.h
> @@ -405,7 +405,7 @@ void cqm_handle_limbo(struct work_struct *work);
>
> bool has_busy_rmid(struct rdt_l3_mon_domain *d);
>
> -void __check_limbo(struct rdt_l3_mon_domain *d, bool force_free);
> +void release_limbo_rmids(struct rdt_l3_mon_domain *d);
>
> void resctrl_file_fflags_init(const char *config, unsigned long fflags);
>
> diff --git a/fs/resctrl/monitor.c b/fs/resctrl/monitor.c
> index 88674e28b2f8..3c9f65888004 100644
> --- a/fs/resctrl/monitor.c
> +++ b/fs/resctrl/monitor.c
> @@ -124,18 +124,42 @@ static void limbo_release_entry(struct rmid_entry *entry)
> closid_num_dirty_rmid[entry->closid]--;
> }
>
> +/*
> + * Release the RMIDs that are marked as busy for this domain without
> + * checking their LLC occupancy. Cache lines may still be tagged with
> + * these RMIDs and will be accounted to the next user of each RMID.
> + */
> +void release_limbo_rmids(struct rdt_l3_mon_domain *d)
> +{
> + u32 idx_limit = resctrl_arch_system_num_rmid_idx();
> + struct rmid_entry *entry;
> + u32 idx, cur_idx = 1;
> +
> + for (;;) {
> + idx = find_next_bit(d->rmid_busy_llc, idx_limit, cur_idx);
> + if (idx >= idx_limit)
> + break;
> +
> + entry = __rmid_entry(idx);
> + clear_bit(idx, d->rmid_busy_llc);
> + if (!--entry->busy)
> + limbo_release_entry(entry);
> + cur_idx = idx + 1;
> + }
> +}
> +
> /*
> * Check the RMIDs that are marked as busy for this domain. If the
> * reported LLC occupancy is below the threshold clear the busy bit and
> * decrement the count. If the busy count gets to zero on an RMID, we
> * free the RMID
> */
> -void __check_limbo(struct rdt_l3_mon_domain *d, bool force_free)
> +static void __check_limbo(struct rdt_l3_mon_domain *d)
> {
> struct rdt_resource *r = resctrl_arch_get_resource(RDT_RESOURCE_L3);
> u32 idx_limit = resctrl_arch_system_num_rmid_idx();
> struct rmid_entry *entry;
> - bool rmid_dirty = true;
> + bool rmid_dirty;
> u32 idx, cur_idx = 1;
> void *arch_mon_ctx;
> void *arch_priv;
> @@ -161,30 +185,28 @@ void __check_limbo(struct rdt_l3_mon_domain *d, bool force_free)
> break;
>
> entry = __rmid_entry(idx);
> - if (!force_free) {
> - if (resctrl_arch_rmid_read(r, &d->hdr, entry->closid,
> - entry->rmid, QOS_L3_OCCUP_EVENT_ID,
> - arch_priv, &val, arch_mon_ctx)) {
> - rmid_dirty = true;
> - } else {
> - rmid_dirty = (val >= resctrl_rmid_realloc_threshold);
> -
> - /*
> - * x86's CLOSID and RMID are independent numbers,
> - * so the entry's CLOSID is an empty CLOSID
> - * (X86_RESCTRL_EMPTY_CLOSID). On Arm the RMID
> - * (PMG) extends the CLOSID (PARTID) space with
> - * bits that aren't used to select the configuration.
> - * It is thus necessary to track both CLOSID and
> - * RMID because there may be dependencies between
> - * them on some architectures.
> - */
> - trace_mon_llc_occupancy_limbo(entry->closid, entry->rmid,
> - d->hdr.id, val);
> - }
> + if (resctrl_arch_rmid_read(r, &d->hdr, entry->closid,
> + entry->rmid, QOS_L3_OCCUP_EVENT_ID,
> + arch_priv, &val, arch_mon_ctx)) {
> + rmid_dirty = true;
> + } else {
> + rmid_dirty = (val >= resctrl_rmid_realloc_threshold);
> +
> + /*
> + * x86's CLOSID and RMID are independent numbers,
> + * so the entry's CLOSID is an empty CLOSID
> + * (X86_RESCTRL_EMPTY_CLOSID). On Arm the RMID
> + * (PMG) extends the CLOSID (PARTID) space with
> + * bits that aren't used to select the configuration.
> + * It is thus necessary to track both CLOSID and
> + * RMID because there may be dependencies between
> + * them on some architectures.
> + */
> + trace_mon_llc_occupancy_limbo(entry->closid, entry->rmid,
> + d->hdr.id, val);
> }
>
> - if (force_free || !rmid_dirty) {
> + if (!rmid_dirty) {
> clear_bit(idx, d->rmid_busy_llc);
> if (!--entry->busy)
> limbo_release_entry(entry);
> @@ -843,7 +865,7 @@ void cqm_handle_limbo(struct work_struct *work)
> if (cpumask_empty(&d->hdr.cpu_mask))
> goto out_unlock;
>
> - __check_limbo(d, false);
> + __check_limbo(d);
>
> if (has_busy_rmid(d)) {
> d->cqm_work_cpu = cpumask_any_housekeeping(&d->hdr.cpu_mask,
> diff --git a/fs/resctrl/rdtgroup.c b/fs/resctrl/rdtgroup.c
> index 5dcbb0a964e8..20c800e678d5 100644
> --- a/fs/resctrl/rdtgroup.c
> +++ b/fs/resctrl/rdtgroup.c
> @@ -4592,7 +4592,7 @@ void resctrl_offline_mon_domain(struct rdt_resource *r, struct rdt_domain_hdr *h
> * the RMID as busy creates RMID leaks if the
> * package never comes back.
> */
> - __check_limbo(d, true);
> + release_limbo_rmids(d);
> }
>
> domain_destroy_l3_mon_state(d);
--
Best regards,
Jinjie
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2 1/2] fs/resctrl: Report a temporary RMID shortage per CLOSID
2026-10-30 9:21 ` [PATCH v2 1/2] fs/resctrl: Report a temporary RMID shortage per CLOSID Jinjie Ruan
@ 2026-10-30 18:14 ` Reinette Chatre
0 siblings, 0 replies; 7+ messages in thread
From: Reinette Chatre @ 2026-10-30 18:14 UTC (permalink / raw)
To: Jinjie Ruan, tony.luck, Dave.Martin, james.morse, babu.moger, bp,
tan.shaopeng, x86, linux-kernel
Hi Jinjie,
On 10/30/26 2:21 AM, Jinjie Ruan wrote:
> An RMID that is freed is held in limbo until its cache occupancy drops
> below the threshold, after which it returns to the free list. A request
> that fails because of limbo is thus temporary and worth retrying, which
> resctrl reports to userspace as -EBUSY. A request that fails because
> every RMID is in use is permanent and reported as -ENOSPC.
>
> Where an RMID is only meaningful together with a CLOSID, a request can
> only be satisfied by an RMID belonging to the requested CLOSID, so the
> distinction has to be drawn per CLOSID. Instead it is drawn system wide.
> -ENOSPC is reported when the free list holds no RMID for the requested
> CLOSID, even when that CLOSID has RMIDs in limbo. -EBUSY is reported
> when the free list is empty and another CLOSID has an RMID in limbo,
> even when the requested CLOSID has none. Userspace is thus told to give
> up on a shortage that may clear on its own, and to retry one that cannot
> clear until it removes a group itself.
>
> Architectures where the RMID is independent of the CLOSID always match
> the first entry on the free list, so neither case arises there and only
> MPAM systems are affected.
>
> Draw the distinction from the number of RMIDs the requested CLOSID has
> in limbo where the RMID depends on the CLOSID, and from the system wide
> count otherwise. Drop the separate test for an empty free list, which
> the search handles on its own.
>
> Fixes: c4c0376eefe1 ("x86/resctrl: Allow RMID allocation to be scoped by CLOSID")
> Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
> Cc: James Morse <james.morse@arm.com>
> Cc: Reinette Chatre <reinette.chatre@intel.com>
> Cc: Babu Moger <babu.moger@amd.com>
> Cc: <stable@vger.kernel.org> # 7.1.x
> ---
Thank you very much.
Reviewed-by: Reinette Chatre <reinette.chatre@intel.com>
Reinette
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2 2/2] fs/resctrl: Do not allocate a monitor context when releasing limbo RMIDs
2026-10-30 9:21 ` [PATCH v2 2/2] fs/resctrl: Do not allocate a monitor context when releasing limbo RMIDs Jinjie Ruan
@ 2026-10-30 18:15 ` Reinette Chatre
0 siblings, 0 replies; 7+ messages in thread
From: Reinette Chatre @ 2026-10-30 18:15 UTC (permalink / raw)
To: Jinjie Ruan, tony.luck, Dave.Martin, james.morse, babu.moger, bp,
tan.shaopeng, x86, linux-kernel
Hi Jinjie,
On 10/30/26 2:21 AM, Jinjie Ruan wrote:
> Busy RMIDs of a monitor domain are normally released by the limbo
> handler once their cache occupancy drops below the threshold. When a
> domain goes offline, its busy RMIDs are released without checking
> occupancy, since the domain is going away and the RMIDs must not be
> left behind.
nit: "left behind" is vague. How about changing "RMIDs must not be
left behind" to "RMIDs would otherwise never return to the free list."
>
> On the monitor domain offline path, __check_limbo() allocates
> the monitor context that an occupancy check needs before it scans
> the busy RMIDs, but without using it, and returns early when that
> allocation fails. Then the caller destroys the domain's monitoring state,
> including the bitmap that records which RMIDs are busy, so nothing can
> clear those bits afterwards and the busy counts never reach zero. Those
> RMIDs never return to the free list and, where the RMID depends on
> the CLOSID, the dirty count of their CLOSID never decreases. The allocation
> can also wait for a monitor to become free, which stalls the CPU offline
> path on a context that is not going to be used.
>
> Only MPAM systems are affected. An architecture that can always read an
> RMID allocates nothing for the monitor context, so the allocation can
> neither fail nor wait there.
>
> So move the release of busy RMIDs into a separate function that does
nit: Please drop "So" to stick with imperative. Just start with "Move the release ..."
> not take a monitor context and leave the occupancy check to
> __check_limbo().
>
> This is not a revert of the fixed commit. It preserves the original fix's
> intent of not reading a counter in the offline path.
More on this below but after reconsidering the fallout I think above paragraph
needs to be dropped.
For entire changelog, could you please adjust the line wraps after edit to not
jump around as much?
>
> Fixes: fc16126cc11d ("x86,fs/resctrl: Prevent out-of-bounds access while offlining CPU when SNC enabled")
Taking a closer look, the issue as described is present before fc16126cc11d.
At fc16126cc11d^, __check_limbo() already returns early on allocation failure,
and the force-release caller already falls through to domain_destroy_l3_mon_state(d),
so the RMIDs leak there too.
The issue seems to originate from feature that added the allocation and early
release, which is:
e557999f80a5 ("x86/resctrl: Allow arch to allocate memory needed in resctrl_arch_rmid_read()")
Even so, as with patch #1, since the impact is only on MPAM this need not
be backported as far. I thus think the tags should be:
Fixes: e557999f80a5 ("x86/resctrl: Allow arch to allocate memory needed in resctrl_arch_rmid_read()")
and
Cc: <stable@vger.kernel.org> # 7.1.x
This fix does depend on fc16126cc11d to apply cleanly but fortunately it has been
backported to 7.1.
> Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
> Cc: James Morse <james.morse@arm.com>
> Cc: Reinette Chatre <reinette.chatre@intel.com>
> Cc: <stable@vger.kernel.org>
> ---
...
> /*
> * Check the RMIDs that are marked as busy for this domain. If the
> * reported LLC occupancy is below the threshold clear the busy bit and
> * decrement the count. If the busy count gets to zero on an RMID, we
> * free the RMID
> */
> -void __check_limbo(struct rdt_l3_mon_domain *d, bool force_free)
> +static void __check_limbo(struct rdt_l3_mon_domain *d)
> {
> struct rdt_resource *r = resctrl_arch_get_resource(RDT_RESOURCE_L3);
> u32 idx_limit = resctrl_arch_system_num_rmid_idx();
> struct rmid_entry *entry;
> - bool rmid_dirty = true;
> + bool rmid_dirty;
> u32 idx, cur_idx = 1;
> void *arch_mon_ctx;
> void *arch_priv;
Another difference between MPAM and tip style is that tip prefers variable
declarations to be in reverse fir order. For reference, see "Variable declarations" in
Documentation/process/maintainer-tip.rst.
Please re-order the declarations to maintain reverse fir.
Everything else looks good.
Thank you very much.
Reinette
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-10-30 18:15 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-30 9:21 [PATCH v2 0/2] fs/resctrl: Fix RMID limbo handling Jinjie Ruan
2026-10-30 9:21 ` [PATCH] fs/resctrl: Do not allocate a monitor context when releasing limbo RMIDs Jinjie Ruan
2026-10-30 9:23 ` Jinjie Ruan
2026-10-30 9:21 ` [PATCH v2 1/2] fs/resctrl: Report a temporary RMID shortage per CLOSID Jinjie Ruan
2026-10-30 18:14 ` Reinette Chatre
2026-10-30 9:21 ` [PATCH v2 2/2] fs/resctrl: Do not allocate a monitor context when releasing limbo RMIDs Jinjie Ruan
2026-10-30 18:15 ` Reinette Chatre
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®