* [PATCH 1/8] dma-buf: protected fence ops by RCU v7
[not found] <20260219160822.1529-1-christian.koenig@amd.com>
@ 2026-02-19 16:07 ` Christian König
2026-02-21 14:15 ` kernel test robot
2026-02-21 14:26 ` kernel test robot
2026-02-19 16:07 ` [PATCH 2/8] dma-buf: detach fence ops on signal v2 Christian König
` (6 subsequent siblings)
7 siblings, 2 replies; 11+ messages in thread
From: Christian König @ 2026-02-19 16:07 UTC (permalink / raw)
To: phasta, matthew.brost, sumit.semwal; +Cc: dri-devel, linaro-mm-sig
The fence ops of a dma_fence currently need to life as long as the
dma_fence is alive. This means that the module which originally issued
a dma_fence can't unload unless all fences are freed up.
As first step to solve this issue protect the fence ops by RCU.
While it is counter intuitive to protect a constant function pointer table
by RCU it allows modules to wait for an RCU grace period before they
unload, to make sure that nobody is executing their functions any more.
This patch has not much functional change, but only adds the RCU
handling for the static checker to test.
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
v6: improve code comments
v7: improve commit message and code comments
Signed-off-by: Christian König <christian.koenig@amd.com>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@igalia.com>
Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
---
drivers/dma-buf/dma-fence.c | 71 +++++++++++++++++++++++++------------
include/linux/dma-fence.h | 29 +++++++++++++--
2 files changed, 75 insertions(+), 25 deletions(-)
diff --git a/drivers/dma-buf/dma-fence.c b/drivers/dma-buf/dma-fence.c
index e05beae6e407..d3c4e23bf297 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,22 @@ 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
+ * issuers of fences who need their lifetime to be independent
+ * of their module after they signal, 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 +570,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 +602,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 +626,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 +637,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 +1021,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 +1068,13 @@ __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;
+ /*
+ * While it is counter intuitive to protect a constant function pointer
+ * table by RCU it allows modules to wait for an RCU grace period
+ * before they unload, to make sure that nobody is executing their
+ * functions any more.
+ */
+ RCU_INIT_POINTER(fence->ops, ops);
INIT_LIST_HEAD(&fence->cb_list);
fence->lock = lock;
fence->context = context;
@@ -1129,11 +1154,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 +1187,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..9d8a4ebe8bf7 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 necessary 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 necessary 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;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 11+ messages in thread* Re: [PATCH 1/8] dma-buf: protected fence ops by RCU v7
2026-02-19 16:07 ` [PATCH 1/8] dma-buf: protected fence ops by RCU v7 Christian König
@ 2026-02-21 14:15 ` kernel test robot
2026-02-21 14:26 ` kernel test robot
1 sibling, 0 replies; 11+ messages in thread
From: kernel test robot @ 2026-02-21 14:15 UTC (permalink / raw)
To: Christian König, phasta, matthew.brost, sumit.semwal
Cc: oe-kbuild-all, dri-devel, linaro-mm-sig
Hi Christian,
kernel test robot noticed the following build warnings:
[auto build test WARNING on drm-misc/drm-misc-next]
[cannot apply to drm-i915/for-linux-next drm-i915/for-linux-next-fixes drm-xe/drm-xe-next linus/master v6.19 next-20260220]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Christian-K-nig/dma-buf-detach-fence-ops-on-signal-v2/20260220-010804
base: https://gitlab.freedesktop.org/drm/misc/kernel.git drm-misc-next
patch link: https://lore.kernel.org/r/20260219160822.1529-2-christian.koenig%40amd.com
patch subject: [PATCH 1/8] dma-buf: protected fence ops by RCU v7
config: hexagon-randconfig-r121-20260221 (https://download.01.org/0day-ci/archive/20260221/202602212248.xPSr8tt8-lkp@intel.com/config)
compiler: clang version 23.0.0git (https://github.com/llvm/llvm-project e86750b29fa0ff207cd43213d66dabe565417638)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260221/202602212248.xPSr8tt8-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202602212248.xPSr8tt8-lkp@intel.com/
sparse warnings: (new ones prefixed by >>)
drivers/dma-buf/dma-fence-array.c: note: in included file (through include/linux/dma-fence-array.h):
>> include/linux/dma-fence.h:721:27: sparse: sparse: incompatible types in comparison expression (different address spaces):
include/linux/dma-fence.h:721:27: sparse: struct dma_fence_ops const [noderef] __rcu *
include/linux/dma-fence.h:721:27: sparse: struct dma_fence_ops const *
>> include/linux/dma-fence.h:721:27: sparse: sparse: incompatible types in comparison expression (different address spaces):
include/linux/dma-fence.h:721:27: sparse: struct dma_fence_ops const [noderef] __rcu *
include/linux/dma-fence.h:721:27: sparse: struct dma_fence_ops const *
>> include/linux/dma-fence.h:721:27: sparse: sparse: incompatible types in comparison expression (different address spaces):
include/linux/dma-fence.h:721:27: sparse: struct dma_fence_ops const [noderef] __rcu *
include/linux/dma-fence.h:721:27: sparse: struct dma_fence_ops const *
>> include/linux/dma-fence.h:721:27: sparse: sparse: incompatible types in comparison expression (different address spaces):
include/linux/dma-fence.h:721:27: sparse: struct dma_fence_ops const [noderef] __rcu *
include/linux/dma-fence.h:721:27: sparse: struct dma_fence_ops const *
>> include/linux/dma-fence.h:721:27: sparse: sparse: incompatible types in comparison expression (different address spaces):
include/linux/dma-fence.h:721:27: sparse: struct dma_fence_ops const [noderef] __rcu *
include/linux/dma-fence.h:721:27: sparse: struct dma_fence_ops const *
include/linux/dma-fence.h:732:27: sparse: sparse: incompatible types in comparison expression (different address spaces):
include/linux/dma-fence.h:732:27: sparse: struct dma_fence_ops const [noderef] __rcu *
include/linux/dma-fence.h:732:27: sparse: struct dma_fence_ops const *
>> include/linux/dma-fence.h:721:27: sparse: sparse: incompatible types in comparison expression (different address spaces):
include/linux/dma-fence.h:721:27: sparse: struct dma_fence_ops const [noderef] __rcu *
include/linux/dma-fence.h:721:27: sparse: struct dma_fence_ops const *
>> include/linux/dma-fence.h:721:27: sparse: sparse: incompatible types in comparison expression (different address spaces):
include/linux/dma-fence.h:721:27: sparse: struct dma_fence_ops const [noderef] __rcu *
include/linux/dma-fence.h:721:27: sparse: struct dma_fence_ops const *
>> include/linux/dma-fence.h:721:27: sparse: sparse: incompatible types in comparison expression (different address spaces):
include/linux/dma-fence.h:721:27: sparse: struct dma_fence_ops const [noderef] __rcu *
include/linux/dma-fence.h:721:27: sparse: struct dma_fence_ops const *
>> include/linux/dma-fence.h:721:27: sparse: sparse: incompatible types in comparison expression (different address spaces):
include/linux/dma-fence.h:721:27: sparse: struct dma_fence_ops const [noderef] __rcu *
include/linux/dma-fence.h:721:27: sparse: struct dma_fence_ops const *
--
drivers/dma-buf/dma-resv.c: note: in included file (through include/linux/dma-resv.h):
>> include/linux/dma-fence.h:721:27: sparse: sparse: incompatible types in comparison expression (different address spaces):
include/linux/dma-fence.h:721:27: sparse: struct dma_fence_ops const [noderef] __rcu *
include/linux/dma-fence.h:721:27: sparse: struct dma_fence_ops const *
include/linux/dma-fence.h:732:27: sparse: sparse: incompatible types in comparison expression (different address spaces):
include/linux/dma-fence.h:732:27: sparse: struct dma_fence_ops const [noderef] __rcu *
include/linux/dma-fence.h:732:27: sparse: struct dma_fence_ops const *
--
drivers/dma-buf/dma-fence.c:1043:38: sparse: sparse: incorrect type in initializer (different address spaces) @@ expected char const [noderef] __rcu *timeline @@ got char * @@
drivers/dma-buf/dma-fence.c:1043:38: sparse: expected char const [noderef] __rcu *timeline
drivers/dma-buf/dma-fence.c:1043:38: sparse: got char *
drivers/dma-buf/dma-fence.c:1044:36: sparse: sparse: incorrect type in initializer (different address spaces) @@ expected char const [noderef] __rcu *driver @@ got char * @@
drivers/dma-buf/dma-fence.c:1044:36: sparse: expected char const [noderef] __rcu *driver
drivers/dma-buf/dma-fence.c:1044:36: sparse: got char *
drivers/dma-buf/dma-fence.c: note: in included file (through include/trace/trace_events.h, include/trace/define_trace.h, include/trace/events/dma_fence.h):
>> include/trace/events/dma_fence.h:17:1: sparse: sparse: dereference of noderef expression
>> include/trace/events/dma_fence.h:17:1: sparse: sparse: dereference of noderef expression
>> include/trace/events/dma_fence.h:17:1: sparse: sparse: dereference of noderef expression
>> include/trace/events/dma_fence.h:17:1: sparse: sparse: dereference of noderef expression
>> include/trace/events/dma_fence.h:17:1: sparse: sparse: dereference of noderef expression
>> include/trace/events/dma_fence.h:17:1: sparse: sparse: dereference of noderef expression
vim +721 include/linux/dma-fence.h
976b6d97c62347 Christian König 2022-01-19 712
976b6d97c62347 Christian König 2022-01-19 713 /**
976b6d97c62347 Christian König 2022-01-19 714 * dma_fence_is_array - check if a fence is from the array subclass
976b6d97c62347 Christian König 2022-01-19 715 * @fence: the fence to test
976b6d97c62347 Christian König 2022-01-19 716 *
976b6d97c62347 Christian König 2022-01-19 717 * Return true if it is a dma_fence_array and false otherwise.
976b6d97c62347 Christian König 2022-01-19 718 */
976b6d97c62347 Christian König 2022-01-19 719 static inline bool dma_fence_is_array(struct dma_fence *fence)
976b6d97c62347 Christian König 2022-01-19 720 {
976b6d97c62347 Christian König 2022-01-19 @721 return fence->ops == &dma_fence_array_ops;
976b6d97c62347 Christian König 2022-01-19 722 }
976b6d97c62347 Christian König 2022-01-19 723
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 11+ messages in thread* Re: [PATCH 1/8] dma-buf: protected fence ops by RCU v7
2026-02-19 16:07 ` [PATCH 1/8] dma-buf: protected fence ops by RCU v7 Christian König
2026-02-21 14:15 ` kernel test robot
@ 2026-02-21 14:26 ` kernel test robot
1 sibling, 0 replies; 11+ messages in thread
From: kernel test robot @ 2026-02-21 14:26 UTC (permalink / raw)
To: Christian König, phasta, matthew.brost, sumit.semwal
Cc: oe-kbuild-all, dri-devel, linaro-mm-sig
Hi Christian,
kernel test robot noticed the following build warnings:
[auto build test WARNING on drm-misc/drm-misc-next]
[cannot apply to drm-i915/for-linux-next drm-i915/for-linux-next-fixes drm-xe/drm-xe-next linus/master v6.19 next-20260220]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Christian-K-nig/dma-buf-detach-fence-ops-on-signal-v2/20260220-010804
base: https://gitlab.freedesktop.org/drm/misc/kernel.git drm-misc-next
patch link: https://lore.kernel.org/r/20260219160822.1529-2-christian.koenig%40amd.com
patch subject: [PATCH 1/8] dma-buf: protected fence ops by RCU v7
config: m68k-randconfig-r111-20260221 (https://download.01.org/0day-ci/archive/20260221/202602212224.vH1Jr91w-lkp@intel.com/config)
compiler: m68k-linux-gcc (GCC) 8.5.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260221/202602212224.vH1Jr91w-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202602212224.vH1Jr91w-lkp@intel.com/
sparse warnings: (new ones prefixed by >>)
>> drivers/gpu/drm/drm_crtc.c:161:9: sparse: sparse: incompatible types in comparison expression (different address spaces):
drivers/gpu/drm/drm_crtc.c:161:9: sparse: struct dma_fence_ops const [noderef] __rcu *
drivers/gpu/drm/drm_crtc.c:161:9: sparse: struct dma_fence_ops const *
--
drivers/gpu/drm/scheduler/sched_fence.c:241:1: sparse: sparse: bad integer constant expression
drivers/gpu/drm/scheduler/sched_fence.c:241:1: sparse: sparse: static assertion failed: "MODULE_INFO(description, ...) contains embedded NUL byte"
drivers/gpu/drm/scheduler/sched_fence.c:242:1: sparse: sparse: bad integer constant expression
drivers/gpu/drm/scheduler/sched_fence.c:242:1: sparse: sparse: static assertion failed: "MODULE_INFO(license, ...) contains embedded NUL byte"
>> drivers/gpu/drm/scheduler/sched_fence.c:198:20: sparse: sparse: incompatible types in comparison expression (different address spaces):
drivers/gpu/drm/scheduler/sched_fence.c:198:20: sparse: struct dma_fence_ops const [noderef] __rcu *
drivers/gpu/drm/scheduler/sched_fence.c:198:20: sparse: struct dma_fence_ops const *
drivers/gpu/drm/scheduler/sched_fence.c:201:20: sparse: sparse: incompatible types in comparison expression (different address spaces):
drivers/gpu/drm/scheduler/sched_fence.c:201:20: sparse: struct dma_fence_ops const [noderef] __rcu *
drivers/gpu/drm/scheduler/sched_fence.c:201:20: sparse: struct dma_fence_ops const *
vim +161 drivers/gpu/drm/drm_crtc.c
35f8cc3b9a92c6 Gustavo Padovan 2016-12-06 158
6d6003c4b613c9 Gustavo Padovan 2016-11-15 159 static struct drm_crtc *fence_to_crtc(struct dma_fence *fence)
6d6003c4b613c9 Gustavo Padovan 2016-11-15 160 {
6d6003c4b613c9 Gustavo Padovan 2016-11-15 @161 BUG_ON(fence->ops != &drm_crtc_fence_ops);
6d6003c4b613c9 Gustavo Padovan 2016-11-15 162 return container_of(fence->lock, struct drm_crtc, fence_lock);
6d6003c4b613c9 Gustavo Padovan 2016-11-15 163 }
6d6003c4b613c9 Gustavo Padovan 2016-11-15 164
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 2/8] dma-buf: detach fence ops on signal v2
[not found] <20260219160822.1529-1-christian.koenig@amd.com>
2026-02-19 16:07 ` [PATCH 1/8] dma-buf: protected fence ops by RCU v7 Christian König
@ 2026-02-19 16:07 ` Christian König
2026-02-21 15:28 ` kernel test robot
2026-02-19 16:07 ` [PATCH 3/8] dma-buf: abstract fence locking v2 Christian König
` (5 subsequent siblings)
7 siblings, 1 reply; 11+ messages in thread
From: Christian König @ 2026-02-19 16:07 UTC (permalink / raw)
To: phasta, matthew.brost, sumit.semwal; +Cc: dri-devel, linaro-mm-sig
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
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>
---
drivers/dma-buf/dma-fence.c | 16 ++++++++++++----
include/linux/dma-fence.h | 4 ++--
2 files changed, 14 insertions(+), 6 deletions(-)
diff --git a/drivers/dma-buf/dma-fence.c b/drivers/dma-buf/dma-fence.c
index d3c4e23bf297..ae77f900c267 100644
--- a/drivers/dma-buf/dma-fence.c
+++ b/drivers/dma-buf/dma-fence.c
@@ -371,6 +371,14 @@ 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.
+ */
+ if (!fence->ops->release && !fence->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 +545,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 +611,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 +647,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 +1033,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();
}
diff --git a/include/linux/dma-fence.h b/include/linux/dma-fence.h
index 9d8a4ebe8bf7..80db7ede91de 100644
--- a/include/linux/dma-fence.h
+++ b/include/linux/dma-fence.h
@@ -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;
--
2.43.0
^ permalink raw reply related [flat|nested] 11+ messages in thread* Re: [PATCH 2/8] dma-buf: detach fence ops on signal v2
2026-02-19 16:07 ` [PATCH 2/8] dma-buf: detach fence ops on signal v2 Christian König
@ 2026-02-21 15:28 ` kernel test robot
0 siblings, 0 replies; 11+ messages in thread
From: kernel test robot @ 2026-02-21 15:28 UTC (permalink / raw)
To: Christian König, phasta, matthew.brost, sumit.semwal
Cc: oe-kbuild-all, dri-devel, linaro-mm-sig
Hi Christian,
kernel test robot noticed the following build warnings:
[auto build test WARNING on drm-misc/drm-misc-next]
[cannot apply to drm-i915/for-linux-next drm-i915/for-linux-next-fixes drm-xe/drm-xe-next linus/master v6.19 next-20260220]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Christian-K-nig/dma-buf-detach-fence-ops-on-signal-v2/20260220-010804
base: https://gitlab.freedesktop.org/drm/misc/kernel.git drm-misc-next
patch link: https://lore.kernel.org/r/20260219160822.1529-3-christian.koenig%40amd.com
patch subject: [PATCH 2/8] dma-buf: detach fence ops on signal v2
config: hexagon-randconfig-r121-20260221 (https://download.01.org/0day-ci/archive/20260221/202602212322.qKZcoRK3-lkp@intel.com/config)
compiler: clang version 23.0.0git (https://github.com/llvm/llvm-project e86750b29fa0ff207cd43213d66dabe565417638)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260221/202602212322.qKZcoRK3-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202602212322.qKZcoRK3-lkp@intel.com/
sparse warnings: (new ones prefixed by >>)
drivers/dma-buf/dma-fence.c:1051:38: sparse: sparse: incorrect type in initializer (different address spaces) @@ expected char const [noderef] __rcu *timeline @@ got char * @@
drivers/dma-buf/dma-fence.c:1051:38: sparse: expected char const [noderef] __rcu *timeline
drivers/dma-buf/dma-fence.c:1051:38: sparse: got char *
drivers/dma-buf/dma-fence.c:1052:36: sparse: sparse: incorrect type in initializer (different address spaces) @@ expected char const [noderef] __rcu *driver @@ got char * @@
drivers/dma-buf/dma-fence.c:1052:36: sparse: expected char const [noderef] __rcu *driver
drivers/dma-buf/dma-fence.c:1052:36: sparse: got char *
drivers/dma-buf/dma-fence.c: note: in included file (through include/trace/trace_events.h, include/trace/define_trace.h, include/trace/events/dma_fence.h):
include/trace/events/dma_fence.h:17:1: sparse: sparse: dereference of noderef expression
include/trace/events/dma_fence.h:17:1: sparse: sparse: dereference of noderef expression
include/trace/events/dma_fence.h:17:1: sparse: sparse: dereference of noderef expression
include/trace/events/dma_fence.h:17:1: sparse: sparse: dereference of noderef expression
include/trace/events/dma_fence.h:17:1: sparse: sparse: dereference of noderef expression
include/trace/events/dma_fence.h:17:1: sparse: sparse: dereference of noderef expression
>> drivers/dma-buf/dma-fence.c:379:19: sparse: sparse: dereference of noderef expression
drivers/dma-buf/dma-fence.c:379:43: sparse: sparse: dereference of noderef expression
vim +379 drivers/dma-buf/dma-fence.c
345
346
347 /**
348 * dma_fence_signal_timestamp_locked - signal completion of a fence
349 * @fence: the fence to signal
350 * @timestamp: fence signal timestamp in kernel's CLOCK_MONOTONIC time domain
351 *
352 * Signal completion for software callbacks on a fence, this will unblock
353 * dma_fence_wait() calls and run all the callbacks added with
354 * dma_fence_add_callback(). Can be called multiple times, but since a fence
355 * can only go from the unsignaled to the signaled state and not back, it will
356 * only be effective the first time. Set the timestamp provided as the fence
357 * signal timestamp.
358 *
359 * Unlike dma_fence_signal_timestamp(), this function must be called with
360 * &dma_fence.lock held.
361 */
362 void dma_fence_signal_timestamp_locked(struct dma_fence *fence,
363 ktime_t timestamp)
364 {
365 struct dma_fence_cb *cur, *tmp;
366 struct list_head cb_list;
367
368 lockdep_assert_held(fence->lock);
369
370 if (unlikely(test_and_set_bit(DMA_FENCE_FLAG_SIGNALED_BIT,
371 &fence->flags)))
372 return;
373
374 /*
375 * When neither a release nor a wait operation is specified set the ops
376 * pointer to NULL to allow the fence structure to become independent
377 * from who originally issued it.
378 */
> 379 if (!fence->ops->release && !fence->ops->wait)
380 RCU_INIT_POINTER(fence->ops, NULL);
381
382 /* Stash the cb_list before replacing it with the timestamp */
383 list_replace(&fence->cb_list, &cb_list);
384
385 fence->timestamp = timestamp;
386 set_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &fence->flags);
387 trace_dma_fence_signaled(fence);
388
389 list_for_each_entry_safe(cur, tmp, &cb_list, node) {
390 INIT_LIST_HEAD(&cur->node);
391 cur->func(fence, cur);
392 }
393 }
394 EXPORT_SYMBOL(dma_fence_signal_timestamp_locked);
395
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 3/8] dma-buf: abstract fence locking v2
[not found] <20260219160822.1529-1-christian.koenig@amd.com>
2026-02-19 16:07 ` [PATCH 1/8] dma-buf: protected fence ops by RCU v7 Christian König
2026-02-19 16:07 ` [PATCH 2/8] dma-buf: detach fence ops on signal v2 Christian König
@ 2026-02-19 16:07 ` Christian König
2026-02-19 16:07 ` [PATCH 4/8] dma-buf: inline spinlock for fence protection v5 Christian König
` (4 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: Christian König @ 2026-02-19 16:07 UTC (permalink / raw)
To: phasta, matthew.brost, sumit.semwal; +Cc: dri-devel, linaro-mm-sig
Add dma_fence_lock_irqsafe() and dma_fence_unlock_irqrestore() wrappers
and mechanically apply them everywhere.
Just a pre-requisite cleanup for a follow up patch.
v2: add some missing i915 bits, add abstraction for lockdep assertion as
well
v3: one more suggestion by Tvrtko
Signed-off-by: Christian König <christian.koenig@amd.com>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@igalia.com>
---
drivers/dma-buf/dma-fence.c | 48 ++++++++++-----------
drivers/dma-buf/st-dma-fence.c | 6 ++-
drivers/dma-buf/sw_sync.c | 14 +++---
drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c | 4 +-
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 4 +-
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h | 2 +-
drivers/gpu/drm/i915/gt/intel_breadcrumbs.c | 2 +-
drivers/gpu/drm/i915/i915_active.c | 19 ++++----
drivers/gpu/drm/nouveau/nouveau_drm.c | 5 ++-
drivers/gpu/drm/scheduler/sched_fence.c | 6 +--
drivers/gpu/drm/xe/xe_sched_job.c | 4 +-
include/linux/dma-fence.h | 38 ++++++++++++++++
12 files changed, 96 insertions(+), 56 deletions(-)
diff --git a/drivers/dma-buf/dma-fence.c b/drivers/dma-buf/dma-fence.c
index ae77f900c267..bd4ec7e26dae 100644
--- a/drivers/dma-buf/dma-fence.c
+++ b/drivers/dma-buf/dma-fence.c
@@ -365,7 +365,7 @@ void dma_fence_signal_timestamp_locked(struct dma_fence *fence,
struct dma_fence_cb *cur, *tmp;
struct list_head cb_list;
- lockdep_assert_held(fence->lock);
+ dma_fence_assert_held(fence);
if (unlikely(test_and_set_bit(DMA_FENCE_FLAG_SIGNALED_BIT,
&fence->flags)))
@@ -412,9 +412,9 @@ void dma_fence_signal_timestamp(struct dma_fence *fence, ktime_t timestamp)
if (WARN_ON(!fence))
return;
- spin_lock_irqsave(fence->lock, flags);
+ dma_fence_lock_irqsave(fence, flags);
dma_fence_signal_timestamp_locked(fence, timestamp);
- spin_unlock_irqrestore(fence->lock, flags);
+ dma_fence_unlock_irqrestore(fence, flags);
}
EXPORT_SYMBOL(dma_fence_signal_timestamp);
@@ -473,9 +473,9 @@ bool dma_fence_check_and_signal(struct dma_fence *fence)
unsigned long flags;
bool ret;
- spin_lock_irqsave(fence->lock, flags);
+ dma_fence_lock_irqsave(fence, flags);
ret = dma_fence_check_and_signal_locked(fence);
- spin_unlock_irqrestore(fence->lock, flags);
+ dma_fence_unlock_irqrestore(fence, flags);
return ret;
}
@@ -501,9 +501,9 @@ void dma_fence_signal(struct dma_fence *fence)
tmp = dma_fence_begin_signalling();
- spin_lock_irqsave(fence->lock, flags);
+ dma_fence_lock_irqsave(fence, flags);
dma_fence_signal_timestamp_locked(fence, ktime_get());
- spin_unlock_irqrestore(fence->lock, flags);
+ dma_fence_unlock_irqrestore(fence, flags);
dma_fence_end_signalling(tmp);
}
@@ -604,10 +604,10 @@ void dma_fence_release(struct kref *kref)
* don't leave chains dangling. We set the error flag first
* so that the callbacks know this signal is due to an error.
*/
- spin_lock_irqsave(fence->lock, flags);
+ dma_fence_lock_irqsave(fence, flags);
fence->error = -EDEADLK;
dma_fence_signal_locked(fence);
- spin_unlock_irqrestore(fence->lock, flags);
+ dma_fence_unlock_irqrestore(fence, flags);
}
ops = rcu_dereference(fence->ops);
@@ -637,7 +637,7 @@ static bool __dma_fence_enable_signaling(struct dma_fence *fence)
const struct dma_fence_ops *ops;
bool was_set;
- lockdep_assert_held(fence->lock);
+ dma_fence_assert_held(fence);
was_set = test_and_set_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT,
&fence->flags);
@@ -673,9 +673,9 @@ void dma_fence_enable_sw_signaling(struct dma_fence *fence)
{
unsigned long flags;
- spin_lock_irqsave(fence->lock, flags);
+ dma_fence_lock_irqsave(fence, flags);
__dma_fence_enable_signaling(fence);
- spin_unlock_irqrestore(fence->lock, flags);
+ dma_fence_unlock_irqrestore(fence, flags);
}
EXPORT_SYMBOL(dma_fence_enable_sw_signaling);
@@ -715,8 +715,7 @@ int dma_fence_add_callback(struct dma_fence *fence, struct dma_fence_cb *cb,
return -ENOENT;
}
- spin_lock_irqsave(fence->lock, flags);
-
+ dma_fence_lock_irqsave(fence, flags);
if (__dma_fence_enable_signaling(fence)) {
cb->func = func;
list_add_tail(&cb->node, &fence->cb_list);
@@ -724,8 +723,7 @@ int dma_fence_add_callback(struct dma_fence *fence, struct dma_fence_cb *cb,
INIT_LIST_HEAD(&cb->node);
ret = -ENOENT;
}
-
- spin_unlock_irqrestore(fence->lock, flags);
+ dma_fence_unlock_irqrestore(fence, flags);
return ret;
}
@@ -748,9 +746,9 @@ int dma_fence_get_status(struct dma_fence *fence)
unsigned long flags;
int status;
- spin_lock_irqsave(fence->lock, flags);
+ dma_fence_lock_irqsave(fence, flags);
status = dma_fence_get_status_locked(fence);
- spin_unlock_irqrestore(fence->lock, flags);
+ dma_fence_unlock_irqrestore(fence, flags);
return status;
}
@@ -780,13 +778,11 @@ dma_fence_remove_callback(struct dma_fence *fence, struct dma_fence_cb *cb)
unsigned long flags;
bool ret;
- spin_lock_irqsave(fence->lock, flags);
-
+ dma_fence_lock_irqsave(fence, flags);
ret = !list_empty(&cb->node);
if (ret)
list_del_init(&cb->node);
-
- spin_unlock_irqrestore(fence->lock, flags);
+ dma_fence_unlock_irqrestore(fence, flags);
return ret;
}
@@ -825,7 +821,7 @@ dma_fence_default_wait(struct dma_fence *fence, bool intr, signed long timeout)
unsigned long flags;
signed long ret = timeout ? timeout : 1;
- spin_lock_irqsave(fence->lock, flags);
+ dma_fence_lock_irqsave(fence, flags);
if (dma_fence_test_signaled_flag(fence))
goto out;
@@ -849,11 +845,11 @@ dma_fence_default_wait(struct dma_fence *fence, bool intr, signed long timeout)
__set_current_state(TASK_INTERRUPTIBLE);
else
__set_current_state(TASK_UNINTERRUPTIBLE);
- spin_unlock_irqrestore(fence->lock, flags);
+ dma_fence_unlock_irqrestore(fence, flags);
ret = schedule_timeout(ret);
- spin_lock_irqsave(fence->lock, flags);
+ dma_fence_lock_irqsave(fence, flags);
if (ret > 0 && intr && signal_pending(current))
ret = -ERESTARTSYS;
}
@@ -863,7 +859,7 @@ dma_fence_default_wait(struct dma_fence *fence, bool intr, signed long timeout)
__set_current_state(TASK_RUNNING);
out:
- spin_unlock_irqrestore(fence->lock, flags);
+ dma_fence_unlock_irqrestore(fence, flags);
return ret;
}
EXPORT_SYMBOL(dma_fence_default_wait);
diff --git a/drivers/dma-buf/st-dma-fence.c b/drivers/dma-buf/st-dma-fence.c
index 73ed6fd48a13..5d0d9abc6e21 100644
--- a/drivers/dma-buf/st-dma-fence.c
+++ b/drivers/dma-buf/st-dma-fence.c
@@ -410,8 +410,10 @@ struct race_thread {
static void __wait_for_callbacks(struct dma_fence *f)
{
- spin_lock_irq(f->lock);
- spin_unlock_irq(f->lock);
+ unsigned long flags;
+
+ dma_fence_lock_irqsave(f, flags);
+ dma_fence_unlock_irqrestore(f, flags);
}
static int thread_signal_callback(void *arg)
diff --git a/drivers/dma-buf/sw_sync.c b/drivers/dma-buf/sw_sync.c
index 6f09d13be6b6..4c81a37dd682 100644
--- a/drivers/dma-buf/sw_sync.c
+++ b/drivers/dma-buf/sw_sync.c
@@ -156,12 +156,12 @@ static void timeline_fence_release(struct dma_fence *fence)
struct sync_timeline *parent = dma_fence_parent(fence);
unsigned long flags;
- spin_lock_irqsave(fence->lock, flags);
+ dma_fence_lock_irqsave(fence, flags);
if (!list_empty(&pt->link)) {
list_del(&pt->link);
rb_erase(&pt->node, &parent->pt_tree);
}
- spin_unlock_irqrestore(fence->lock, flags);
+ dma_fence_unlock_irqrestore(fence, flags);
sync_timeline_put(parent);
dma_fence_free(fence);
@@ -179,7 +179,7 @@ static void timeline_fence_set_deadline(struct dma_fence *fence, ktime_t deadlin
struct sync_pt *pt = dma_fence_to_sync_pt(fence);
unsigned long flags;
- spin_lock_irqsave(fence->lock, flags);
+ dma_fence_lock_irqsave(fence, flags);
if (test_bit(SW_SYNC_HAS_DEADLINE_BIT, &fence->flags)) {
if (ktime_before(deadline, pt->deadline))
pt->deadline = deadline;
@@ -187,7 +187,7 @@ static void timeline_fence_set_deadline(struct dma_fence *fence, ktime_t deadlin
pt->deadline = deadline;
__set_bit(SW_SYNC_HAS_DEADLINE_BIT, &fence->flags);
}
- spin_unlock_irqrestore(fence->lock, flags);
+ dma_fence_unlock_irqrestore(fence, flags);
}
static const struct dma_fence_ops timeline_fence_ops = {
@@ -431,13 +431,13 @@ static int sw_sync_ioctl_get_deadline(struct sync_timeline *obj, unsigned long a
goto put_fence;
}
- spin_lock_irqsave(fence->lock, flags);
+ dma_fence_lock_irqsave(fence, flags);
if (!test_bit(SW_SYNC_HAS_DEADLINE_BIT, &fence->flags)) {
ret = -ENOENT;
goto unlock;
}
data.deadline_ns = ktime_to_ns(pt->deadline);
- spin_unlock_irqrestore(fence->lock, flags);
+ dma_fence_unlock_irqrestore(fence, flags);
dma_fence_put(fence);
@@ -450,7 +450,7 @@ static int sw_sync_ioctl_get_deadline(struct sync_timeline *obj, unsigned long a
return 0;
unlock:
- spin_unlock_irqrestore(fence->lock, flags);
+ dma_fence_unlock_irqrestore(fence, flags);
put_fence:
dma_fence_put(fence);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
index b82357c65723..1404e1fe62a4 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
@@ -479,10 +479,10 @@ bool amdgpu_ring_soft_recovery(struct amdgpu_ring *ring, unsigned int vmid,
if (amdgpu_sriov_vf(ring->adev) || !ring->funcs->soft_recovery || !fence)
return false;
- spin_lock_irqsave(fence->lock, flags);
+ dma_fence_lock_irqsave(fence, flags);
if (!dma_fence_is_signaled_locked(fence))
dma_fence_set_error(fence, -ENODATA);
- spin_unlock_irqrestore(fence->lock, flags);
+ dma_fence_unlock_irqrestore(fence, flags);
while (!dma_fence_is_signaled(fence) &&
ktime_to_ns(ktime_sub(deadline, ktime_get())) > 0)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
index 6a2ea200d90c..4761e7486811 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
@@ -2802,8 +2802,8 @@ void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm)
dma_fence_put(vm->last_unlocked);
dma_fence_wait(vm->last_tlb_flush, false);
/* Make sure that all fence callbacks have completed */
- spin_lock_irqsave(vm->last_tlb_flush->lock, flags);
- spin_unlock_irqrestore(vm->last_tlb_flush->lock, flags);
+ dma_fence_lock_irqsave(vm->last_tlb_flush, flags);
+ dma_fence_unlock_irqrestore(vm->last_tlb_flush, flags);
dma_fence_put(vm->last_tlb_flush);
list_for_each_entry_safe(mapping, tmp, &vm->freed, list) {
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
index 139642eacdd0..d5c41e24fb51 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
@@ -638,7 +638,7 @@ static inline uint64_t amdgpu_vm_tlb_seq(struct amdgpu_vm *vm)
* sure that the dma_fence structure isn't freed up.
*/
rcu_read_lock();
- lock = vm->last_tlb_flush->lock;
+ lock = dma_fence_spinlock(vm->last_tlb_flush);
rcu_read_unlock();
spin_lock_irqsave(lock, flags);
diff --git a/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c b/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c
index bf6117d5fc57..78ea2d9ccedf 100644
--- a/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c
+++ b/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c
@@ -148,7 +148,7 @@ __dma_fence_signal__notify(struct dma_fence *fence,
{
struct dma_fence_cb *cur, *tmp;
- lockdep_assert_held(fence->lock);
+ dma_fence_assert_held(fence);
list_for_each_entry_safe(cur, tmp, list, node) {
INIT_LIST_HEAD(&cur->node);
diff --git a/drivers/gpu/drm/i915/i915_active.c b/drivers/gpu/drm/i915/i915_active.c
index 6b0c1162505a..9d41e052ab65 100644
--- a/drivers/gpu/drm/i915/i915_active.c
+++ b/drivers/gpu/drm/i915/i915_active.c
@@ -1045,9 +1045,10 @@ __i915_active_fence_set(struct i915_active_fence *active,
* nesting rules for the fence->lock; the inner lock is always the
* older lock.
*/
- spin_lock_irqsave(fence->lock, flags);
+ dma_fence_lock_irqsave(fence, flags);
if (prev)
- spin_lock_nested(prev->lock, SINGLE_DEPTH_NESTING);
+ spin_lock_nested(dma_fence_spinlock(prev),
+ SINGLE_DEPTH_NESTING);
/*
* A does the cmpxchg first, and so it sees C or NULL, as before, or
@@ -1061,17 +1062,18 @@ __i915_active_fence_set(struct i915_active_fence *active,
*/
while (cmpxchg(__active_fence_slot(active), prev, fence) != prev) {
if (prev) {
- spin_unlock(prev->lock);
+ spin_unlock(dma_fence_spinlock(prev));
dma_fence_put(prev);
}
- spin_unlock_irqrestore(fence->lock, flags);
+ dma_fence_unlock_irqrestore(fence, flags);
prev = i915_active_fence_get(active);
GEM_BUG_ON(prev == fence);
- spin_lock_irqsave(fence->lock, flags);
+ dma_fence_lock_irqsave(fence, flags);
if (prev)
- spin_lock_nested(prev->lock, SINGLE_DEPTH_NESTING);
+ spin_lock_nested(dma_fence_spinlock(prev),
+ SINGLE_DEPTH_NESTING);
}
/*
@@ -1088,10 +1090,11 @@ __i915_active_fence_set(struct i915_active_fence *active,
*/
if (prev) {
__list_del_entry(&active->cb.node);
- spin_unlock(prev->lock); /* serialise with prev->cb_list */
+ /* serialise with prev->cb_list */
+ spin_unlock(dma_fence_spinlock(prev));
}
list_add_tail(&active->cb.node, &fence->cb_list);
- spin_unlock_irqrestore(fence->lock, flags);
+ dma_fence_unlock_irqrestore(fence, flags);
return prev;
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c
index f2e04a048ac2..e6805b8b9ffa 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.c
@@ -156,12 +156,13 @@ nouveau_name(struct drm_device *dev)
static inline bool
nouveau_cli_work_ready(struct dma_fence *fence)
{
+ unsigned long flags;
bool ret = true;
- spin_lock_irq(fence->lock);
+ dma_fence_lock_irqsave(fence, flags);
if (!dma_fence_is_signaled_locked(fence))
ret = false;
- spin_unlock_irq(fence->lock);
+ dma_fence_unlock_irqrestore(fence, flags);
if (ret == true)
dma_fence_put(fence);
diff --git a/drivers/gpu/drm/scheduler/sched_fence.c b/drivers/gpu/drm/scheduler/sched_fence.c
index 9391d6f0dc01..724d77694246 100644
--- a/drivers/gpu/drm/scheduler/sched_fence.c
+++ b/drivers/gpu/drm/scheduler/sched_fence.c
@@ -156,19 +156,19 @@ static void drm_sched_fence_set_deadline_finished(struct dma_fence *f,
struct dma_fence *parent;
unsigned long flags;
- spin_lock_irqsave(&fence->lock, flags);
+ dma_fence_lock_irqsave(f, flags);
/* If we already have an earlier deadline, keep it: */
if (test_bit(DRM_SCHED_FENCE_FLAG_HAS_DEADLINE_BIT, &f->flags) &&
ktime_before(fence->deadline, deadline)) {
- spin_unlock_irqrestore(&fence->lock, flags);
+ dma_fence_unlock_irqrestore(f, flags);
return;
}
fence->deadline = deadline;
set_bit(DRM_SCHED_FENCE_FLAG_HAS_DEADLINE_BIT, &f->flags);
- spin_unlock_irqrestore(&fence->lock, flags);
+ dma_fence_unlock_irqrestore(f, flags);
/*
* smp_load_aquire() to ensure that if we are racing another
diff --git a/drivers/gpu/drm/xe/xe_sched_job.c b/drivers/gpu/drm/xe/xe_sched_job.c
index 3927666fe556..ae5b38b2a884 100644
--- a/drivers/gpu/drm/xe/xe_sched_job.c
+++ b/drivers/gpu/drm/xe/xe_sched_job.c
@@ -190,11 +190,11 @@ static bool xe_fence_set_error(struct dma_fence *fence, int error)
unsigned long irq_flags;
bool signaled;
- spin_lock_irqsave(fence->lock, irq_flags);
+ dma_fence_lock_irqsave(fence, irq_flags);
signaled = test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags);
if (!signaled)
dma_fence_set_error(fence, error);
- spin_unlock_irqrestore(fence->lock, irq_flags);
+ dma_fence_unlock_irqrestore(fence, irq_flags);
return signaled;
}
diff --git a/include/linux/dma-fence.h b/include/linux/dma-fence.h
index 80db7ede91de..086324af96c9 100644
--- a/include/linux/dma-fence.h
+++ b/include/linux/dma-fence.h
@@ -377,6 +377,44 @@ dma_fence_get_rcu_safe(struct dma_fence __rcu **fencep)
} while (1);
}
+/**
+ * dma_fence_spinlock - return pointer to the spinlock protecting the fence
+ * @fence: the fence to get the lock from
+ *
+ * Return the pointer to the extern lock.
+ */
+static inline spinlock_t *dma_fence_spinlock(struct dma_fence *fence)
+{
+ return fence->lock;
+}
+
+/**
+ * dma_fence_lock_irqsave - irqsave lock the fence
+ * @fence: the fence to lock
+ * @flags: where to store the CPU flags.
+ *
+ * Lock the fence, preventing it from changing to the signaled state.
+ */
+#define dma_fence_lock_irqsave(fence, flags) \
+ spin_lock_irqsave(fence->lock, flags)
+
+/**
+ * dma_fence_unlock_irqrestore - unlock the fence and irqrestore
+ * @fence: the fence to unlock
+ * @flags the CPU flags to restore
+ *
+ * Unlock the fence, allowing it to change it's state to signaled again.
+ */
+#define dma_fence_unlock_irqrestore(fence, flags) \
+ spin_unlock_irqrestore(fence->lock, flags)
+
+/**
+ * dma_fence_assert_held - lockdep assertion that fence is locked
+ * @fence: the fence which should be locked
+ */
+#define dma_fence_assert_held(fence) \
+ lockdep_assert_held(dma_fence_spinlock(fence));
+
#ifdef CONFIG_LOCKDEP
bool dma_fence_begin_signalling(void);
void dma_fence_end_signalling(bool cookie);
--
2.43.0
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH 4/8] dma-buf: inline spinlock for fence protection v5
[not found] <20260219160822.1529-1-christian.koenig@amd.com>
` (2 preceding siblings ...)
2026-02-19 16:07 ` [PATCH 3/8] dma-buf: abstract fence locking v2 Christian König
@ 2026-02-19 16:07 ` Christian König
2026-02-19 16:07 ` [PATCH 5/8] dma-buf/selftests: test RCU ops and inline lock v2 Christian König
` (3 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: Christian König @ 2026-02-19 16:07 UTC (permalink / raw)
To: phasta, matthew.brost, sumit.semwal; +Cc: dri-devel, linaro-mm-sig
Implement per-fence spinlocks, allowing implementations to not give an
external spinlock to protect the fence internal state. Instead a spinlock
embedded into the fence structure itself is used in this case.
Shared spinlocks have the problem that implementations need to guarantee
that the lock lives at least as long all fences referencing them.
Using a per-fence spinlock allows completely decoupling spinlock producer
and consumer life times, simplifying the handling in most use cases.
v2: improve naming, coverage and function documentation
v3: fix one additional locking in the selftests
v4: separate out some changes to make the patch smaller,
fix one amdgpu crash found by CI systems
v5: improve comments
Signed-off-by: Christian König <christian.koenig@amd.com>
Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
---
drivers/dma-buf/dma-fence.c | 21 ++++++++++++++++-----
drivers/dma-buf/sync_debug.h | 2 +-
drivers/gpu/drm/drm_crtc.c | 2 +-
drivers/gpu/drm/drm_writeback.c | 2 +-
drivers/gpu/drm/nouveau/nouveau_fence.c | 3 ++-
drivers/gpu/drm/qxl/qxl_release.c | 3 ++-
drivers/gpu/drm/vmwgfx/vmwgfx_fence.c | 3 ++-
drivers/gpu/drm/xe/xe_hw_fence.c | 3 ++-
include/linux/dma-fence.h | 19 +++++++++++++------
9 files changed, 40 insertions(+), 18 deletions(-)
diff --git a/drivers/dma-buf/dma-fence.c b/drivers/dma-buf/dma-fence.c
index bd4ec7e26dae..39f0a4d08a2d 100644
--- a/drivers/dma-buf/dma-fence.c
+++ b/drivers/dma-buf/dma-fence.c
@@ -343,7 +343,6 @@ void __dma_fence_might_wait(void)
}
#endif
-
/**
* dma_fence_signal_timestamp_locked - signal completion of a fence
* @fence: the fence to signal
@@ -1068,7 +1067,6 @@ static void
__dma_fence_init(struct dma_fence *fence, const struct dma_fence_ops *ops,
spinlock_t *lock, u64 context, u64 seqno, unsigned long flags)
{
- BUG_ON(!lock);
BUG_ON(!ops || !ops->get_driver_name || !ops->get_timeline_name);
kref_init(&fence->refcount);
@@ -1080,10 +1078,15 @@ __dma_fence_init(struct dma_fence *fence, const struct dma_fence_ops *ops,
*/
RCU_INIT_POINTER(fence->ops, ops);
INIT_LIST_HEAD(&fence->cb_list);
- fence->lock = lock;
fence->context = context;
fence->seqno = seqno;
fence->flags = flags | BIT(DMA_FENCE_FLAG_INITIALIZED_BIT);
+ if (lock) {
+ fence->extern_lock = lock;
+ } else {
+ spin_lock_init(&fence->inline_lock);
+ fence->flags |= BIT(DMA_FENCE_FLAG_INLINE_LOCK_BIT);
+ }
fence->error = 0;
trace_dma_fence_init(fence);
@@ -1093,7 +1096,7 @@ __dma_fence_init(struct dma_fence *fence, const struct dma_fence_ops *ops,
* dma_fence_init - Initialize a custom fence.
* @fence: the fence to initialize
* @ops: the dma_fence_ops for operations on this fence
- * @lock: the irqsafe spinlock to use for locking this fence
+ * @lock: optional irqsafe spinlock to use for locking this fence
* @context: the execution context this fence is run on
* @seqno: a linear increasing sequence number for this context
*
@@ -1103,6 +1106,10 @@ __dma_fence_init(struct dma_fence *fence, const struct dma_fence_ops *ops,
*
* context and seqno are used for easy comparison between fences, allowing
* to check which fence is later by simply using dma_fence_later().
+ *
+ * It is strongly discouraged to provide an external lock because this couples
+ * lock and fence life time. This is only allowed for legacy use cases when
+ * multiple fences need to be prevented from signaling out of order.
*/
void
dma_fence_init(struct dma_fence *fence, const struct dma_fence_ops *ops,
@@ -1116,7 +1123,7 @@ EXPORT_SYMBOL(dma_fence_init);
* dma_fence_init64 - Initialize a custom fence with 64-bit seqno support.
* @fence: the fence to initialize
* @ops: the dma_fence_ops for operations on this fence
- * @lock: the irqsafe spinlock to use for locking this fence
+ * @lock: optional irqsafe spinlock to use for locking this fence
* @context: the execution context this fence is run on
* @seqno: a linear increasing sequence number for this context
*
@@ -1126,6 +1133,10 @@ EXPORT_SYMBOL(dma_fence_init);
*
* Context and seqno are used for easy comparison between fences, allowing
* to check which fence is later by simply using dma_fence_later().
+ *
+ * It is strongly discouraged to provide an external lock because this couples
+ * lock and fence life time. This is only allowed for legacy use cases when
+ * multiple fences need to be prevented from signaling out of order.
*/
void
dma_fence_init64(struct dma_fence *fence, const struct dma_fence_ops *ops,
diff --git a/drivers/dma-buf/sync_debug.h b/drivers/dma-buf/sync_debug.h
index 02af347293d0..c49324505b20 100644
--- a/drivers/dma-buf/sync_debug.h
+++ b/drivers/dma-buf/sync_debug.h
@@ -47,7 +47,7 @@ struct sync_timeline {
static inline struct sync_timeline *dma_fence_parent(struct dma_fence *fence)
{
- return container_of(fence->lock, struct sync_timeline, lock);
+ return container_of(fence->extern_lock, struct sync_timeline, lock);
}
/**
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index a7797d260f1e..17472915842f 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -159,7 +159,7 @@ static const struct dma_fence_ops drm_crtc_fence_ops;
static struct drm_crtc *fence_to_crtc(struct dma_fence *fence)
{
BUG_ON(fence->ops != &drm_crtc_fence_ops);
- return container_of(fence->lock, struct drm_crtc, fence_lock);
+ return container_of(fence->extern_lock, struct drm_crtc, fence_lock);
}
static const char *drm_crtc_fence_get_driver_name(struct dma_fence *fence)
diff --git a/drivers/gpu/drm/drm_writeback.c b/drivers/gpu/drm/drm_writeback.c
index 95b8a2e4bda6..624a4e8b6c99 100644
--- a/drivers/gpu/drm/drm_writeback.c
+++ b/drivers/gpu/drm/drm_writeback.c
@@ -81,7 +81,7 @@
* From userspace, this property will always read as zero.
*/
-#define fence_to_wb_connector(x) container_of(x->lock, \
+#define fence_to_wb_connector(x) container_of(x->extern_lock, \
struct drm_writeback_connector, \
fence_lock)
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c
index 4a193b7d6d9e..c282c94138b2 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fence.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fence.c
@@ -41,7 +41,8 @@ static const struct dma_fence_ops nouveau_fence_ops_legacy;
static inline struct nouveau_fence_chan *
nouveau_fctx(struct nouveau_fence *fence)
{
- return container_of(fence->base.lock, struct nouveau_fence_chan, lock);
+ return container_of(fence->base.extern_lock, struct nouveau_fence_chan,
+ lock);
}
static bool
diff --git a/drivers/gpu/drm/qxl/qxl_release.c b/drivers/gpu/drm/qxl/qxl_release.c
index 06b0b2aa7953..37d4ae0faf0d 100644
--- a/drivers/gpu/drm/qxl/qxl_release.c
+++ b/drivers/gpu/drm/qxl/qxl_release.c
@@ -62,7 +62,8 @@ static long qxl_fence_wait(struct dma_fence *fence, bool intr,
struct qxl_device *qdev;
unsigned long cur, end = jiffies + timeout;
- qdev = container_of(fence->lock, struct qxl_device, release_lock);
+ qdev = container_of(fence->extern_lock, struct qxl_device,
+ release_lock);
if (!wait_event_timeout(qdev->release_event,
(dma_fence_is_signaled(fence) ||
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
index 85795082fef9..d251eec57df9 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
@@ -47,7 +47,8 @@ struct vmw_event_fence_action {
static struct vmw_fence_manager *
fman_from_fence(struct vmw_fence_obj *fence)
{
- return container_of(fence->base.lock, struct vmw_fence_manager, lock);
+ return container_of(fence->base.extern_lock, struct vmw_fence_manager,
+ lock);
}
static void vmw_fence_obj_destroy(struct dma_fence *f)
diff --git a/drivers/gpu/drm/xe/xe_hw_fence.c b/drivers/gpu/drm/xe/xe_hw_fence.c
index ae8ed15b64c5..14720623ad00 100644
--- a/drivers/gpu/drm/xe/xe_hw_fence.c
+++ b/drivers/gpu/drm/xe/xe_hw_fence.c
@@ -124,7 +124,8 @@ static struct xe_hw_fence *to_xe_hw_fence(struct dma_fence *fence);
static struct xe_hw_fence_irq *xe_hw_fence_irq(struct xe_hw_fence *fence)
{
- return container_of(fence->dma.lock, struct xe_hw_fence_irq, lock);
+ return container_of(fence->dma.extern_lock, struct xe_hw_fence_irq,
+ lock);
}
static const char *xe_hw_fence_get_driver_name(struct dma_fence *dma_fence)
diff --git a/include/linux/dma-fence.h b/include/linux/dma-fence.h
index 086324af96c9..9ed359e38d4e 100644
--- a/include/linux/dma-fence.h
+++ b/include/linux/dma-fence.h
@@ -34,7 +34,8 @@ struct seq_file;
* @ops: dma_fence_ops associated with this fence
* @rcu: used for releasing fence with kfree_rcu
* @cb_list: list of all callbacks to call
- * @lock: spin_lock_irqsave used for locking
+ * @extern_lock: external spin_lock_irqsave used for locking (deprecated)
+ * @inline_lock: alternative internal spin_lock_irqsave used for locking
* @context: execution context this fence belongs to, returned by
* dma_fence_context_alloc()
* @seqno: the sequence number of this fence inside the execution context,
@@ -49,6 +50,7 @@ struct seq_file;
* of the time.
*
* DMA_FENCE_FLAG_INITIALIZED_BIT - fence was initialized
+ * DMA_FENCE_FLAG_INLINE_LOCK_BIT - use inline spinlock instead of external one
* DMA_FENCE_FLAG_SIGNALED_BIT - fence is already signaled
* DMA_FENCE_FLAG_TIMESTAMP_BIT - timestamp recorded for fence signaling
* DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT - enable_signaling might have been called
@@ -66,7 +68,10 @@ struct seq_file;
* been completed, or never called at all.
*/
struct dma_fence {
- spinlock_t *lock;
+ union {
+ spinlock_t *extern_lock;
+ spinlock_t inline_lock;
+ };
const struct dma_fence_ops __rcu *ops;
/*
* We clear the callback list on kref_put so that by the time we
@@ -100,6 +105,7 @@ struct dma_fence {
enum dma_fence_flag_bits {
DMA_FENCE_FLAG_INITIALIZED_BIT,
+ DMA_FENCE_FLAG_INLINE_LOCK_BIT,
DMA_FENCE_FLAG_SEQNO64_BIT,
DMA_FENCE_FLAG_SIGNALED_BIT,
DMA_FENCE_FLAG_TIMESTAMP_BIT,
@@ -381,11 +387,12 @@ dma_fence_get_rcu_safe(struct dma_fence __rcu **fencep)
* dma_fence_spinlock - return pointer to the spinlock protecting the fence
* @fence: the fence to get the lock from
*
- * Return the pointer to the extern lock.
+ * Return either the pointer to the embedded or the external spin lock.
*/
static inline spinlock_t *dma_fence_spinlock(struct dma_fence *fence)
{
- return fence->lock;
+ return test_bit(DMA_FENCE_FLAG_INLINE_LOCK_BIT, &fence->flags) ?
+ &fence->inline_lock : fence->extern_lock;
}
/**
@@ -396,7 +403,7 @@ static inline spinlock_t *dma_fence_spinlock(struct dma_fence *fence)
* Lock the fence, preventing it from changing to the signaled state.
*/
#define dma_fence_lock_irqsave(fence, flags) \
- spin_lock_irqsave(fence->lock, flags)
+ spin_lock_irqsave(dma_fence_spinlock(fence), flags)
/**
* dma_fence_unlock_irqrestore - unlock the fence and irqrestore
@@ -406,7 +413,7 @@ static inline spinlock_t *dma_fence_spinlock(struct dma_fence *fence)
* Unlock the fence, allowing it to change it's state to signaled again.
*/
#define dma_fence_unlock_irqrestore(fence, flags) \
- spin_unlock_irqrestore(fence->lock, flags)
+ spin_unlock_irqrestore(dma_fence_spinlock(fence), flags)
/**
* dma_fence_assert_held - lockdep assertion that fence is locked
--
2.43.0
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH 5/8] dma-buf/selftests: test RCU ops and inline lock v2
[not found] <20260219160822.1529-1-christian.koenig@amd.com>
` (3 preceding siblings ...)
2026-02-19 16:07 ` [PATCH 4/8] dma-buf: inline spinlock for fence protection v5 Christian König
@ 2026-02-19 16:07 ` Christian König
2026-02-19 16:07 ` [PATCH 6/8] dma-buf: use inline lock for the stub fence v2 Christian König
` (2 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: Christian König @ 2026-02-19 16:07 UTC (permalink / raw)
To: phasta, matthew.brost, sumit.semwal; +Cc: dri-devel, linaro-mm-sig
Drop the mock_fence and the kmem_cache, instead use the inline lock and
test if the ops are properly dropped after signaling.
v2: move the RCU check to the end of the test
Signed-off-by: Christian König <christian.koenig@amd.com>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@igalia.com>
---
drivers/dma-buf/st-dma-fence.c | 44 ++++++++--------------------------
1 file changed, 10 insertions(+), 34 deletions(-)
diff --git a/drivers/dma-buf/st-dma-fence.c b/drivers/dma-buf/st-dma-fence.c
index 5d0d9abc6e21..0d9d524d79b6 100644
--- a/drivers/dma-buf/st-dma-fence.c
+++ b/drivers/dma-buf/st-dma-fence.c
@@ -14,43 +14,26 @@
#include "selftest.h"
-static struct kmem_cache *slab_fences;
-
-static struct mock_fence {
- struct dma_fence base;
- struct spinlock lock;
-} *to_mock_fence(struct dma_fence *f) {
- return container_of(f, struct mock_fence, base);
-}
-
static const char *mock_name(struct dma_fence *f)
{
return "mock";
}
-static void mock_fence_release(struct dma_fence *f)
-{
- kmem_cache_free(slab_fences, to_mock_fence(f));
-}
-
static const struct dma_fence_ops mock_ops = {
.get_driver_name = mock_name,
.get_timeline_name = mock_name,
- .release = mock_fence_release,
};
static struct dma_fence *mock_fence(void)
{
- struct mock_fence *f;
+ struct dma_fence *f;
- f = kmem_cache_alloc(slab_fences, GFP_KERNEL);
+ f = kmalloc(sizeof(*f), GFP_KERNEL);
if (!f)
return NULL;
- spin_lock_init(&f->lock);
- dma_fence_init(&f->base, &mock_ops, &f->lock, 0, 0);
-
- return &f->base;
+ dma_fence_init(f, &mock_ops, NULL, 0, 0);
+ return f;
}
static int sanitycheck(void *arg)
@@ -100,6 +83,11 @@ static int test_signaling(void *arg)
goto err_free;
}
+ if (rcu_dereference_protected(f->ops, true)) {
+ pr_err("Fence ops not cleared on signal\n");
+ goto err_free;
+ }
+
err = 0;
err_free:
dma_fence_put(f);
@@ -540,19 +528,7 @@ int dma_fence(void)
SUBTEST(test_stub),
SUBTEST(race_signal_callback),
};
- int ret;
pr_info("sizeof(dma_fence)=%zu\n", sizeof(struct dma_fence));
-
- slab_fences = KMEM_CACHE(mock_fence,
- SLAB_TYPESAFE_BY_RCU |
- SLAB_HWCACHE_ALIGN);
- if (!slab_fences)
- return -ENOMEM;
-
- ret = subtests(tests, NULL);
-
- kmem_cache_destroy(slab_fences);
-
- return ret;
+ return subtests(tests, NULL);
}
--
2.43.0
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH 6/8] dma-buf: use inline lock for the stub fence v2
[not found] <20260219160822.1529-1-christian.koenig@amd.com>
` (4 preceding siblings ...)
2026-02-19 16:07 ` [PATCH 5/8] dma-buf/selftests: test RCU ops and inline lock v2 Christian König
@ 2026-02-19 16:07 ` Christian König
2026-02-19 16:07 ` [PATCH 7/8] dma-buf: use inline lock for the dma-fence-array Christian König
2026-02-19 16:07 ` [PATCH 8/8] dma-buf: use inline lock for the dma-fence-chain Christian König
7 siblings, 0 replies; 11+ messages in thread
From: Christian König @ 2026-02-19 16:07 UTC (permalink / raw)
To: phasta, matthew.brost, sumit.semwal; +Cc: dri-devel, linaro-mm-sig
Using the inline lock is now the recommended way for dma_fence
implementations.
So use this approach for the framework's internal fences as well.
Also saves about 4 bytes for the external spinlock.
v2: drop unnecessary changes
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>
---
drivers/dma-buf/dma-fence.c | 12 ++----------
1 file changed, 2 insertions(+), 10 deletions(-)
diff --git a/drivers/dma-buf/dma-fence.c b/drivers/dma-buf/dma-fence.c
index 39f0a4d08a2d..133cb9033b2c 100644
--- a/drivers/dma-buf/dma-fence.c
+++ b/drivers/dma-buf/dma-fence.c
@@ -24,7 +24,6 @@ EXPORT_TRACEPOINT_SYMBOL(dma_fence_emit);
EXPORT_TRACEPOINT_SYMBOL(dma_fence_enable_signal);
EXPORT_TRACEPOINT_SYMBOL(dma_fence_signaled);
-static DEFINE_SPINLOCK(dma_fence_stub_lock);
static struct dma_fence dma_fence_stub;
/*
@@ -123,12 +122,9 @@ static const struct dma_fence_ops dma_fence_stub_ops = {
static int __init dma_fence_init_stub(void)
{
- dma_fence_init(&dma_fence_stub, &dma_fence_stub_ops,
- &dma_fence_stub_lock, 0, 0);
-
+ dma_fence_init(&dma_fence_stub, &dma_fence_stub_ops, NULL, 0, 0);
set_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT,
&dma_fence_stub.flags);
-
dma_fence_signal(&dma_fence_stub);
return 0;
}
@@ -160,11 +156,7 @@ struct dma_fence *dma_fence_allocate_private_stub(ktime_t timestamp)
if (fence == NULL)
return NULL;
- dma_fence_init(fence,
- &dma_fence_stub_ops,
- &dma_fence_stub_lock,
- 0, 0);
-
+ dma_fence_init(fence, &dma_fence_stub_ops, NULL, 0, 0);
set_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT,
&fence->flags);
--
2.43.0
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH 7/8] dma-buf: use inline lock for the dma-fence-array
[not found] <20260219160822.1529-1-christian.koenig@amd.com>
` (5 preceding siblings ...)
2026-02-19 16:07 ` [PATCH 6/8] dma-buf: use inline lock for the stub fence v2 Christian König
@ 2026-02-19 16:07 ` Christian König
2026-02-19 16:07 ` [PATCH 8/8] dma-buf: use inline lock for the dma-fence-chain Christian König
7 siblings, 0 replies; 11+ messages in thread
From: Christian König @ 2026-02-19 16:07 UTC (permalink / raw)
To: phasta, matthew.brost, sumit.semwal; +Cc: dri-devel, linaro-mm-sig
Using the inline lock is now the recommended way for dma_fence
implementations.
So use this approach for the framework's internal fences as well.
Also saves about 4 bytes for the external spinlock.
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>
---
drivers/dma-buf/dma-fence-array.c | 5 ++---
include/linux/dma-fence-array.h | 1 -
2 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/drivers/dma-buf/dma-fence-array.c b/drivers/dma-buf/dma-fence-array.c
index 6657d4b30af9..c2119a8049fe 100644
--- a/drivers/dma-buf/dma-fence-array.c
+++ b/drivers/dma-buf/dma-fence-array.c
@@ -204,9 +204,8 @@ void dma_fence_array_init(struct dma_fence_array *array,
array->num_fences = num_fences;
- spin_lock_init(&array->lock);
- dma_fence_init(&array->base, &dma_fence_array_ops, &array->lock,
- context, seqno);
+ dma_fence_init(&array->base, &dma_fence_array_ops, NULL, context,
+ seqno);
init_irq_work(&array->work, irq_dma_fence_array_work);
atomic_set(&array->num_pending, signal_on_any ? 1 : num_fences);
diff --git a/include/linux/dma-fence-array.h b/include/linux/dma-fence-array.h
index 079b3dec0a16..370b3d2bba37 100644
--- a/include/linux/dma-fence-array.h
+++ b/include/linux/dma-fence-array.h
@@ -38,7 +38,6 @@ struct dma_fence_array_cb {
struct dma_fence_array {
struct dma_fence base;
- spinlock_t lock;
unsigned num_fences;
atomic_t num_pending;
struct dma_fence **fences;
--
2.43.0
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH 8/8] dma-buf: use inline lock for the dma-fence-chain
[not found] <20260219160822.1529-1-christian.koenig@amd.com>
` (6 preceding siblings ...)
2026-02-19 16:07 ` [PATCH 7/8] dma-buf: use inline lock for the dma-fence-array Christian König
@ 2026-02-19 16:07 ` Christian König
7 siblings, 0 replies; 11+ messages in thread
From: Christian König @ 2026-02-19 16:07 UTC (permalink / raw)
To: phasta, matthew.brost, sumit.semwal; +Cc: dri-devel, linaro-mm-sig
Using the inline lock is now the recommended way for dma_fence
implementations.
So use this approach for the framework's internal fences as well.
Also saves about 4 bytes for the external spinlock.
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>
---
drivers/dma-buf/dma-fence-chain.c | 3 +--
include/linux/dma-fence-chain.h | 1 -
2 files changed, 1 insertion(+), 3 deletions(-)
diff --git a/drivers/dma-buf/dma-fence-chain.c b/drivers/dma-buf/dma-fence-chain.c
index a8a90acf4f34..a707792b6025 100644
--- a/drivers/dma-buf/dma-fence-chain.c
+++ b/drivers/dma-buf/dma-fence-chain.c
@@ -245,7 +245,6 @@ void dma_fence_chain_init(struct dma_fence_chain *chain,
struct dma_fence_chain *prev_chain = to_dma_fence_chain(prev);
uint64_t context;
- spin_lock_init(&chain->lock);
rcu_assign_pointer(chain->prev, prev);
chain->fence = fence;
chain->prev_seqno = 0;
@@ -261,7 +260,7 @@ void dma_fence_chain_init(struct dma_fence_chain *chain,
seqno = max(prev->seqno, seqno);
}
- dma_fence_init64(&chain->base, &dma_fence_chain_ops, &chain->lock,
+ dma_fence_init64(&chain->base, &dma_fence_chain_ops, NULL,
context, seqno);
/*
diff --git a/include/linux/dma-fence-chain.h b/include/linux/dma-fence-chain.h
index 68c3c1e41014..d39ce7a2e599 100644
--- a/include/linux/dma-fence-chain.h
+++ b/include/linux/dma-fence-chain.h
@@ -46,7 +46,6 @@ struct dma_fence_chain {
*/
struct irq_work work;
};
- spinlock_t lock;
};
--
2.43.0
^ permalink raw reply related [flat|nested] 11+ messages in thread