dma-buf: detach fence ops on signal v3

When neither a release nor a wait backend ops is specified it is possible
to let the dma_fence live on independently of the module who issued it.

This makes it possible to unload drivers and only wait for all their
fences to signal.

v2: fix typo in comment
v3: fix sparse rcu warnings

Signed-off-by: Christian König <christian.koenig@amd.com>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@igalia.com>
Reviewed-by: Philipp Stanner <phasta@kernel.org>
Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
Link: https://lore.kernel.org/r/20260219160822.1529-3-christian.koenig@amd.com
This commit is contained in:
Christian König
2025-10-08 18:12:46 +02:00
parent f4cc3ab824
commit 541c8f2468
2 changed files with 16 additions and 6 deletions

View File

@@ -362,6 +362,7 @@ void __dma_fence_might_wait(void)
void dma_fence_signal_timestamp_locked(struct dma_fence *fence,
ktime_t timestamp)
{
const struct dma_fence_ops *ops;
struct dma_fence_cb *cur, *tmp;
struct list_head cb_list;
@@ -371,6 +372,15 @@ void dma_fence_signal_timestamp_locked(struct dma_fence *fence,
&fence->flags)))
return;
/*
* When neither a release nor a wait operation is specified set the ops
* pointer to NULL to allow the fence structure to become independent
* from who originally issued it.
*/
ops = rcu_dereference_protected(fence->ops, true);
if (!ops->release && !ops->wait)
RCU_INIT_POINTER(fence->ops, NULL);
/* Stash the cb_list before replacing it with the timestamp */
list_replace(&fence->cb_list, &cb_list);
@@ -537,7 +547,7 @@ dma_fence_wait_timeout(struct dma_fence *fence, bool intr, signed long timeout)
rcu_read_lock();
ops = rcu_dereference(fence->ops);
trace_dma_fence_wait_start(fence);
if (ops->wait) {
if (ops && ops->wait) {
/*
* Implementing the wait ops is deprecated and not supported for
* issuers of fences who need their lifetime to be independent
@@ -603,7 +613,7 @@ void dma_fence_release(struct kref *kref)
}
ops = rcu_dereference(fence->ops);
if (ops->release)
if (ops && ops->release)
ops->release(fence);
else
dma_fence_free(fence);
@@ -639,7 +649,7 @@ static bool __dma_fence_enable_signaling(struct dma_fence *fence)
rcu_read_lock();
ops = rcu_dereference(fence->ops);
if (!was_set && ops->enable_signaling) {
if (!was_set && ops && ops->enable_signaling) {
trace_dma_fence_enable_signal(fence);
if (!ops->enable_signaling(fence)) {
@@ -1025,7 +1035,7 @@ void dma_fence_set_deadline(struct dma_fence *fence, ktime_t deadline)
rcu_read_lock();
ops = rcu_dereference(fence->ops);
if (ops->set_deadline && !dma_fence_is_signaled(fence))
if (ops && ops->set_deadline && !dma_fence_is_signaled(fence))
ops->set_deadline(fence, deadline);
rcu_read_unlock();
}

View File

@@ -472,7 +472,7 @@ dma_fence_is_signaled_locked(struct dma_fence *fence)
rcu_read_lock();
ops = rcu_dereference(fence->ops);
if (ops->signaled && ops->signaled(fence)) {
if (ops && ops->signaled && ops->signaled(fence)) {
rcu_read_unlock();
dma_fence_signal_locked(fence);
return true;
@@ -508,7 +508,7 @@ dma_fence_is_signaled(struct dma_fence *fence)
rcu_read_lock();
ops = rcu_dereference(fence->ops);
if (ops->signaled && ops->signaled(fence)) {
if (ops && ops->signaled && ops->signaled(fence)) {
rcu_read_unlock();
dma_fence_signal(fence);
return true;