Commit 78ac1c35 authored by Christian König's avatar Christian König
Browse files

dma-buf: fix dma_fence_array_signaled v4



The function silently assumed that signaling was already enabled for the
dma_fence_array. This meant that without enabling signaling first we would
never see forward progress.

Fix that by falling back to testing each individual fence when signaling
isn't enabled yet.

v2: add the comment suggested by Boris why this is done this way
v3: fix the underflow pointed out by Tvrtko
v4: atomic_read_acquire() as suggested by Tvrtko

Signed-off-by: default avatarChristian König <christian.koenig@amd.com>
Reviewed-by: default avatarBoris Brezillon <boris.brezillon@collabora.com>
Tested-by: default avatarChia-I Wu <olvaffe@gmail.com>
Reviewed-by: default avatarTvrtko Ursulin <tvrtko.ursulin@igalia.com>
Closes: https://gitlab.freedesktop.org/mesa/mesa/-/issues/12094
Cc: <stable@vger.kernel.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20241112121925.18464-1-christian.koenig@amd.com
parent fe52c649
Loading
Loading
Loading
Loading
+27 −1
Original line number Diff line number Diff line
@@ -103,10 +103,36 @@ static bool dma_fence_array_enable_signaling(struct dma_fence *fence)
static bool dma_fence_array_signaled(struct dma_fence *fence)
{
	struct dma_fence_array *array = to_dma_fence_array(fence);
	int num_pending;
	unsigned int i;

	if (atomic_read(&array->num_pending) > 0)
	/*
	 * We need to read num_pending before checking the enable_signal bit
	 * to avoid racing with the enable_signaling() implementation, which
	 * might decrement the counter, and cause a partial check.
	 * atomic_read_acquire() pairs with atomic_dec_and_test() in
	 * dma_fence_array_enable_signaling()
	 *
	 * The !--num_pending check is here to account for the any_signaled case
	 * if we race with enable_signaling(), that means the !num_pending check
	 * in the is_signalling_enabled branch might be outdated (num_pending
	 * might have been decremented), but that's fine. The user will get the
	 * right value when testing again later.
	 */
	num_pending = atomic_read_acquire(&array->num_pending);
	if (test_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT, &array->base.flags)) {
		if (num_pending <= 0)
			goto signal;
		return false;
	}

	for (i = 0; i < array->num_fences; ++i) {
		if (dma_fence_is_signaled(array->fences[i]) && !--num_pending)
			goto signal;
	}
	return false;

signal:
	dma_fence_array_clear_pending_error(array);
	return true;
}