From: Thomas Hellström <[email protected]> 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 <[email protected]> Reviewed-by: Maarten Lankhorst <[email protected]> Tested-by: Thadeu Lima de Souza Cascardo <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Maarten Lankhorst <[email protected]> (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 <[email protected]> --- 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 _______________________________________________ Devel mailing list [email protected] https://lists.openvz.org/mailman/listinfo/devel
