[Devel] [PATCH hci-8.1 6/6] ms/cgroup/dmem: Add reclaim callback for lowering max below current usage

Mirian Shilakadze mirian.shilakadze at virtuozzo.com
Mon Nov 2 02:51:48 MSK 2026


From: Thomas Hellström <thomas.hellstrom at linux.intel.com>

Add an optional reclaim callback to struct dmem_cgroup_region. When
dmem.max is set below the current usage of a cgroup pool, the new limit
is applied immediately (so that concurrent allocations are throttled
while reclaim is in progress) and then the driver is asked to evict
memory to bring usage back below the limit.

Reclaim is attempted up to a bounded number of times. No error is
returned to userspace if usage remains above the limit after reclaim,
and a pending signal will abort the reclaim loop early. This matches
the behavior of memory.max in the memory cgroup controller.

Also honor O_NONBLOCK so that if that flag is set during the
max value write, no reclaim is initiated. The idea is to avoid
charging the reclaim cost to the writer of the max value.

v2:
- Write max before reclaim is attempted (Maarten)
- Let signals abort the reclaim without error (Maarten)
- If a new max value is written with the O_NONBLOCK flag,
  reclaim is not attempted (Maarten)
- Extract region from the pool parameter rather than
  passing it explicitly to set_resource_xxx().

v3:
- Use an rw_semaphore (unregister_sem) to protect reclaim callbacks
  against concurrent region unregistration: readers (reclaim) hold the
  read side; dmem_cgroup_unregister_region() takes the write side to
  drain in-flight callbacks before returning. (Sashiko-bot)

v5:
- Rebased on the introduction of struct dmem_cgroup_init.
- Use nonblock=true in reset_all_resource_limits() to avoid sleeping
  inside rcu_read_lock() in dmemcs_offline(). (Sashiko-bot)
- Compare usage against the truncated limit value stored in cnt.max,
  not the original u64. (Sashiko-bot)
- Use a DMEM_MAX_RECLAIM_RETRIES (16) retry budget instead of 5, matching
  the memcg controller's MAX_RECLAIM_RETRIES. Only -ENOSPC (no progress)
  counts against the retry budget; other errors terminate the loop
  immediately.

v6:
- Fix dmem_cgroup_ops->reclaim docstring: -ENOSPC does not stop reclaim
  immediately but is retried up to DMEM_MAX_RECLAIM_RETRIES times; only
  other negative errors terminate the loop. (Sashiko-bot)

v7:
- Replace the per-region rw_semaphore with a static SRCU domain
  (dmemcg_srcu). SRCU is a better fit than rwsem for this use: it
  avoids the per-region lock overhead on every reclaim call, and
  synchronize_srcu() at unregister time is a rare operation. (Maarten)
- Trim in-function comments to focus on what rather than how.

Assisted-by: GitHub_Copilot:claude-sonnet-4.6
Signed-off-by: Thomas Hellström <thomas.hellstrom at linux.intel.com>
Reviewed-by: Maarten Lankhorst <maarten.lankhorst at linux.intel.com>
Tested-by: Thadeu Lima de Souza Cascardo <cascardo at igalia.com>
Link: https://patch.msgid.link/20260725100036.2372-4-thomas.hellstrom@linux.intel.com
Signed-off-by: Maarten Lankhorst <dev at lankhorst.se>
(cherry picked from commit 747c4bb450adcd8b99d3543448419e1952755832)

Rebase note: only the first step of set_resource_max() is taken: the
new limit is applied at once instead of through page_counter_set_max(),
which leaves the old limit when usage is above the new one. The reclaim
callback is left out, with the retry loop, the O_NONBLOCK handling and
the SRCU protection that only serve it. Drivers pass the callback in
the struct dmem_cgroup_init of e11640b9cea4 ("cgroup/dmem: Introduce
struct dmem_cgroup_init for region initialization"), which changes
dmem_cgroup_register_region() for every driver and does not apply to
this tree. So lowering dmem.max below the usage of an amdgpu or xe pool
does not evict at once, as upstream does since 425a783e1bc1 ("drm/ttm:
Hook up a cgroup-aware reclaim callback for the dmem controller") with
bd4f284df04d for amdgpu and 042a1bea20db for xe. TTM evicts the pool's
buffers when its next allocation hits the limit. For the NVIDIA driver,
which registers no callback, this is the same as upstream.

https://virtuozzo.atlassian.net/browse/VSTOR-152813
Signed-off-by: Mirian Shilakadze <mirian.shilakadze at virtuozzo.com>
---
 kernel/cgroup/dmem.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/kernel/cgroup/dmem.c b/kernel/cgroup/dmem.c
index 8424df801bc0..46b6aca765a4 100644
--- a/kernel/cgroup/dmem.c
+++ b/kernel/cgroup/dmem.c
@@ -158,7 +158,10 @@ set_resource_low(struct dmem_cgroup_pool_state *pool, u64 val)
 static void
 set_resource_max(struct dmem_cgroup_pool_state *pool, u64 val)
 {
-	page_counter_set_max(&pool->cnt, val);
+	unsigned long limit = (unsigned long)val;
+
+	/* Apply the new limit immediately so concurrent allocations are throttled. */
+	xchg(&pool->cnt.max, limit);
 }
 
 static u64 get_resource_low(struct dmem_cgroup_pool_state *pool)
-- 
2.43.0



More information about the Devel mailing list