Re: [PATCH v7 10/12] drm/xe/bo: Add purgeable shrinker state helpers

Thomas Hellström
2026-03-24T14:51:55Z

On Mon, 2026-03-23 at 15:00 +0530, Arvind Yadav wrote:
> Encapsulate TTM purgeable flag updates and shrinker page accounting
> into helper functions to prevent desynchronization between the TTM
> tt->purgeable flag and the shrinker's page bucket counters.
>
> Without these helpers, direct manipulation of xe_ttm_tt->purgeable
> risks forgetting to update the corresponding shrinker counters,
> leading to incorrect memory pressure calculations.
>
> Update purgeable BO state to PURGED after successful shrinker purge
> for DONTNEED BOs.
>
> v4:
>   - @madv_purgeable atomic_t → u32 change across all relevant
>     patches (Matt)
>
> v5:
>   - Update purgeable BO state to PURGED after a successful shrinker
>     purge for DONTNEED BOs.
>   - Split ghost BO and zero-refcount handling in xe_bo_shrink()
> (Thomas)
>
> v6:
>   - Create separate patch for 'Split ghost BO and zero-refcount
>     handling'. (Thomas)
>
> v7:
>   - Merge xe_bo_set_purgeable_shrinker() and
> xe_bo_clear_purgeable_shrinker()
>     into a single static helper xe_bo_set_purgeable_shrinker(bo,
> new_state)
>     called automatically from xe_bo_set_purgeable_state(). Callers no
> longer
>     need to manage shrinker accounting separately. (Thomas)
>
> Cc: Matthew Brost <matthew.brost@intel.com>
> Cc: Himal Prasad Ghimiray <himal.prasad.ghimiray@intel.com>
> Cc: Thomas Hellström <thomas.hellstrom@linux.intel.com>
> Signed-off-by: Arvind Yadav <arvind.yadav@intel.com>

Reviewed-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>

> ---
>  drivers/gpu/drm/xe/xe_bo.c | 43
> +++++++++++++++++++++++++++++++++++++-
>  1 file changed, 42 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/xe/xe_bo.c b/drivers/gpu/drm/xe/xe_bo.c
> index 83a1d1ca6cc6..85e42e785ebe 100644
> --- a/drivers/gpu/drm/xe/xe_bo.c
> +++ b/drivers/gpu/drm/xe/xe_bo.c
> @@ -835,6 +835,42 @@ static int xe_bo_move_notify(struct xe_bo *bo,
>   return 0;
>  }
>
> +/**
> + * xe_bo_set_purgeable_shrinker() - Update shrinker accounting for
> purgeable state
> + * @bo: Buffer object
> + * @new_state: New purgeable state being set
> + *
> + * Transfers pages between shrinkable and purgeable buckets when the
> BO
> + * purgeable state changes. Called automatically from
> xe_bo_set_purgeable_state().
> + */
> +static void xe_bo_set_purgeable_shrinker(struct xe_bo *bo,
> + enum
> xe_madv_purgeable_state new_state)
> +{
> + struct ttm_buffer_object *ttm_bo = &bo->ttm;
> + struct ttm_tt *tt = ttm_bo->ttm;
> + struct xe_device *xe = ttm_to_xe_device(ttm_bo->bdev);
> + struct xe_ttm_tt *xe_tt;
> + long tt_pages;
> +
> + xe_bo_assert_held(bo);
> +
> + if (!tt || !ttm_tt_is_populated(tt))
> + return;
> +
> + xe_tt = container_of(tt, struct xe_ttm_tt, ttm);
> + tt_pages = tt->num_pages;
> +
> + if (!xe_tt->purgeable && new_state ==
> XE_MADV_PURGEABLE_DONTNEED) {
> + xe_tt->purgeable = true;
> + /* Transfer pages from shrinkable to purgeable count
> */
> + xe_shrinker_mod_pages(xe->mem.shrinker, -tt_pages,
> tt_pages);
> + } else if (xe_tt->purgeable && new_state ==
> XE_MADV_PURGEABLE_WILLNEED) {
> + xe_tt->purgeable = false;
> + /* Transfer pages from purgeable to shrinkable count
> */
> + xe_shrinker_mod_pages(xe->mem.shrinker, tt_pages, -
> tt_pages);
> + }
> +}
> +
>  /**
>   * xe_bo_set_purgeable_state() - Set BO purgeable state with
> validation
>   * @bo: Buffer object
> @@ -842,7 +878,8 @@ static int xe_bo_move_notify(struct xe_bo *bo,
>   *
>   * Sets the purgeable state with lockdep assertions and validates
> state
>   * transitions. Once a BO is PURGED, it cannot transition to any
> other state.
> - * Invalid transitions are caught with xe_assert().
> + * Invalid transitions are caught with xe_assert(). Shrinker page
> accounting
> + * is updated automatically.
>   */
>  void xe_bo_set_purgeable_state(struct xe_bo *bo,
>          enum xe_madv_purgeable_state
> new_state)
> @@ -861,6 +898,7 @@ void xe_bo_set_purgeable_state(struct xe_bo *bo,
>   new_state != XE_MADV_PURGEABLE_PURGED));
>
>   bo->madv_purgeable = new_state;
> + xe_bo_set_purgeable_shrinker(bo, new_state);
>  }
>
>  /**
> @@ -1243,6 +1281,9 @@ long xe_bo_shrink(struct ttm_operation_ctx
> *ctx, struct ttm_buffer_object *bo,
>   lret = xe_bo_move_notify(xe_bo, ctx);
>   if (!lret)
>   lret = xe_bo_shrink_purge(ctx, bo, scanned);
> + if (lret > 0 && xe_bo_madv_is_dontneed(xe_bo))
> + xe_bo_set_purgeable_state(xe_bo,
> +
> XE_MADV_PURGEABLE_PURGED);
>   goto out_unref;
>   }
>