All of lore.kernel.org
 help / color / mirror / Atom feed
From: Boris Brezillon <boris.brezillon@collabora.com>
To: "Christian König" <ckoenig.leichtzumerken@gmail.com>
Cc: phasta@mailbox.org, matthew.brost@intel.com,
	sumit.semwal@linaro.org, dri-devel@lists.freedesktop.org,
	linaro-mm-sig@lists.linaro.org
Subject: Re: [PATCH 1/8] dma-buf: protected fence ops by RCU v5
Date: Fri, 13 Feb 2026 15:20:28 +0100	[thread overview]
Message-ID: <20260213152028.52e15600@fedora> (raw)
In-Reply-To: <20260210102232.1642-2-christian.koenig@amd.com>

On Tue, 10 Feb 2026 11:01:56 +0100
"Christian König" <ckoenig.leichtzumerken@gmail.com> wrote:

> At first glance it is counter intuitive to protect a constant function
> pointer table by RCU, but this allows modules providing the function
> table to unload by waiting for an RCU grace period.
> 
> v2: make one the now duplicated lockdep warnings a comment instead.
> v3: Add more documentation to ->wait and ->release callback.
> v4: fix typo in documentation
> v5: rebased on drm-tip
> 
> Signed-off-by: Christian König <christian.koenig@amd.com>

Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>

