[PATCH 2/2] dma-buf: add warning when dma_fence is signaled from IOCTL
Christian König
christian.koenig at amd.com
Wed Aug 13 09:18:43 UTC 2025
On 13.08.25 10:16, Philipp Stanner wrote:
> On Tue, 2025-08-12 at 16:34 +0200, Christian König wrote:
>> From: Christian König <ckoenig at able.fritz.box>
>
> Is this the correct mail addr? :)
^^ No it isn't and how the heck did that happen?
Looks like my gitconfig is somehow changed, but I have no idea why.
>>
>> We have the re-occurring problem that people try to invent a
>> DMA-fences implementation which signals fences based on an userspace
>> IOCTL.
>>
>> This is well known as source of hard to track down crashes and is
>> documented to be an invalid approach. The problem is that it seems
>> to work during initial testing and only long term tests points out
>> why this can never work correctly.
>>
>> So give at least a warning when people try to signal a fence from
>> task context and not from interrupts or a work item. This check is
>> certainly not perfect but better than nothing.
>>
>> Signed-off-by: Christian König <ckoenig at able.fritz.box>
>> ---
>> drivers/dma-buf/dma-fence.c | 59 +++++++++++++++++++++++++++----------
>> include/linux/dma-fence.h | 9 ++++--
>> 2 files changed, 51 insertions(+), 17 deletions(-)
>>
>> diff --git a/drivers/dma-buf/dma-fence.c b/drivers/dma-buf/dma-fence.c
>> index 3f78c56b58dc..2bce620eacac 100644
>> --- a/drivers/dma-buf/dma-fence.c
>> +++ b/drivers/dma-buf/dma-fence.c
>> @@ -345,33 +345,23 @@ void __dma_fence_might_wait(void)
>> }
>> #endif
>>
>> -
>> /**
>> - * dma_fence_signal_timestamp_locked - signal completion of a fence
>> + * dma_fence_signal_internal - internal signal completion of a fence
>> * @fence: the fence to signal
>> * @timestamp: fence signal timestamp in kernel's CLOCK_MONOTONIC time domain
>> *
>> - * Signal completion for software callbacks on a fence, this will unblock
>> - * dma_fence_wait() calls and run all the callbacks added with
>> - * dma_fence_add_callback(). Can be called multiple times, but since a fence
>> - * can only go from the unsignaled to the signaled state and not back, it will
>> - * only be effective the first time. Set the timestamp provided as the fence
>> - * signal timestamp.
>> - *
>> - * Unlike dma_fence_signal_timestamp(), this function must be called with
>> - * &dma_fence.lock held.
>> + * Internal signal the dma_fence without error checking. Should *NEVER* be used
>> + * by drivers or external code directly.
>
> s/Internal/Internally
>
>> *
>> * Returns 0 on success and a negative error value when @fence has been
>> * signalled already.
>> */
>> -int dma_fence_signal_timestamp_locked(struct dma_fence *fence,
>> - ktime_t timestamp)
>> +int dma_fence_signal_internal(struct dma_fence *fence, ktime_t timestamp)
>> {
>> struct dma_fence_cb *cur, *tmp;
>> struct list_head cb_list;
>>
>> lockdep_assert_held(fence->lock);
>> -
>> if (unlikely(test_and_set_bit(DMA_FENCE_FLAG_SIGNALED_BIT,
>> &fence->flags)))
>> return -EINVAL;
>> @@ -390,7 +380,46 @@ int dma_fence_signal_timestamp_locked(struct dma_fence *fence,
>>
>> return 0;
>> }
>> -EXPORT_SYMBOL(dma_fence_signal_timestamp_locked);
>> +EXPORT_SYMBOL(dma_fence_signal_internal);
>
> If it must only be used internally, can it be kept private, without
> exporting the symbol?
I have gone back and force about that as well.
We would then need to uninline dma_fence_is_signaled().
>> +
>> +/**
>> + * dma_fence_signal_timestamp_locked - signal completion of a fence
>> + * @fence: the fence to signal
>> + * @timestamp: fence signal timestamp in kernel's CLOCK_MONOTONIC time domain
>> + *
>> + * Signal completion for software callbacks on a fence, this will unblock
>> + * dma_fence_wait() calls and run all the callbacks added with
>> + * dma_fence_add_callback(). Can be called multiple times, but since a fence
>> + * can only go from the unsignaled to the signaled state and not back, it will
>> + * only be effective the first time. Set the timestamp provided as the fence
>> + * signal timestamp.
>> + *
>> + * Unlike dma_fence_signal_timestamp(), this function must be called with
>> + * &dma_fence.lock held.
>> + *
>> + * Returns 0 on success and a negative error value when @fence has been
>> + * signalled already.
>> + */
>> +int dma_fence_signal_timestamp_locked(struct dma_fence *fence,
>> + ktime_t timestamp)
>> +{
>> + /*
>> + * We have the re-occurring problem that people try to invent a
>> + * DMA-fences implementation which signals fences based on an userspace
>> + * IOCTL.
>> + *
>> + * This is well known as source of hard to track down crashes and is
>> + * documented to be an invalid approach. The problem is that it seems
>> + * to work during initial testing and only long term tests points out
>> + * why this can never work correctly.
>> + *
>> + * So give at least a warning when people try to signal a fence from
>> + * task context and not from interrupts or a work item. This check is
>> + * certainly not perfect but better than nothing.
>> + */
>> + WARN_ON_ONCE(!in_interrupt() && !current_work());
>> + return dma_fence_signal_internal(fence, timestamp);
>> +}
>
> So this now is the point to decide what we want: do you want to *allow*
> drivers to do it, or want to *prohibit* it?
>
> If you want to prohibit it, then (additionally) returning an error code
> here would make sense.
I'm actually trying to remove the return value for quite a while now.
IIRC nobody is actually using it any more since it doesn't really signal an error condition.
Thanks,
Christian.
>
>
> P.
>
>>
>> /**
>> * dma_fence_signal_timestamp - signal completion of a fence
>> diff --git a/include/linux/dma-fence.h b/include/linux/dma-fence.h
>> index 64639e104110..8dbcd66989b8 100644
>> --- a/include/linux/dma-fence.h
>> +++ b/include/linux/dma-fence.h
>> @@ -369,6 +369,7 @@ int dma_fence_signal_locked(struct dma_fence *fence);
>> int dma_fence_signal_timestamp(struct dma_fence *fence, ktime_t timestamp);
>> int dma_fence_signal_timestamp_locked(struct dma_fence *fence,
>> ktime_t timestamp);
>> +int dma_fence_signal_internal(struct dma_fence *fence, ktime_t timestamp);
>> signed long dma_fence_default_wait(struct dma_fence *fence,
>> bool intr, signed long timeout);
>> int dma_fence_add_callback(struct dma_fence *fence,
>> @@ -422,7 +423,7 @@ dma_fence_is_signaled_locked(struct dma_fence *fence)
>> return true;
>>
>> if (fence->ops->signaled && fence->ops->signaled(fence)) {
>> - dma_fence_signal_locked(fence);
>> + dma_fence_signal_internal(fence, ktime_get());
>> return true;
>> }
>>
>> @@ -448,11 +449,15 @@ dma_fence_is_signaled_locked(struct dma_fence *fence)
>> static inline bool
>> dma_fence_is_signaled(struct dma_fence *fence)
>> {
>> + unsigned long flags;
>> +
>> if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags))
>> return true;
>>
>> if (fence->ops->signaled && fence->ops->signaled(fence)) {
>> - dma_fence_signal(fence);
>> + spin_lock_irqsave(fence->lock, flags);
>> + dma_fence_signal_internal(fence, ktime_get());
>> + spin_unlock_irqrestore(fence->lock, flags);
>> return true;
>> }
>>
>
More information about the dri-devel
mailing list