]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
drm/vmwgfx: take fman->lock around fence list mutation in fifo_down
authorZack Rusin <zack.rusin@broadcom.com>
Tue, 5 May 2026 22:22:25 +0000 (18:22 -0400)
committerZack Rusin <zack.rusin@broadcom.com>
Mon, 27 Jul 2026 15:29:24 +0000 (11:29 -0400)
vmw_fence_fifo_down() drops fman->lock to wait on a fence and, on
timeout, mutates fman->fence_list via list_del_init() and signals
the fence without re-acquiring the lock.  __vmw_fences_update() walks
and removes entries from the same list under fman->lock from any
other waiter, the fence-IRQ thread, or vmw_fences_update(), so the
unlocked list_del_init() can corrupt the list head.

Re-take fman->lock before manipulating fence->head and use
dma_fence_signal_locked().  Wrap the locked signalling in
dma_fence_begin_signalling() / dma_fence_end_signalling() so the
lockdep annotation that dma_fence_signal() previously provided is
preserved (the same pattern as __vmw_fences_update()).

dma_fence_put() is moved outside the lock to avoid a recursive
acquire from vmw_fence_obj_destroy(), which also takes fman->lock.

Fixes: ae2a104058e2 ("vmwgfx: Implement fence objects")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-4.7
Signed-off-by: Zack Rusin <zack.rusin@broadcom.com>
Reviewed-by: Ian Forbes <ian.forbes@broadcom.com>
Link: https://patch.msgid.link/20260505222728.519626-5-zack.rusin@broadcom.com
drivers/gpu/drm/vmwgfx/vmwgfx_fence.c

index 4ef84ff9b638c9d190f6d42dbff8e915046b9026..384c6736cf6b153340eb77f74040f101b4595e17 100644 (file)
@@ -367,13 +367,24 @@ void vmw_fence_fifo_down(struct vmw_fence_manager *fman)
                ret = vmw_fence_obj_wait(fence, false, false,
                                         VMW_FENCE_WAIT_TIMEOUT);
 
+               spin_lock(&fman->lock);
                if (unlikely(ret != 0)) {
+                       bool cookie = dma_fence_begin_signalling();
+
                        list_del_init(&fence->head);
-                       dma_fence_signal(&fence->base);
+                       if (fence->waiter_added) {
+                               vmw_seqno_waiter_remove(fman->dev_priv);
+                               fence->waiter_added = false;
+                       }
+                       dma_fence_signal_locked(&fence->base);
+                       dma_fence_end_signalling(cookie);
                }
 
                BUG_ON(!list_empty(&fence->head));
+               spin_unlock(&fman->lock);
+
                dma_fence_put(&fence->base);
+
                spin_lock(&fman->lock);
        }
        spin_unlock(&fman->lock);