Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Christian König <christian.koenig@amd.com>
Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
Tested-by: Chia-I Wu <olvaffe@gmail.com>
Reviewed-by: Tvrtko 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

+27 -1
+27 -1
drivers/dma-buf/dma-fence-array.c
··· 103 103 static bool dma_fence_array_signaled(struct dma_fence *fence) 104 104 { 105 105 struct dma_fence_array *array = to_dma_fence_array(fence); 106 + int num_pending; 107 + unsigned int i; 106 108 107 - if (atomic_read(&array->num_pending) > 0) 109 + /* 110 + * We need to read num_pending before checking the enable_signal bit 111 + * to avoid racing with the enable_signaling() implementation, which 112 + * might decrement the counter, and cause a partial check. 113 + * atomic_read_acquire() pairs with atomic_dec_and_test() in 114 + * dma_fence_array_enable_signaling() 115 + * 116 + * The !--num_pending check is here to account for the any_signaled case 117 + * if we race with enable_signaling(), that means the !num_pending check 118 + * in the is_signalling_enabled branch might be outdated (num_pending 119 + * might have been decremented), but that's fine. The user will get the 120 + * right value when testing again later. 121 + */ 122 + num_pending = atomic_read_acquire(&array->num_pending); 123 + if (test_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT, &array->base.flags)) { 124 + if (num_pending <= 0) 125 + goto signal; 108 126 return false; 127 + } 109 128 129 + for (i = 0; i < array->num_fences; ++i) { 130 + if (dma_fence_is_signaled(array->fences[i]) && !--num_pending) 131 + goto signal; 132 + } 133 + return false; 134 + 135 + signal: 110 136 dma_fence_array_clear_pending_error(array); 111 137 return true; 112 138 }