drm/vmwgfx: take fman->lock around fence list mutation in fifo_down

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: ae2a104058 ("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
This commit is contained in:
Zack Rusin 2026-05-05 18:22:25 -04:00
parent f47d542d59
commit 250af2e8c3

View 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);