Skip to content

Commit 6277552

Browse files
NitinGoteThomas Hellström
authored andcommitted
drm/xe: Hold a dma-buf reference for imported BOs
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. v2: - Reworked the fix to avoid creating the imported sg BO before dma_buf_dynamic_attach() succeeds. - Attach with importer_priv == NULL and make invalidate_mappings ignore incomplete imports. 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. 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). 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. 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/ v7: - Move changelog above --- so it stays in the commit message. - Reorder changelog entries oldest-to-newest. (Thomas) Closes: https://gitlab.freedesktop.org/drm/xe/kernel/-/work_items/8023 Fixes: dd08ebf ("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 Reviewed-by: Thomas Hellström <thomas.hellstrom@linux.intel.com> Signed-off-by: Nitin Gote <nitin.r.gote@intel.com> Signed-off-by: Matthew Auld <matthew.auld@intel.com> Link: https://patch.msgid.link/20260710191027.260160-2-nitin.r.gote@intel.com (cherry picked from commit 3516f3f) Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
1 parent 7bc597c commit 6277552

4 files changed

Lines changed: 25 additions & 6 deletions

File tree

drivers/gpu/drm/xe/xe_bo.c

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1349,7 +1349,7 @@ int xe_bo_notifier_prepare_pinned(struct xe_bo *bo)
13491349
backup = xe_bo_init_locked(xe, NULL, NULL, bo->ttm.base.resv, NULL, xe_bo_size(bo),
13501350
DRM_XE_GEM_CPU_CACHING_WB, ttm_bo_type_kernel,
13511351
XE_BO_FLAG_SYSTEM | XE_BO_FLAG_NEEDS_CPU_ACCESS |
1352-
XE_BO_FLAG_PINNED, &exec);
1352+
XE_BO_FLAG_PINNED, NULL, &exec);
13531353
if (IS_ERR(backup)) {
13541354
drm_exec_retry_on_contention(&exec);
13551355
ret = PTR_ERR(backup);
@@ -1490,7 +1490,7 @@ int xe_bo_evict_pinned(struct xe_bo *bo)
14901490
xe_bo_size(bo),
14911491
DRM_XE_GEM_CPU_CACHING_WB, ttm_bo_type_kernel,
14921492
XE_BO_FLAG_SYSTEM | XE_BO_FLAG_NEEDS_CPU_ACCESS |
1493-
XE_BO_FLAG_PINNED, &exec);
1493+
XE_BO_FLAG_PINNED, NULL, &exec);
14941494
if (IS_ERR(backup)) {
14951495
drm_exec_retry_on_contention(&exec);
14961496
ret = PTR_ERR(backup);
@@ -1826,6 +1826,8 @@ static void xe_ttm_bo_destroy(struct ttm_buffer_object *ttm_bo)
18261826

18271827
if (bo->ttm.base.import_attach)
18281828
drm_prime_gem_destroy(&bo->ttm.base, NULL);
1829+
if (bo->dma_buf)
1830+
dma_buf_put(bo->dma_buf);
18291831
drm_gem_object_release(&bo->ttm.base);
18301832

18311833
xe_assert(xe, list_empty(&ttm_bo->base.gpuva.list));
@@ -2283,6 +2285,8 @@ void xe_bo_free(struct xe_bo *bo)
22832285
* @cpu_caching: The cpu caching used for system memory backing store.
22842286
* @type: The TTM buffer object type.
22852287
* @flags: XE_BO_FLAG_ flags.
2288+
* @dma_buf: The dma-buf to reference for the BO lifetime (imported BOs),
2289+
* or NULL.
22862290
* @exec: The drm_exec transaction to use for exhaustive eviction.
22872291
*
22882292
* 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,
22942298
struct xe_tile *tile, struct dma_resv *resv,
22952299
struct ttm_lru_bulk_move *bulk, size_t size,
22962300
u16 cpu_caching, enum ttm_bo_type type,
2297-
u32 flags, struct drm_exec *exec)
2301+
u32 flags, struct dma_buf *dma_buf,
2302+
struct drm_exec *exec)
22982303
{
22992304
struct ttm_operation_ctx ctx = {
23002305
.interruptible = true,
@@ -2383,6 +2388,17 @@ struct xe_bo *xe_bo_init_locked(struct xe_device *xe, struct xe_bo *bo,
23832388
placement = (type == ttm_bo_type_sg ||
23842389
bo->flags & XE_BO_FLAG_DEFER_BACKING) ? &sys_placement :
23852390
&bo->placement;
2391+
2392+
/*
2393+
* For imported BOs, keep the exporter dma-buf alive for the BO
2394+
* lifetime. Taken before ttm_bo_init_reserved() to also cover a
2395+
* creation failure there. Released in xe_ttm_bo_destroy().
2396+
*/
2397+
if (dma_buf) {
2398+
get_dma_buf(dma_buf);
2399+
bo->dma_buf = dma_buf;
2400+
}
2401+
23862402
err = ttm_bo_init_reserved(&xe->ttm, &bo->ttm, type,
23872403
placement, alignment,
23882404
&ctx, NULL, resv, xe_ttm_bo_destroy);
@@ -2500,7 +2516,7 @@ __xe_bo_create_locked(struct xe_device *xe,
25002516
vm && !xe_vm_in_fault_mode(vm) &&
25012517
flags & XE_BO_FLAG_USER ?
25022518
&vm->lru_bulk_move : NULL, size,
2503-
cpu_caching, type, flags, exec);
2519+
cpu_caching, type, flags, NULL, exec);
25042520
if (IS_ERR(bo))
25052521
return bo;
25062522

drivers/gpu/drm/xe/xe_bo.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,8 @@ struct xe_bo *xe_bo_init_locked(struct xe_device *xe, struct xe_bo *bo,
118118
struct xe_tile *tile, struct dma_resv *resv,
119119
struct ttm_lru_bulk_move *bulk, size_t size,
120120
u16 cpu_caching, enum ttm_bo_type type,
121-
u32 flags, struct drm_exec *exec);
121+
u32 flags, struct dma_buf *dma_buf,
122+
struct drm_exec *exec);
122123
struct xe_bo *xe_bo_create_locked(struct xe_device *xe, struct xe_tile *tile,
123124
struct xe_vm *vm, size_t size,
124125
enum ttm_bo_type type, u32 flags,

drivers/gpu/drm/xe/xe_bo_types.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ struct xe_bo {
3636
struct xe_bo *backup_obj;
3737
/** @parent_obj: Ref to parent bo if this a backup_obj */
3838
struct xe_bo *parent_obj;
39+
/** @dma_buf: Imported dma-buf ref to keep its resv alive. */
40+
struct dma_buf *dma_buf;
3941
/** @flags: flags for this buffer object */
4042
u32 flags;
4143
/** @vm: VM this BO is attached to, for extobj this will be NULL */

drivers/gpu/drm/xe/xe_dma_buf.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,7 @@ xe_dma_buf_create_obj(struct drm_device *dev, struct dma_buf *dma_buf)
302302

303303
bo = xe_bo_init_locked(xe, NULL, NULL, resv, NULL, dma_buf->size,
304304
0, /* Will require 1way or 2way for vm_bind */
305-
ttm_bo_type_sg, XE_BO_FLAG_SYSTEM, &exec);
305+
ttm_bo_type_sg, XE_BO_FLAG_SYSTEM, dma_buf, &exec);
306306
drm_exec_retry_on_contention(&exec);
307307
if (IS_ERR(bo)) {
308308
ret = PTR_ERR(bo);

0 commit comments

Comments
 (0)