FAILED: patch "[PATCH] drm/xe: Wait on external BO kernel fences in exec IOCTL" failed to apply to 6.12-stable tree
Subsystems (3)
[email protected]
maintainerThe patch below does not apply to the 6.12-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.12.y
git checkout FETCH_HEAD
git cherry-pick -x af80e2bfde9312c76b60cf9274248dce0410b30d
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026072911-surplus-properly-117b@gregkh' --subject-prefix 'PATCH 6.12.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From af80e2bfde9312c76b60cf9274248dce0410b30d Mon Sep 17 00:00:00 2001
From: Matthew Brost <[email protected]>
Date: Thu, 2 Jul 2026 14:58:05 -0700
Subject: [PATCH] drm/xe: Wait on external BO kernel fences in exec IOCTL
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Before arming a user job, xe_exec_ioctl() only added the VM's dma-resv KERNEL slot as a dependency. That slot covers rebinds and the kernel operations of the VM's private BOs, but not external BOs (bo->vm == NULL), which carry their kernel operations (evictions, moves, ...) in their own dma-resv KERNEL slot.
The DMA_RESV_USAGE_KERNEL slot is the cross-driver contract for memory management operations that must complete before the BO or its backing store may be used: any accessor is required to wait on the KERNEL fences before touching the resv. By skipping the external BOs' KERNEL slots, the exec path violated that contract and could schedule a user job while a kernel operation on an external BO mapped by the VM was still in flight, racing against it and potentially reading or writing memory that was being moved.
Replace the VM-only dependency with an iteration over every object locked by the exec, adding each object's KERNEL slot as a job dependency. This covers the VM resv (rebinds and private BOs) as well as every external BO, mirroring the drm_gpuvm_resv_add_fence() call that later publishes the job fence to the same set of objects. Long-running mode continues to skip this, as before.
drivers/gpu/drm/xe/xe_exec.c +16 -6
@@ -292,13 +292,23 @@ int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file) goto err_exec; } -/* Wait behind rebinds */ +/* +* Wait behind rebinds and any kernel operations (evictions, defrag +* moves, ...) on the VM and all external BOs. The VM's private BOs +* carry their kernel ops in the VM dma-resv KERNEL slot, while each +* external BO carries them in its own dma-resv KERNEL slot; both are +* covered by iterating every object locked by the exec, mirroring the +* drm_gpuvm_resv_add_fence() below. +*/ if (!xe_vm_in_lr_mode (vm)) { - err =xe_sched_job_add_deps (job, -xe_vm_resv (vm), -DMA_RESV_USAGE_KERNEL ); -if (err) - goto err_put_job; +struct drm_gem_object *obj; + +drm_exec_for_each_locked_object (exec, obj) { + err =xe_sched_job_add_deps (job, obj->resv, +DMA_RESV_USAGE_KERNEL ); +if (err) + goto err_put_job; + } }for (i =0 ; i < num_syncs && !err; i++)
Sasha Levin
maintainerPATCH 1/2 drm/exec: Remove the index parameter from drm_exec_for_each_locked_obj[_reverse]
From: Thomas Hellström <[email protected]>
[ Upstream commit ce44b78512e9102aea54ff6b6e521d6c8de9f31c ]
Nobody makes any use of it. Possible internal future users can instead use the _index variable. External users shouldn't use it since the array it's pointing into is internal drm_exec state.
v2:
- Use a unique id for the loop variable (Christian)
Stable-dep-of: af80e2bfde93 ("drm/xe: Wait on external BO kernel fences in exec IOCTL")
--- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 9 +++------ drivers/gpu/drm/drm_exec.c | 6 ++---- drivers/gpu/drm/drm_gpuvm.c | 3 +-- drivers/gpu/drm/xe/xe_vm.c | 3 +-- include/drm/drm_exec.h | 20 ++++++++++++-------- 5 files changed, 19 insertions(+), 22 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +3 -6
@@ -843,7 +843,6 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p,struct amdgpu_vm *vm = &fpriv->vm;struct amdgpu_bo_list_entry *e;struct drm_gem_object *obj; -unsigned long index;unsigned int i;int r;
@@ -964,7 +963,7 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p, goto out_free_user_pages; } -drm_exec_for_each_locked_object (&p->exec, index, obj) { +drm_exec_for_each_locked_object (&p->exec, obj) { r =amdgpu_cs_bo_validate (p,gem_to_amdgpu_bo (obj));if (unlikely (r)) goto out_free_user_pages;
@@ -1202,7 +1201,6 @@ static int amdgpu_cs_sync_rings(struct amdgpu_cs_parser *p)struct drm_gpu_scheduler *sched;struct drm_gem_object *obj;struct dma_fence *fence; -unsigned long index;unsigned int i;int r;
@@ -1213,7 +1211,7 @@ static int amdgpu_cs_sync_rings(struct amdgpu_cs_parser *p)return r; } -drm_exec_for_each_locked_object (&p->exec, index, obj) { +drm_exec_for_each_locked_object (&p->exec, obj) {struct amdgpu_bo *bo =gem_to_amdgpu_bo (obj);struct dma_resv *resv = bo->tbo.base.resv;
@@ -1281,7 +1279,6 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p,struct amdgpu_vm *vm = &fpriv->vm;struct amdgpu_bo_list_entry *e;struct drm_gem_object *gobj; -unsigned long index;unsigned int i;uint64_t seq;int r;
@@ -1332,7 +1329,7 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p, } p->fence =dma_fence_get (&leader->base.s_fence->finished); -drm_exec_for_each_locked_object (&p->exec, index, gobj) { +drm_exec_for_each_locked_object (&p->exec, gobj) {ttm_bo_move_to_lru_tail_unlocked (&gem_to_amdgpu_bo (gobj)->tbo);
drivers/gpu/drm/drm_exec.c +2 -4
@@ -22,7 +22,6 @@* * struct drm_gem_object *obj; * struct drm_exec exec; -* unsigned long index; * int ret; * * drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT);
@@ -38,7 +37,7 @@* goto error; * } * -* drm_exec_for_each_locked_object(&exec, index, obj) { +* drm_exec_for_each_locked_object(&exec, obj) { * dma_resv_add_fence(obj->resv, fence, DMA_RESV_USAGE_READ); * ... * }
@@ -54,9 +53,8 @@static void drm_exec_unlock_all (struct drm_exec *exec) {struct drm_gem_object *obj; -unsigned long index; -drm_exec_for_each_locked_object_reverse (exec, index, obj) { +drm_exec_for_each_locked_object_reverse (exec, obj) {dma_resv_unlock (obj->resv);drm_gem_object_put (obj); }
drivers/gpu/drm/drm_gpuvm.c +1 -2
@@ -1451,9 +1451,8 @@ drm_gpuvm_resv_add_fence(struct drm_gpuvm *gpuvm, enum dma_resv_usage extobj_usage) {struct drm_gem_object *obj; -unsigned long index; -drm_exec_for_each_locked_object (exec, index, obj) { +drm_exec_for_each_locked_object (exec, obj) {dma_resv_assert_held (obj->resv); dma_resv_add_fence(obj->resv, fence, drm_gpuvm_is_extobj(gpuvm, obj) ?
drivers/gpu/drm/xe/xe_vm.c +1 -2
@@ -418,7 +418,6 @@ int xe_vm_validate_rebind(struct xe_vm *vm, struct drm_exec *exec, unsigned int num_fences) {struct drm_gem_object *obj; -unsigned long index;int ret; do {
@@ -431,7 +430,7 @@ int xe_vm_validate_rebind(struct xe_vm *vm, struct drm_exec *exec,return ret; }while (!list_empty (&vm->gpuvm.evict.list)); -drm_exec_for_each_locked_object (exec, index, obj) { +drm_exec_for_each_locked_object (exec, obj) { ret =dma_resv_reserve_fences (obj->resv, num_fences);if (ret)return ret;
include/drm/drm_exec.h +12 -8
@@ -65,31 +65,35 @@ drm_exec_obj(struct drm_exec *exec, unsigned long index)return index < exec->num_objects ? exec->objects[index] :NULL ; } +/* Helper for drm_exec_for_each_locked_object(). Internal use only. */ +#define __drm_exec_for_each_locked_object (exec, obj, __index) \ + for (unsigned long __index = 0; ((obj) = drm_exec_obj(exec, __index)); ++__index)/** * drm_exec_for_each_locked_object - iterate over all the locked objects * @exec: drm_exec object -* @index: unsigned long index for the iteration * @obj: the current GEM object * * Iterate over all the locked GEM objects inside the drm_exec object. */ -#define drm_exec_for_each_locked_object (exec, index, obj) \ - for ((index) = 0; ((obj) = drm_exec_obj(exec, index)); ++(index)) +#define drm_exec_for_each_locked_object (exec, obj) \ + __drm_exec_for_each_locked_object(exec, obj, __UNIQUE_ID(drm_exec)) +/* Helper for drm_exec_for_each_locked_object_reverse(). Internal use only. */ +#define __drm_exec_for_each_locked_object_reverse (exec, obj, __index) \ + for (unsigned long __index = (exec)->num_objects - 1; \ + ((obj) = drm_exec_obj(exec, __index)); --__index)/** * drm_exec_for_each_locked_object_reverse - iterate over all the locked * objects in reverse locking order * @exec: drm_exec object -* @index: unsigned long index for the iteration * @obj: the current GEM object * * Iterate over all the locked GEM objects inside the drm_exec object in -* reverse locking order. Note that @index may go below zero and wrap, +* reverse locking order. Note that the internal index may wrap around, * but that will be caught by drm_exec_obj(), returning a NULL object. */ -#define drm_exec_for_each_locked_object_reverse (exec, index, obj) \ - for ((index) = (exec)->num_objects - 1; \ - ((obj) = drm_exec_obj(exec, index)); --(index)) +#define drm_exec_for_each_locked_object_reverse (exec, obj) \ + __drm_exec_for_each_locked_object_reverse(exec, obj, __UNIQUE_ID(drm_exec))/** * drm_exec_until_all_locked - loop until all GEM objects are locked
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 2/2 drm/xe: Wait on external BO kernel fences in exec IOCTL
From: Matthew Brost <[email protected]>
[ Upstream commit af80e2bfde9312c76b60cf9274248dce0410b30d ]
Before arming a user job, xe_exec_ioctl() only added the VM's dma-resv KERNEL slot as a dependency. That slot covers rebinds and the kernel operations of the VM's private BOs, but not external BOs (bo->vm == NULL), which carry their kernel operations (evictions, moves, ...) in their own dma-resv KERNEL slot.
The DMA_RESV_USAGE_KERNEL slot is the cross-driver contract for memory management operations that must complete before the BO or its backing store may be used: any accessor is required to wait on the KERNEL fences before touching the resv. By skipping the external BOs' KERNEL slots, the exec path violated that contract and could schedule a user job while a kernel operation on an external BO mapped by the VM was still in flight, racing against it and potentially reading or writing memory that was being moved.
Replace the VM-only dependency with an iteration over every object locked by the exec, adding each object's KERNEL slot as a job dependency. This covers the VM resv (rebinds and private BOs) as well as every external BO, mirroring the drm_gpuvm_resv_add_fence() call that later publishes the job fence to the same set of objects. Long-running mode continues to skip this, as before.
--- drivers/gpu/drm/xe/xe_exec.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-)
drivers/gpu/drm/xe/xe_exec.c +16 -6
@@ -270,13 +270,23 @@ int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file) goto err_exec; } -/* Wait behind rebinds */ +/* +* Wait behind rebinds and any kernel operations (evictions, defrag +* moves, ...) on the VM and all external BOs. The VM's private BOs +* carry their kernel ops in the VM dma-resv KERNEL slot, while each +* external BO carries them in its own dma-resv KERNEL slot; both are +* covered by iterating every object locked by the exec, mirroring the +* drm_gpuvm_resv_add_fence() below. +*/ if (!xe_vm_in_lr_mode (vm)) { - err =xe_sched_job_add_deps (job, -xe_vm_resv (vm), -DMA_RESV_USAGE_KERNEL ); -if (err) - goto err_put_job; +struct drm_gem_object *obj; + +drm_exec_for_each_locked_object (exec, obj) { + err =xe_sched_job_add_deps (job, obj->resv, +DMA_RESV_USAGE_KERNEL ); +if (err) + goto err_put_job; + } }for (i =0 ; i < num_syncs && !err; i++)
Signature · 1 line
2.53.0