> ---
>  drivers/dma-buf/dma-fence.c | 69 +++++++++++++++++++++++++------------
>  include/linux/dma-fence.h   | 29 ++++++++++++++--
>  2 files changed, 73 insertions(+), 25 deletions(-)
> 
> diff --git a/drivers/dma-buf/dma-fence.c b/drivers/dma-buf/dma-fence.c
> index e05beae6e407..de9bf18be3d4 100644
> --- a/drivers/dma-buf/dma-fence.c
> +++ b/drivers/dma-buf/dma-fence.c
> @@ -522,6 +522,7 @@ EXPORT_SYMBOL(dma_fence_signal);
>  signed long
>  dma_fence_wait_timeout(struct dma_fence *fence, bool intr, signed long timeout)
>  {
> +	const struct dma_fence_ops *ops;
>  	signed long ret;
>  
>  	if (WARN_ON(timeout < 0))
> @@ -533,15 +534,21 @@ dma_fence_wait_timeout(struct dma_fence *fence, bool intr, signed long timeout)
>  
>  	dma_fence_enable_sw_signaling(fence);
>  
> -	if (trace_dma_fence_wait_start_enabled()) {
> -		rcu_read_lock();
> -		trace_dma_fence_wait_start(fence);
> +	rcu_read_lock();
> +	ops = rcu_dereference(fence->ops);
> +	trace_dma_fence_wait_start(fence);
> +	if (ops->wait) {
> +		/*
> +		 * Implementing the wait ops is deprecated and not supported for
> +		 * issuer independent fences, so it is ok to use the ops outside
> +		 * the RCU protected section.
> +		 */
> +		rcu_read_unlock();
> +		ret = ops->wait(fence, intr, timeout);
> +	} else {
>  		rcu_read_unlock();
> -	}
> -	if (fence->ops->wait)
> -		ret = fence->ops->wait(fence, intr, timeout);
> -	else
>  		ret = dma_fence_default_wait(fence, intr, timeout);
> +	}
>  	if (trace_dma_fence_wait_end_enabled()) {
>  		rcu_read_lock();
>  		trace_dma_fence_wait_end(fence);
> @@ -562,6 +569,7 @@ void dma_fence_release(struct kref *kref)
>  {
>  	struct dma_fence *fence =
>  		container_of(kref, struct dma_fence, refcount);
> +	const struct dma_fence_ops *ops;
>  
>  	rcu_read_lock();
>  	trace_dma_fence_destroy(fence);
> @@ -593,12 +601,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();
>  }
>  EXPORT_SYMBOL(dma_fence_release);
>  
> @@ -617,6 +625,7 @@ EXPORT_SYMBOL(dma_fence_free);
>  
>  static bool __dma_fence_enable_signaling(struct dma_fence *fence)
>  {
> +	const struct dma_fence_ops *ops;
>  	bool was_set;
>  
>  	lockdep_assert_held(fence->lock);
> @@ -627,14 +636,18 @@ static bool __dma_fence_enable_signaling(struct dma_fence *fence)
>  	if (dma_fence_test_signaled_flag(fence))
>  		return false;
>  
> -	if (!was_set && fence->ops->enable_signaling) {
> +	rcu_read_lock();
> +	ops = rcu_dereference(fence->ops);
> +	if (!was_set && ops->enable_signaling) {
>  		trace_dma_fence_enable_signal(fence);
>  
> -		if (!fence->ops->enable_signaling(fence)) {
> +		if (!ops->enable_signaling(fence)) {
> +			rcu_read_unlock();
>  			dma_fence_signal_locked(fence);
>  			return false;
>  		}
>  	}
> +	rcu_read_unlock();
>  
>  	return true;
>  }
> @@ -1007,8 +1020,13 @@ EXPORT_SYMBOL(dma_fence_wait_any_timeout);
>   */
>  void dma_fence_set_deadline(struct dma_fence *fence, ktime_t deadline)
>  {
> -	if (fence->ops->set_deadline && !dma_fence_is_signaled(fence))
> -		fence->ops->set_deadline(fence, deadline);
> +	const struct dma_fence_ops *ops;
> +
> +	rcu_read_lock();
> +	ops = rcu_dereference(fence->ops);
> +	if (ops->set_deadline && !dma_fence_is_signaled(fence))
> +		ops->set_deadline(fence, deadline);
> +	rcu_read_unlock();
>  }
>  EXPORT_SYMBOL(dma_fence_set_deadline);
>  
> @@ -1049,7 +1067,12 @@ __dma_fence_init(struct dma_fence *fence, const struct dma_fence_ops *ops,
>  	BUG_ON(!ops || !ops->get_driver_name || !ops->get_timeline_name);
>  
>  	kref_init(&fence->refcount);
> -	fence->ops = ops;
> +	/*
> +	 * At first glance it is counter intuitive to protect a constant
> +	 * function pointer table by RCU, but this allows modules providing the
> +	 * function table to unload by waiting for an RCU grace period.
> +	 */
> +	RCU_INIT_POINTER(fence->ops, ops);
>  	INIT_LIST_HEAD(&fence->cb_list);
>  	fence->lock = lock;
>  	fence->context = context;
> @@ -1129,11 +1152,12 @@ EXPORT_SYMBOL(dma_fence_init64);
>   */
>  const char __rcu *dma_fence_driver_name(struct dma_fence *fence)
>  {
> -	RCU_LOCKDEP_WARN(!rcu_read_lock_held(),
> -			 "RCU protection is required for safe access to returned string");
> +	const struct dma_fence_ops *ops;
>  
> +	/* RCU protection is required for safe access to returned string */
> +	ops = rcu_dereference(fence->ops);
>  	if (!dma_fence_test_signaled_flag(fence))
> -		return (const char __rcu *)fence->ops->get_driver_name(fence);
> +		return (const char __rcu *)ops->get_driver_name(fence);
>  	else
>  		return (const char __rcu *)"detached-driver";
>  }
> @@ -1161,11 +1185,12 @@ EXPORT_SYMBOL(dma_fence_driver_name);
>   */
>  const char __rcu *dma_fence_timeline_name(struct dma_fence *fence)
>  {
> -	RCU_LOCKDEP_WARN(!rcu_read_lock_held(),
> -			 "RCU protection is required for safe access to returned string");
> +	const struct dma_fence_ops *ops;
>  
> +	/* RCU protection is required for safe access to returned string */
> +	ops = rcu_dereference(fence->ops);
>  	if (!dma_fence_test_signaled_flag(fence))
> -		return (const char __rcu *)fence->ops->get_driver_name(fence);
> +		return (const char __rcu *)ops->get_driver_name(fence);
>  	else
>  		return (const char __rcu *)"signaled-timeline";
>  }
> diff --git a/include/linux/dma-fence.h b/include/linux/dma-fence.h
> index 9c4d25289239..6bf4feb0e01f 100644
> --- a/include/linux/dma-fence.h
> +++ b/include/linux/dma-fence.h
> @@ -67,7 +67,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
> @@ -220,6 +220,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 fence from detaching after
> +	 * 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);
> @@ -231,6 +235,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 fence from detaching after
> +	 * 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);
>  
> @@ -454,13 +465,19 @@ dma_fence_test_signaled_flag(struct dma_fence *fence)
>  static inline bool
>  dma_fence_is_signaled_locked(struct dma_fence *fence)
>  {
> +	const struct dma_fence_ops *ops;
> +
>  	if (dma_fence_test_signaled_flag(fence))
>  		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;
>  }
> @@ -484,13 +501,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 (dma_fence_test_signaled_flag(fence))
>  		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(fence);
>  		return true;
>  	}
> +	rcu_read_unlock();
>  
>  	return false;
>  }


  parent reply	other threads:[~2026-02-13 14:20 UTC|newest]

Thread overview: 33+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-02-10 10:01 Independence for dma_fences! v7 Christian König
2026-02-10 10:01 ` [PATCH 1/8] dma-buf: protected fence ops by RCU v5 Christian König
2026-02-11 10:06   ` Philipp Stanner
2026-02-11 15:43     ` Christian König
2026-02-12  8:56       ` Philipp Stanner
2026-02-19 10:23         ` Christian König
2026-02-19 10:35           ` Philipp Stanner
2026-02-19 12:49             ` Christian König
2026-02-12  9:03       ` Tvrtko Ursulin
2026-02-12  9:31   ` Tvrtko Ursulin
2026-02-13 14:20   ` Boris Brezillon [this message]
2026-02-10 10:01 ` [PATCH 2/8] dma-buf: detach fence ops on signal v2 Christian König
2026-02-13 14:22   ` Boris Brezillon
2026-02-19 12:52     ` Christian König
2026-02-19 15:49       ` Boris Brezillon
2026-02-10 10:01 ` [PATCH 3/8] dma-buf: abstract fence locking v2 Christian König
2026-02-12  9:07   ` Tvrtko Ursulin
2026-02-10 10:01 ` [PATCH 4/8] dma-buf: inline spinlock for fence protection v4 Christian König
2026-02-11  9:50   ` Philipp Stanner
2026-02-11 14:59     ` Christian König
2026-02-12  9:01       ` Philipp Stanner
2026-02-12  9:16   ` Tvrtko Ursulin
2026-02-13 14:27   ` Boris Brezillon
2026-02-15  8:48     ` Boris Brezillon
2026-02-16  7:33     ` Philipp Stanner
2026-02-16  9:48       ` Boris Brezillon
2026-02-10 10:02 ` [PATCH 5/8] dma-buf/selftests: test RCU ops and inline lock v2 Christian König
2026-02-10 10:02 ` [PATCH 6/8] dma-buf: use inline lock for the stub fence v2 Christian König
2026-02-13 14:32   ` Boris Brezillon
2026-02-10 10:02 ` [PATCH 7/8] dma-buf: use inline lock for the dma-fence-array Christian König
2026-02-13 14:33   ` Boris Brezillon
2026-02-10 10:02 ` [PATCH 8/8] dma-buf: use inline lock for the dma-fence-chain Christian König
2026-02-13 14:33   ` Boris Brezillon

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=20260213152028.52e15600@fedora \
    --to=boris.brezillon@collabora.com \
    --cc=ckoenig.leichtzumerken@gmail.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=linaro-mm-sig@lists.linaro.org \
    --cc=matthew.brost@intel.com \
    --cc=phasta@mailbox.org \
    --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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.