From: "Thomas Hellström" <thomas.hellstrom@linux.intel.com>
To: intel-xe@lists.freedesktop.org
Cc: "Thomas Hellström" <thomas.hellstrom@linux.intel.com>,
"Matthew Brost" <matthew.brost@intel.com>,
"Matthew Auld" <matthew.auld@intel.com>,
"Rodrigo Vivi" <rodrigo.vivi@intel.com>,
stable@vger.kernel.org
Subject: [PATCH] drm/xe: Fix shrinker accounting double-subtraction on nested external pins
Date: Mon, 14 Sep 2026 15:45:40 +0200 [thread overview]
Message-ID: <20260914134540.385186-1-thomas.hellstrom@linux.intel.com> (raw)
xe_bo_pin_external() and xe_bo_unpin_external() support nested pins,
since the underlying ttm_bo_pin()/ttm_bo_unpin() maintain a pin_count
refcount rather than a boolean. However, the shrinker accounting calls
xe_ttm_tt_account_subtract() and xe_ttm_tt_account_add() are invoked
unconditionally on every pin_external()/unpin_external() call, instead
of only on the transition into and out of the pinned state.
An external BO (dma-buf) can be pinned more than once while already
pinned, for example when it has multiple attachments/importers, each
independently calling xe_bo_pin_external(). Each such nested pin
subtracts the BO's pages from the shrinker's accounting again, even
though the BO's pages were already removed from consideration by the
first pin. Symmetrically, each nested unpin adds them back again
before the BO is actually unpinned. This desynchronizes the
shrinker's page and object counts from reality, and since they are
declared as signed long but interpreted as unsigned long in
xe_shrinker_count(), the underflow can turn into an enormous
shrinkable/purgeable page count, causing the shrinker to be invoked
excessively under memory pressure.
Guard the accounting calls with the same pin-count transition checks
already used to guard the pinned_link list maintenance, so accounting
is only updated on the outermost pin and the final unpin.
Fixes: 00c8efc3180f ("drm/xe: Add a shrinker for xe bos")
Cc: Thomas Hellström <thomas.hellstrom@linux.intel.com>
Cc: Matthew Brost <matthew.brost@intel.com>
Cc: Matthew Auld <matthew.auld@intel.com>
Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
Cc: intel-xe@lists.freedesktop.org
Cc: <stable@vger.kernel.org> # v6.15+
Assisted-by: LLM
Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
---
drivers/gpu/drm/xe/xe_bo.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/xe/xe_bo.c b/drivers/gpu/drm/xe/xe_bo.c
index 9f3f0cb95afa..f46ff260be9b 100644
--- a/drivers/gpu/drm/xe/xe_bo.c
+++ b/drivers/gpu/drm/xe/xe_bo.c
@@ -3141,12 +3141,13 @@ uint64_t vram_region_gpu_offset(struct ttm_resource *res)
int xe_bo_pin_external(struct xe_bo *bo, bool in_place, struct drm_exec *exec)
{
struct xe_device *xe = xe_bo_device(bo);
+ bool first_pin = !xe_bo_is_pinned(bo);
int err;
xe_assert(xe, !bo->vm);
xe_assert(xe, xe_bo_is_user(bo));
- if (!xe_bo_is_pinned(bo)) {
+ if (first_pin) {
if (!in_place) {
err = xe_bo_validate(bo, NULL, false, exec);
if (err)
@@ -3159,7 +3160,7 @@ int xe_bo_pin_external(struct xe_bo *bo, bool in_place, struct drm_exec *exec)
}
ttm_bo_pin(&bo->ttm);
- if (bo->ttm.ttm && ttm_tt_is_populated(bo->ttm.ttm))
+ if (first_pin && bo->ttm.ttm && ttm_tt_is_populated(bo->ttm.ttm))
xe_ttm_tt_account_subtract(xe, bo->ttm.ttm);
/*
@@ -3242,18 +3243,19 @@ int xe_bo_pin(struct xe_bo *bo, struct drm_exec *exec)
void xe_bo_unpin_external(struct xe_bo *bo)
{
struct xe_device *xe = xe_bo_device(bo);
+ bool last_unpin = bo->ttm.pin_count == 1;
xe_assert(xe, !bo->vm);
xe_assert(xe, xe_bo_is_pinned(bo));
xe_assert(xe, xe_bo_is_user(bo));
spin_lock(&xe->pinned.lock);
- if (bo->ttm.pin_count == 1 && !list_empty(&bo->pinned_link))
+ if (last_unpin && !list_empty(&bo->pinned_link))
list_del_init(&bo->pinned_link);
spin_unlock(&xe->pinned.lock);
ttm_bo_unpin(&bo->ttm);
- if (bo->ttm.ttm && ttm_tt_is_populated(bo->ttm.ttm))
+ if (last_unpin && bo->ttm.ttm && ttm_tt_is_populated(bo->ttm.ttm))
xe_ttm_tt_account_add(xe, bo->ttm.ttm);
/*
--
2.55.0
next reply other threads:[~2026-09-14 13:46 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-14 13:45 Thomas Hellström [this message]
2026-09-14 14:15 ` [PATCH] drm/xe: Fix shrinker accounting double-subtraction on nested external pins sashiko-bot
2026-09-14 14:40 ` Matthew Auld
2026-09-14 15:43 ` ✓ CI.KUnit: success for " Patchwork
2026-09-14 17:06 ` ✓ Xe.CI.BAT: " Patchwork
2026-09-14 20:58 ` ✓ Xe.CI.FULL: " Patchwork
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=20260914134540.385186-1-thomas.hellstrom@linux.intel.com \
--to=thomas.hellstrom@linux.intel.com \
--cc=intel-xe@lists.freedesktop.org \
--cc=matthew.auld@intel.com \
--cc=matthew.brost@intel.com \
--cc=rodrigo.vivi@intel.com \
--cc=stable@vger.kernel.org \
/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