From: Tvrtko Ursulin <tursulin@ursulin.net>
To: "Christian König" <christian.koenig@amd.com>,
phasta@mailbox.org, alexdeucher@gmail.com,
simona.vetter@ffwll.ch, matthew.brost@intel.com,
dri-devel@lists.freedesktop.org, amd-gfx@lists.freedesktop.org,
linaro-mm-sig@lists.linaro.org, sumit.semwal@linaro.org
Subject: Re: [PATCH 02/18] dma-buf: protected fence ops by RCU v3
Date: Tue, 18 Nov 2025 16:03:48 +0000 [thread overview]
Message-ID: <ed7595b4-b6e4-4a7f-ad35-e3a3cf063e72@ursulin.net> (raw)
In-Reply-To: <35d7ab6c-bd4d-4267-8ae1-2637d6c0f1ff@amd.com>
On 18/11/2025 14:28, Christian König wrote:
> On 11/14/25 11:50, Tvrtko Ursulin wrote:
>>> @@ -569,12 +577,12 @@ void dma_fence_release(struct kref *kref)
>>> spin_unlock_irqrestore(fence->lock, flags);
>>> }
>>> - rcu_read_unlock();
>>> -
>>> - if (fence->ops->release)
>>> - fence->ops->release(fence);
>>> + ops = rcu_dereference(fence->ops);
>>> + if (ops->release)
>>> + ops->release(fence);
>>> else
>>> dma_fence_free(fence);
>>> + rcu_read_unlock();
>>
>> Risk being a spin lock in the release callback will trigger a warning on PREEMPT_RT. But at least the current code base does not have anything like that AFAICS so I guess it is okay.
>
> I don't think that this is a problem. When PREEMPT_RT is enabled both RCU and spinlocks become preemptible.
>
> So as far as I know it is perfectly valid to grab a spinlock under an rcu read side critical section.
Looking at the source just now, I think it is possible I mixed it up
with preempt_disable()+spin_lock().
>>> diff --git a/include/linux/dma-fence.h b/include/linux/dma-fence.h
>>> index 64639e104110..77f07735f556 100644
>>> --- a/include/linux/dma-fence.h
>>> +++ b/include/linux/dma-fence.h
>>> @@ -66,7 +66,7 @@ struct seq_file;
>>> */
>>> struct dma_fence {
>>> spinlock_t *lock;
>>> - const struct dma_fence_ops *ops;
>>> + const struct dma_fence_ops __rcu *ops;
>>> /*
>>> * We clear the callback list on kref_put so that by the time we
>>> * release the fence it is unused. No one should be adding to the
>>> @@ -218,6 +218,10 @@ struct dma_fence_ops {
>>> * timed out. Can also return other error values on custom implementations,
>>> * which should be treated as if the fence is signaled. For example a hardware
>>> * lockup could be reported like that.
>>> + *
>>> + * Implementing this callback prevents the BO from detaching after
>>
>> s/BO/fence/
>>
>>> + * signaling and so it is mandatory for the module providing the
>>> + * dma_fence_ops to stay loaded as long as the dma_fence exists.
>>> */
>>> signed long (*wait)(struct dma_fence *fence,
>>> bool intr, signed long timeout);
>>> @@ -229,6 +233,13 @@ struct dma_fence_ops {
>>> * Can be called from irq context. This callback is optional. If it is
>>> * NULL, then dma_fence_free() is instead called as the default
>>> * implementation.
>>> + *
>>> + * Implementing this callback prevents the BO from detaching after
>>
>> Ditto.
>
> Both fixed, thanks.
>
>>
>>> + * signaling and so it is mandatory for the module providing the
>>> + * dma_fence_ops to stay loaded as long as the dma_fence exists.
>>> + *
>>> + * If the callback is implemented the memory backing the dma_fence
>>> + * object must be freed RCU safe.
>>> */
>>> void (*release)(struct dma_fence *fence);
>>> @@ -418,13 +429,19 @@ const char __rcu *dma_fence_timeline_name(struct dma_fence *fence);
>>> static inline bool
>>> dma_fence_is_signaled_locked(struct dma_fence *fence)
>>> {
>>> + const struct dma_fence_ops *ops;
>>> +
>>> if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags))
>>> return true;
>>> - if (fence->ops->signaled && fence->ops->signaled(fence)) {
>>> + rcu_read_lock();
>>> + ops = rcu_dereference(fence->ops);
>>> + if (ops->signaled && ops->signaled(fence)) {
>>> + rcu_read_unlock();
>>> dma_fence_signal_locked(fence);
>>> return true;
>>> }
>>> + rcu_read_unlock();
>>> return false;
>>> }
>>> @@ -448,13 +465,19 @@ dma_fence_is_signaled_locked(struct dma_fence *fence)
>>> static inline bool
>>> dma_fence_is_signaled(struct dma_fence *fence)
>>> {
>>> + const struct dma_fence_ops *ops;
>>> +
>>> if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags))
>>> return true;
>>> - if (fence->ops->signaled && fence->ops->signaled(fence)) {
>>> + rcu_read_lock();
>>> + ops = rcu_dereference(fence->ops);
>>> + if (ops->signaled && ops->signaled(fence)) {
>>> + rcu_read_unlock();
>>
>> With the unlocked version two threads could race and one could make the fence->lock go away just around here, before the dma_fence_signal below will take it. It seems it is only safe to rcu_read_unlock before signaling if using the embedded fence (later in the series). Can you think of a downside to holding the rcu read lock to after signaling? that would make it safe I think.
>
> Well it's good to talk about it but I think that it is not necessary to protect the lock in this particular case.
>
> See the RCU protection is only for the fence->ops pointer, but the lock can be taken way after the fence is already signaled.
>
> That's why I came up with the patch to move the lock into the fence in the first place.
Right. And you think there is nothing to gain with the option of keeping
the rcu_read_unlock() to after signalling? Ie. why not plug a potential
race if we can for no negative effect.
Regards,
Tvrtko
>> Regards,
>>
>> Tvrtko
>>
>>> dma_fence_signal(fence);
>>> return true;
>>> }
>>> + rcu_read_unlock();
>>> return false;
>>> }
>>
>
next prev parent reply other threads:[~2025-11-18 16:03 UTC|newest]
Thread overview: 52+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-11-13 14:51 Independence for dma_fences! v3 Christian König
2025-11-13 14:51 ` [PATCH 01/18] dma-buf: cleanup dma_fence_describe v3 Christian König
2025-11-20 14:09 ` Tvrtko Ursulin
2025-11-27 10:17 ` Philipp Stanner
2025-11-13 14:51 ` [PATCH 02/18] dma-buf: protected fence ops by RCU v3 Christian König
2025-11-14 10:50 ` Tvrtko Ursulin
2025-11-18 14:28 ` Christian König
2025-11-18 16:03 ` Tvrtko Ursulin [this message]
2025-11-20 14:03 ` Christian König
2025-11-20 14:08 ` Tvrtko Ursulin
2025-11-13 14:51 ` [PATCH 03/18] dma-buf: detach fence ops on signal v2 Christian König
2025-11-20 14:14 ` Tvrtko Ursulin
2025-11-27 10:29 ` Philipp Stanner
2025-11-13 14:51 ` [PATCH 04/18] dma-buf: inline spinlock for fence protection v2 Christian König
2025-11-13 20:49 ` kernel test robot
2025-11-14 7:30 ` kernel test robot
2025-11-14 11:49 ` Tvrtko Ursulin
2025-11-27 10:44 ` Philipp Stanner
2025-11-13 14:51 ` [PATCH 05/18] dma-buf: use inline lock for the stub fence Christian König
2025-11-27 10:50 ` Philipp Stanner
2025-11-28 12:31 ` Christian König
2025-11-13 14:51 ` [PATCH 06/18] dma-buf: use inline lock for the dma-fence-array Christian König
2025-11-27 10:51 ` Philipp Stanner
2025-11-13 14:51 ` [PATCH 07/18] dma-buf: use inline lock for the dma-fence-chain Christian König
2025-11-27 10:52 ` Philipp Stanner
2025-11-13 14:51 ` [PATCH 08/18] drm/sched: use inline locks for the drm-sched-fence Christian König
2025-11-13 16:23 ` Philipp Stanner
2025-11-17 15:32 ` Christian König
2025-11-18 7:10 ` Philipp Stanner
2025-11-20 14:17 ` Tvrtko Ursulin
2025-11-13 14:51 ` [PATCH 09/18] drm/amdgpu: fix KFD eviction fence enable_signaling path Christian König
2025-11-27 10:57 ` Philipp Stanner
2025-11-28 10:01 ` Christian König
2025-11-13 14:51 ` [PATCH 10/18] drm/amdgpu: independence for the amdgpu_fence! Christian König
2025-11-20 14:42 ` Tvrtko Ursulin
2025-11-13 14:51 ` [PATCH 11/18] drm/amdgpu: independence for the amdgpu_eviction_fence! Christian König
2025-11-27 11:02 ` Philipp Stanner
2025-11-13 14:51 ` [PATCH 12/18] drm/amdgpu: independence for the amdgpu_vm_tlb_fence! Christian König
2025-11-13 14:51 ` [PATCH 13/18] drm/amdgpu: independence for the amdkfd_fence! v2 Christian König
2025-11-14 11:43 ` kernel test robot
2025-11-27 11:10 ` Philipp Stanner
2025-11-28 10:06 ` Christian König
2025-11-28 10:10 ` Philipp Stanner
2025-11-28 10:12 ` Christian König
2025-11-13 14:51 ` [PATCH 14/18] drm/amdgpu: independence for the amdgpu_userq__fence! Christian König
2025-11-13 14:51 ` [PATCH 15/18] drm/xe: Disconnect the low hanging fences from Xe module Christian König
2025-11-13 14:51 ` [PATCH 16/18] drm/xe: Drop HW fence slab Christian König
2025-11-13 14:51 ` [PATCH 17/18] drm/xe: Promote xe_hw_fence_irq to an ref counted object Christian König
2025-11-13 14:51 ` [PATCH 18/18] drm/xe: Finish disconnect HW fences from module Christian König
2025-11-27 11:17 ` Philipp Stanner
2025-11-13 16:20 ` Independence for dma_fences! v3 Philipp Stanner
2025-11-17 15:28 ` Christian König
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=ed7595b4-b6e4-4a7f-ad35-e3a3cf063e72@ursulin.net \
--to=tursulin@ursulin.net \
--cc=alexdeucher@gmail.com \
--cc=amd-gfx@lists.freedesktop.org \
--cc=christian.koenig@amd.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=linaro-mm-sig@lists.linaro.org \
--cc=matthew.brost@intel.com \
--cc=phasta@mailbox.org \
--cc=simona.vetter@ffwll.ch \
--cc=sumit.semwal@linaro.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox