Re: [PATCH v8 6/6] drm/ttm: Use common ancestor of evictor and evictee as limit pool

[email protected] Tue, 04 Aug 2026 08:53:38 +0000
Newsgroups org.freedesktop.lists.dri-devel
Message-ID <[email protected]>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Critical] Refcount underflow and use-after-free of cgroup subsystem state (css).
- [High] GFP_KERNEL allocation while holding a dma_resv lock causes lockdep warnings and potential deadlocks.
--

--- Patch [6]: [PATCH v8 6/6] drm/ttm: Use common ancestor of evictor and evictee as limit pool ---
commit 80190cfff36182bea4c8b3f724df7df584bfc3b3
Author: Natalie Vock <[email protected]>

drm/ttm: Use common ancestor of evictor and evictee as limit pool
    
When checking if buffers should be skipped for eviction due to dmem.low
protection, this patch calculates the protection from the shared ancestor
of the evictor and evictee instead of the root cgroup. This prevents
breaking prioritization of sibling cgroups.

> diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
> index 6bbea148838e4..79c96aba4bf49 100644
> --- a/drivers/gpu/drm/ttm/ttm_bo.c
> +++ b/drivers/gpu/drm/ttm/ttm_bo.c
[ ... ]
> @@ -628,11 +628,48 @@ static s64 ttm_bo_evict_cb(struct ttm_lru_walk *walk, struct ttm_buffer_object *
>  {
>  	struct ttm_bo_evict_walk *evict_walk =
>  		container_of(walk, typeof(*evict_walk), walk);
> +	struct dmem_cgroup_pool_state *limit_pool, *ancestor = NULL;
> +	bool evict_valuable;
>  	s64 lret;
>  
[ ... ]
> +	if (!limit_pool) {
> +		ancestor = dmem_cgroup_get_common_ancestor(bo->resource->css,
> +							   evict_walk->alloc_state->charge_pool);

[Severity: High]
Does this allocation path trigger a deadlock?

ttm_bo_evict_cb() is executed via ttm_lru_walk_for_evict() which holds the
dma_resv lock of the buffer object (acquired via
ttm_bo_lru_for_each_reserved_guarded).

When calling dmem_cgroup_get_common_ancestor(), it can end up in
get_cg_pool_unlocked() which does a GFP_KERNEL allocation if the ancestor
pool does not exist:

kernel/cgroup/dmem.c:get_cg_pool_unlocked() {
	...
	allocpool = kzalloc_obj(*allocpool);
	...
}

Using GFP_KERNEL while holding a dma_resv lock can trigger direct memory
reclaim, which in turn can invoke GPU shrinkers.

Those shrinkers will attempt to acquire dma_resv locks, leading to a
potential deadlock.

> +		limit_pool = ancestor;
> +	}
> +
> +	evict_valuable = dmem_cgroup_state_evict_valuable(limit_pool, bo->resource->css,
> +							  evict_walk->try_low,
> +							  &evict_walk->hit_low);
> +	if (ancestor)
> +		dmem_cgroup_pool_state_put(ancestor);

[Severity: Critical]
Does this cause a refcount underflow and use-after-free of the cgroup
subsystem state (css)?

dmem_cgroup_get_common_ancestor() acquires and returns a pool reference but
explicitly drops its temporary css reference before returning:

kernel/cgroup/dmem.c:dmem_cgroup_get_common_ancestor() {
	...
	if (IS_ERR(pool))
		pool = NULL;
	css_put(ancestor_css);
	return pool;
}

However, dmem_cgroup_pool_state_put() is designed to balance
dmem_cgroup_try_charge() and drops both a pool reference and a css reference.

Since dmem_cgroup_get_common_ancestor() did not acquire an extra css reference
for the caller, the css_put() in dmem_cgroup_pool_state_put() causes an
underflow.

This can lead to premature freeing of the css, resulting in a use-after-free
and memory corruption.

> +
> +	if (!evict_valuable)
>  		return 0;

-- 
Sashiko AI review ยท https://sashiko.dev/#/patchset/[email protected]?part=6