From: Tvrtko Ursulin <tursulin@ursulin.net>
To: Natalie Vock <natalie.vock@gmx.de>,
Maarten Lankhorst <dev@lankhorst.se>,
Maxime Ripard <mripard@kernel.org>, Tejun Heo <tj@kernel.org>,
Johannes Weiner <hannes@cmpxchg.org>,
Michal Koutný <mkoutny@suse.com>,
Christian Koenig <christian.koenig@amd.com>,
Huang Rui <ray.huang@amd.com>,
Matthew Auld <matthew.auld@intel.com>,
Matthew Brost <matthew.brost@intel.com>,
Maarten Lankhorst <maarten.lankhorst@linux.intel.com>,
Thomas Zimmermann <tzimmermann@suse.de>,
David Airlie <airlied@gmail.com>, Simona Vetter <simona@ffwll.ch>
Cc: cgroups@vger.kernel.org, dri-devel@lists.freedesktop.org
Subject: Re: [PATCH v4 3/6] drm/ttm: Extract code for attempting allocation in a place
Date: Wed, 25 Feb 2026 15:18:47 +0000 [thread overview]
Message-ID: <8c3db886-72d1-49c1-ac6c-7640af735e51@ursulin.net> (raw)
In-Reply-To: <20260225-dmemcg-aggressive-protect-v4-3-de847ab35184@gmx.de>
On 25/02/2026 12:10, Natalie Vock wrote:
> Move all code for attempting allocation for a specific place to
> ttm_bo_alloc_place. With subsequent patches, this logic is going to get
> more complicated, so it helps readability to have this separate.
>
> ttm_bo_alloc_at_place takes a pointer to a struct ttm_bo_alloc_state.
> This struct holds various state produced by the allocation (e.g. cgroup
> resource associated with the allocation) that the caller needs to keep
> track of (and potentially dispose of). This is just the limiting cgroup
> pool for now, but future patches will add more state needing to be tracked.
>
> ttm_bo_alloc_at_place also communicates via return codes if eviction
> using ttm_bo_evict_alloc should be attempted. This is preparation for
> attempting eviction in more cases than just force_space being set.
>
> No functional change intended.
>
> Signed-off-by: Natalie Vock <natalie.vock@gmx.de>
> ---
> drivers/gpu/drm/ttm/ttm_bo.c | 109 +++++++++++++++++++++++++++++++++----------
> 1 file changed, 84 insertions(+), 25 deletions(-)
>
> diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
> index acb9197db8798..48dbaaa46824c 100644
> --- a/drivers/gpu/drm/ttm/ttm_bo.c
> +++ b/drivers/gpu/drm/ttm/ttm_bo.c
> @@ -489,6 +489,11 @@ int ttm_bo_evict_first(struct ttm_device *bdev, struct ttm_resource_manager *man
> return ret;
> }
>
> +struct ttm_bo_alloc_state {
> + /** @limit_pool: Which pool limit we should test against */
> + struct dmem_cgroup_pool_state *limit_pool;
> +};
> +
> /**
> * struct ttm_bo_evict_walk - Parameters for the evict walk.
> */
> @@ -504,12 +509,13 @@ struct ttm_bo_evict_walk {
> /** @evicted: Number of successful evictions. */
> unsigned long evicted;
>
> - /** @limit_pool: Which pool limit we should test against */
> - struct dmem_cgroup_pool_state *limit_pool;
> /** @try_low: Whether we should attempt to evict BO's with low watermark threshold */
> bool try_low;
> /** @hit_low: If we cannot evict a bo when @try_low is false (first pass) */
> bool hit_low;
> +
> + /** @alloc_state: State associated with the allocation attempt. */
> + struct ttm_bo_alloc_state *alloc_state;
> };
>
> static s64 ttm_bo_evict_cb(struct ttm_lru_walk *walk, struct ttm_buffer_object *bo)
> @@ -518,8 +524,9 @@ static s64 ttm_bo_evict_cb(struct ttm_lru_walk *walk, struct ttm_buffer_object *
> container_of(walk, typeof(*evict_walk), walk);
> s64 lret;
>
> - if (!dmem_cgroup_state_evict_valuable(evict_walk->limit_pool, bo->resource->css,
> - evict_walk->try_low, &evict_walk->hit_low))
> + if (!dmem_cgroup_state_evict_valuable(evict_walk->alloc_state->limit_pool,
> + bo->resource->css, evict_walk->try_low,
> + &evict_walk->hit_low))
> return 0;
>
> if (bo->pin_count || !bo->bdev->funcs->eviction_valuable(bo, evict_walk->place))
> @@ -561,7 +568,7 @@ static int ttm_bo_evict_alloc(struct ttm_device *bdev,
> struct ttm_operation_ctx *ctx,
> struct ww_acquire_ctx *ticket,
> struct ttm_resource **res,
> - struct dmem_cgroup_pool_state *limit_pool)
> + struct ttm_bo_alloc_state *state)
> {
> struct ttm_bo_evict_walk evict_walk = {
> .walk = {
> @@ -574,7 +581,7 @@ static int ttm_bo_evict_alloc(struct ttm_device *bdev,
> .place = place,
> .evictor = evictor,
> .res = res,
> - .limit_pool = limit_pool,
> + .alloc_state = state,
> };
> s64 lret;
>
> @@ -689,6 +696,58 @@ static int ttm_bo_add_pipelined_eviction_fences(struct ttm_buffer_object *bo,
> return dma_resv_reserve_fences(bo->base.resv, 1);
> }
>
> +
> +/**
> + * ttm_bo_alloc_at_place - Attempt allocating a BO's backing store in a place
> + *
> + * @bo: The buffer to allocate the backing store of
> + * @place: The place to attempt allocation in
> + * @ctx: ttm_operation_ctx associated with this allocation
> + * @force_space: If we should evict buffers to force space
> + * @res: On allocation success, the resulting struct ttm_resource.
> + * @alloc_state: Object holding allocation state such as charged cgroups.
> + *
> + * Returns:
> + * -EBUSY: No space available, but allocation should be retried with ttm_bo_evict_alloc.
> + * -ENOSPC: No space available, allocation should not be retried.
> + * -ERESTARTSYS: An interruptible sleep was interrupted by a signal.
> + *
> + */
> +static int ttm_bo_alloc_at_place(struct ttm_buffer_object *bo,
> + const struct ttm_place *place,
> + struct ttm_operation_ctx *ctx,
> + bool force_space,
> + struct ttm_resource **res,
> + struct ttm_bo_alloc_state *alloc_state)
> +{
> + bool may_evict;
> + int ret;
> +
> + may_evict = (force_space && place->mem_type != TTM_PL_SYSTEM);
> +
> + ret = ttm_resource_alloc(bo, place, res,
> + force_space ? &alloc_state->limit_pool : NULL);
> +
> + if (ret) {
> + /*
> + * -EAGAIN means the charge failed, which we treat like an
> + * allocation failure. Therefore, return an error code indicating
> + * the allocation failed - either -EBUSY if the allocation should
> + * be retried with eviction, or -ENOSPC if there should be no second
> + * attempt.
> + */
> + if (ret == -EAGAIN)
> + return may_evict ? -EBUSY : -ENOSPC;
> +
> + if (ret == -ENOSPC && may_evict)
> + return -EBUSY;
> +
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> /**
> * ttm_bo_alloc_resource - Allocate backing store for a BO
> *
> @@ -714,7 +773,9 @@ static int ttm_bo_alloc_resource(struct ttm_buffer_object *bo,
> bool force_space,
> struct ttm_resource **res)
> {
> + struct ttm_bo_alloc_state alloc_state = {0};
= {};
> struct ttm_device *bdev = bo->bdev;
> + struct ttm_resource_manager *man;
I don't mind if you pull the above two out of the loop too much, but I
have to re-point it out since I am sure you know the principle of not
making changes which are not strictly needed, especially if they are not
a clear win on readability or something.
> struct ww_acquire_ctx *ticket;
> int i, ret;
>
> @@ -725,9 +786,6 @@ static int ttm_bo_alloc_resource(struct ttm_buffer_object *bo,
>
> for (i = 0; i < placement->num_placement; ++i) {
> const struct ttm_place *place = &placement->placement[i];
> - struct dmem_cgroup_pool_state *limit_pool = NULL;
> - struct ttm_resource_manager *man;
> - bool may_evict;
>
> man = ttm_manager_type(bdev, place->mem_type);
> if (!man || !ttm_resource_manager_used(man))
> @@ -737,25 +795,26 @@ static int ttm_bo_alloc_resource(struct ttm_buffer_object *bo,
> TTM_PL_FLAG_FALLBACK))
> continue;
>
> - may_evict = (force_space && place->mem_type != TTM_PL_SYSTEM);
> - ret = ttm_resource_alloc(bo, place, res, force_space ? &limit_pool : NULL);
> - if (ret) {
> - if (ret != -ENOSPC && ret != -EAGAIN) {
> - dmem_cgroup_pool_state_put(limit_pool);
> - return ret;
> - }
> - if (!may_evict) {
> - dmem_cgroup_pool_state_put(limit_pool);
> - continue;
> - }
> + ret = ttm_bo_alloc_at_place(bo, place, ctx, force_space,
> + res, &alloc_state);
>
> + if (ret == -ENOSPC) {
> + dmem_cgroup_pool_state_put(alloc_state.limit_pool);
> + continue;
> + } else if (ret == -EBUSY) {
> ret = ttm_bo_evict_alloc(bdev, man, place, bo, ctx,
> - ticket, res, limit_pool);
> - dmem_cgroup_pool_state_put(limit_pool);
> - if (ret == -EBUSY)
> + ticket, res, &alloc_state);
> +
> + dmem_cgroup_pool_state_put(alloc_state.limit_pool);
> +
> + if (ret) {
> + if (ret != -EBUSY)
> + return ret;
> continue;
> - if (ret)
> - return ret;
> + }
Would keeping the ret checks at one level of indentation look better? Eg
like the current version:
if (ret == -EBUSY)
continue;
else if (ret)
return ret;
Up to you.
Btw, it is an interesting design that there are eviction errors which
prevent trying the next placement. A bit surprising to me but it is out
of scope here.
Anyway, I went back and forth a few times over the logic and it indeed
looks to me that there are no functional changes. Thanks for improving
the commit message as well, now it is completely clear what the patch is
about. With or without the nitpicks:
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@igalia.com>
Regards,
Tvrtko
> + } else if (ret) {
> + dmem_cgroup_pool_state_put(alloc_state.limit_pool);
> + return ret;
> }
>
> ret = ttm_bo_add_pipelined_eviction_fences(bo, man, ctx->no_wait_gpu);
>
next prev parent reply other threads:[~2026-02-25 15:18 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-02-25 12:10 [PATCH v4 0/6] cgroup/dmem,drm/ttm: Improve protection in contended cases Natalie Vock
2026-02-25 12:10 ` [PATCH v4 1/6] cgroup/dmem: Add queries for protection values Natalie Vock
2026-02-27 3:36 ` Claude review: " Claude Code Review Bot
2026-02-25 12:10 ` [PATCH v4 2/6] cgroup/dmem: Add dmem_cgroup_common_ancestor helper Natalie Vock
2026-02-25 17:16 ` Tejun Heo
2026-02-27 3:36 ` Claude review: " Claude Code Review Bot
2026-02-25 12:10 ` [PATCH v4 3/6] drm/ttm: Extract code for attempting allocation in a place Natalie Vock
2026-02-25 15:18 ` Tvrtko Ursulin [this message]
2026-02-25 15:27 ` Tvrtko Ursulin
2026-02-26 8:56 ` Tvrtko Ursulin
2026-02-27 3:36 ` Claude review: " Claude Code Review Bot
2026-02-25 12:10 ` [PATCH v4 4/6] drm/ttm: Split cgroup charge and resource allocation Natalie Vock
2026-02-25 15:33 ` Tvrtko Ursulin
2026-02-25 16:01 ` Tvrtko Ursulin
2026-02-27 3:36 ` Claude review: " Claude Code Review Bot
2026-02-25 12:10 ` [PATCH v4 5/6] drm/ttm: Be more aggressive when allocating below protection limit Natalie Vock
2026-02-27 3:36 ` Claude review: " Claude Code Review Bot
2026-02-25 12:10 ` [PATCH v4 6/6] drm/ttm: Use common ancestor of evictor and evictee as limit pool Natalie Vock
2026-02-27 3:36 ` Claude review: " Claude Code Review Bot
2026-02-27 3:36 ` Claude review: cgroup/dmem,drm/ttm: Improve protection in contended cases Claude Code Review Bot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=8c3db886-72d1-49c1-ac6c-7640af735e51@ursulin.net \
--to=tursulin@ursulin.net \
--cc=airlied@gmail.com \
--cc=cgroups@vger.kernel.org \
--cc=christian.koenig@amd.com \
--cc=dev@lankhorst.se \
--cc=dri-devel@lists.freedesktop.org \
--cc=hannes@cmpxchg.org \
--cc=maarten.lankhorst@linux.intel.com \
--cc=matthew.auld@intel.com \
--cc=matthew.brost@intel.com \
--cc=mkoutny@suse.com \
--cc=mripard@kernel.org \
--cc=natalie.vock@gmx.de \
--cc=ray.huang@amd.com \
--cc=simona@ffwll.ch \
--cc=tj@kernel.org \
--cc=tzimmermann@suse.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox