From: "Thomas Hellström" <thomas.hellstrom@linux.intel.com>
To: Nitin Gote <nitin.r.gote@intel.com>, intel-xe@lists.freedesktop.org
Cc: stable@vger.kernel.org,
Christian Konig <christian.koenig@amd.com>,
Matthew Auld <matthew.auld@intel.com>
Subject: Re: [PATCH] drm/xe: Hold a dma-buf reference for imported BOs
Date: Fri, 10 Jul 2026 14:45:24 +0200 [thread overview]
Message-ID: <5f6b7649d0bcc6bc37691708d985bdb558a66adb.camel@linux.intel.com> (raw)
In-Reply-To: <20260710093726.43324-2-nitin.r.gote@intel.com>
On Fri, 2026-07-10 at 15:07 +0530, Nitin Gote wrote:
> An imported dma-buf BO is created as a ttm_bo_type_sg BO whose
> reservation object is the exporter's dma_buf->resv. The importer,
> however, only takes a dma-buf reference after a successful
> dma_buf_dynamic_attach(). Until then nothing keeps the exporter
> alive,
> so if the exporter is freed while the BO still references its resv, a
> later access to that resv is a use-after-free:
>
> Oops: general protection fault, probably for non-canonical address
> 0x6b6b6b6b6b6b6b9c
> Workqueue: ttm ttm_bo_delayed_delete [ttm]
> RIP: 0010:mutex_can_spin_on_owner+0x3f/0xc0
>
> This can be reached on two paths:
>
> - dma_buf_dynamic_attach() fails, or
> - ttm_bo_init_reserved() fails during BO creation.
>
> In both cases the BO already has bo->base.resv pointing at the
> exporter
> resv, and sg BOs are always torn down via ttm_bo_delayed_delete(),
> which
> locks bo->base.resv asynchronously - potentially after the exporter
> has
> been freed.
>
> Take the dma-buf reference in xe_bo_init_locked(), before
> ttm_bo_init_reserved(), so it also covers a creation failure there,
> and
> release it in xe_ttm_bo_destroy(). The reference is held for the
> whole
> BO lifetime, keeping the shared resv alive on every path.
>
> Closes:
> https://gitlab.freedesktop.org/drm/xe/kernel/-/work_items/8023
> Fixes: dd08ebf6c352 ("drm/xe: Introduce a new DRM driver for Intel
> GPUs")
> Cc: stable@vger.kernel.org
> Cc: Thomas Hellstrom <thomas.hellstrom@linux.intel.com>
> Cc: Christian Konig <christian.koenig@amd.com>
> Cc: Matthew Auld <matthew.auld@intel.com>
> Suggested-by: Thomas Hellstrom <thomas.hellstrom@linux.intel.com>
> Assisted-by: GitHub_Copilot:claude-sonnet-4.6
> Signed-off-by: Nitin Gote <nitin.r.gote@intel.com>
> ---
> Thank you Thomas for suggesting this simpler approach over the
> earlier
> TTM/LRU handling.
>
> v6:
> - Reworked the fix based on Thomas' suggestion. Instead of the TTM
> resv
> individualization (v1-v5) plus the xe off-LRU/placement handling
> (v5),
> just hold a dma-buf reference for the imported BO lifetime so the
> shared resv can never be freed while the BO still references it.
> Single xe patch, no TTM change. (Thomas)
> - Take the reference in xe_bo_init_locked() before
> ttm_bo_init_reserved()
> so a TTM creation failure is covered too (Thomas).
> - Dropped the v5 series (drm/ttm + drm/xe off-LRU); the off-LRU
> approach
> also regressed in CI BAT via ttm_bo_pipeline_gutting() creating a
> ghost
> BO that outlived the exporter.
> Link to v5: https://patchwork.freedesktop.org/series/169984/
>
> v5:
> - Add drm/xe patch to keep imported sg BOs off the LRU before attach
> succeeds; the TTM fix alone is not sufficient for xe if the BO is
> already LRU-visible. (Thomas)
> v4 patch:
>
> https://patchwork.freedesktop.org/patch/736663/?series=169129&rev=2
> - Patch 1 (drm/ttm) carries Christian's Reviewed-by from v4.
>
> v4:
> - Moved import_attach check to after dma_resv_copy_fences() so
> fences
> are copied before returning for successful imports (Thomas).
> - Removed exporter-alive claim from commit message (Thomas).
>
> v3:
> - Dropped the xe-side reordering approach since importer_priv must
> be
> valid when dma_buf_dynamic_attach() publishes the attachment.
> - Per Christian's suggestion on the v1 thread, keyed the check on
> import_attach rather than removing the sg guard entirely.
> - Fixes both xe and amdgpu in a single TTM patch.
We typically place the changelog above the ___ for xe, so it is kept in
the commit message. And in the reverse order so v3 comes first.
With that fixed,
Reviewed-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
>
>
> drivers/gpu/drm/xe/xe_bo.c | 24 ++++++++++++++++++++----
> drivers/gpu/drm/xe/xe_bo.h | 3 ++-
> drivers/gpu/drm/xe/xe_bo_types.h | 2 ++
> drivers/gpu/drm/xe/xe_dma_buf.c | 2 +-
> 4 files changed, 25 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/gpu/drm/xe/xe_bo.c b/drivers/gpu/drm/xe/xe_bo.c
> index 85e6d9a0f575..ae730bd6f4b2 100644
> --- a/drivers/gpu/drm/xe/xe_bo.c
> +++ b/drivers/gpu/drm/xe/xe_bo.c
> @@ -1349,7 +1349,7 @@ int xe_bo_notifier_prepare_pinned(struct xe_bo
> *bo)
> backup = xe_bo_init_locked(xe, NULL, NULL, bo-
> >ttm.base.resv, NULL, xe_bo_size(bo),
>
> DRM_XE_GEM_CPU_CACHING_WB, ttm_bo_type_kernel,
> XE_BO_FLAG_SYSTEM |
> XE_BO_FLAG_NEEDS_CPU_ACCESS |
> - XE_BO_FLAG_PINNED,
> &exec);
> + XE_BO_FLAG_PINNED, NULL,
> &exec);
> if (IS_ERR(backup)) {
> drm_exec_retry_on_contention(&exec);
> ret = PTR_ERR(backup);
> @@ -1490,7 +1490,7 @@ int xe_bo_evict_pinned(struct xe_bo *bo)
> xe_bo_size(bo),
>
> DRM_XE_GEM_CPU_CACHING_WB, ttm_bo_type_kernel,
> XE_BO_FLAG_SYSTEM
> | XE_BO_FLAG_NEEDS_CPU_ACCESS |
> -
> XE_BO_FLAG_PINNED, &exec);
> +
> XE_BO_FLAG_PINNED, NULL, &exec);
> if (IS_ERR(backup)) {
> drm_exec_retry_on_contention(&exec);
> ret = PTR_ERR(backup);
> @@ -1826,6 +1826,8 @@ static void xe_ttm_bo_destroy(struct
> ttm_buffer_object *ttm_bo)
>
> if (bo->ttm.base.import_attach)
> drm_prime_gem_destroy(&bo->ttm.base, NULL);
> + if (bo->dma_buf)
> + dma_buf_put(bo->dma_buf);
> drm_gem_object_release(&bo->ttm.base);
>
> xe_assert(xe, list_empty(&ttm_bo->base.gpuva.list));
> @@ -2283,6 +2285,8 @@ void xe_bo_free(struct xe_bo *bo)
> * @cpu_caching: The cpu caching used for system memory backing
> store.
> * @type: The TTM buffer object type.
> * @flags: XE_BO_FLAG_ flags.
> + * @dma_buf: The dma-buf to reference for the BO lifetime (imported
> BOs),
> + * or NULL.
> * @exec: The drm_exec transaction to use for exhaustive eviction.
> *
> * Initialize or create an xe buffer object. On failure, any
> allocated buffer
> @@ -2294,7 +2298,8 @@ struct xe_bo *xe_bo_init_locked(struct
> xe_device *xe, struct xe_bo *bo,
> struct xe_tile *tile, struct
> dma_resv *resv,
> struct ttm_lru_bulk_move *bulk,
> size_t size,
> u16 cpu_caching, enum ttm_bo_type
> type,
> - u32 flags, struct drm_exec *exec)
> + u32 flags, struct dma_buf *dma_buf,
> + struct drm_exec *exec)
> {
> struct ttm_operation_ctx ctx = {
> .interruptible = true,
> @@ -2383,6 +2388,17 @@ struct xe_bo *xe_bo_init_locked(struct
> xe_device *xe, struct xe_bo *bo,
> placement = (type == ttm_bo_type_sg ||
> bo->flags & XE_BO_FLAG_DEFER_BACKING) ?
> &sys_placement :
> &bo->placement;
> +
> + /*
> + * For imported BOs, keep the exporter dma-buf alive for the
> BO
> + * lifetime. Taken before ttm_bo_init_reserved() to also
> cover a
> + * creation failure there. Released in xe_ttm_bo_destroy().
> + */
> + if (dma_buf) {
> + get_dma_buf(dma_buf);
> + bo->dma_buf = dma_buf;
> + }
> +
> err = ttm_bo_init_reserved(&xe->ttm, &bo->ttm, type,
> placement, alignment,
> &ctx, NULL, resv,
> xe_ttm_bo_destroy);
> @@ -2500,7 +2516,7 @@ __xe_bo_create_locked(struct xe_device *xe,
> vm && !xe_vm_in_fault_mode(vm) &&
> flags & XE_BO_FLAG_USER ?
> &vm->lru_bulk_move : NULL, size,
> - cpu_caching, type, flags, exec);
> + cpu_caching, type, flags, NULL,
> exec);
> if (IS_ERR(bo))
> return bo;
>
> diff --git a/drivers/gpu/drm/xe/xe_bo.h b/drivers/gpu/drm/xe/xe_bo.h
> index 6340317f7d2e..7ae1d9ac0574 100644
> --- a/drivers/gpu/drm/xe/xe_bo.h
> +++ b/drivers/gpu/drm/xe/xe_bo.h
> @@ -118,7 +118,8 @@ struct xe_bo *xe_bo_init_locked(struct xe_device
> *xe, struct xe_bo *bo,
> struct xe_tile *tile, struct
> dma_resv *resv,
> struct ttm_lru_bulk_move *bulk,
> size_t size,
> u16 cpu_caching, enum ttm_bo_type
> type,
> - u32 flags, struct drm_exec *exec);
> + u32 flags, struct dma_buf *dma_buf,
> + struct drm_exec *exec);
> struct xe_bo *xe_bo_create_locked(struct xe_device *xe, struct
> xe_tile *tile,
> struct xe_vm *vm, size_t size,
> enum ttm_bo_type type, u32 flags,
> diff --git a/drivers/gpu/drm/xe/xe_bo_types.h
> b/drivers/gpu/drm/xe/xe_bo_types.h
> index fcc63ae3f455..e45f24301050 100644
> --- a/drivers/gpu/drm/xe/xe_bo_types.h
> +++ b/drivers/gpu/drm/xe/xe_bo_types.h
> @@ -36,6 +36,8 @@ struct xe_bo {
> struct xe_bo *backup_obj;
> /** @parent_obj: Ref to parent bo if this a backup_obj */
> struct xe_bo *parent_obj;
> + /** @dma_buf: Imported dma-buf ref to keep its resv alive.
> */
> + struct dma_buf *dma_buf;
> /** @flags: flags for this buffer object */
> u32 flags;
> /** @vm: VM this BO is attached to, for extobj this will be
> NULL */
> diff --git a/drivers/gpu/drm/xe/xe_dma_buf.c
> b/drivers/gpu/drm/xe/xe_dma_buf.c
> index 8a920e58245c..bf0728838ead 100644
> --- a/drivers/gpu/drm/xe/xe_dma_buf.c
> +++ b/drivers/gpu/drm/xe/xe_dma_buf.c
> @@ -302,7 +302,7 @@ xe_dma_buf_create_obj(struct drm_device *dev,
> struct dma_buf *dma_buf)
>
> bo = xe_bo_init_locked(xe, NULL, NULL, resv, NULL,
> dma_buf->size,
> 0, /* Will require 1way or
> 2way for vm_bind */
> - ttm_bo_type_sg,
> XE_BO_FLAG_SYSTEM, &exec);
> + ttm_bo_type_sg,
> XE_BO_FLAG_SYSTEM, dma_buf, &exec);
> drm_exec_retry_on_contention(&exec);
> if (IS_ERR(bo)) {
> ret = PTR_ERR(bo);
next prev parent reply other threads:[~2026-07-10 12:45 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-10 9:37 [PATCH] drm/xe: Hold a dma-buf reference for imported BOs Nitin Gote
2026-07-10 10:02 ` ✓ CI.KUnit: success for " Patchwork
2026-07-10 10:45 ` ✓ Xe.CI.BAT: " Patchwork
2026-07-10 12:45 ` Thomas Hellström [this message]
2026-07-10 19:39 ` ✗ Xe.CI.FULL: failure " Patchwork
-- strict thread matches above, loose matches on Subject: below --
2026-07-10 19:10 [PATCH] " Nitin Gote
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=5f6b7649d0bcc6bc37691708d985bdb558a66adb.camel@linux.intel.com \
--to=thomas.hellstrom@linux.intel.com \
--cc=christian.koenig@amd.com \
--cc=intel-xe@lists.freedesktop.org \
--cc=matthew.auld@intel.com \
--cc=nitin.r.gote@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