diff options
Diffstat (limited to 'drivers/dma-buf/dma-fence-array.c')
| -rw-r--r-- | drivers/dma-buf/dma-fence-array.c | 28 | 
1 files changed, 27 insertions, 1 deletions
| diff --git a/drivers/dma-buf/dma-fence-array.c b/drivers/dma-buf/dma-fence-array.c index 8a08ffde31e7..6657d4b30af9 100644 --- a/drivers/dma-buf/dma-fence-array.c +++ b/drivers/dma-buf/dma-fence-array.c @@ -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;  } | 
