summarylogtreecommitdiffstats
path: root/0001-nouveau-fix-client-work-fence-deletion-race.patch
diff options
context:
space:
mode:
Diffstat (limited to '0001-nouveau-fix-client-work-fence-deletion-race.patch')
-rw-r--r--0001-nouveau-fix-client-work-fence-deletion-race.patch55
1 files changed, 55 insertions, 0 deletions
diff --git a/0001-nouveau-fix-client-work-fence-deletion-race.patch b/0001-nouveau-fix-client-work-fence-deletion-race.patch
new file mode 100644
index 000000000000..c5073038f440
--- /dev/null
+++ b/0001-nouveau-fix-client-work-fence-deletion-race.patch
@@ -0,0 +1,55 @@
+From 0138bee3c72c96d6aaedce02f5691730ec81571d Mon Sep 17 00:00:00 2001
+From: Dave Airlie <airlied@redhat.com>
+Date: Thu, 15 Jun 2023 12:22:11 +1000
+Subject: [PATCH] nouveau: fix client work fence deletion race
+
+This seems to have existed for ever but is now more apparant after
+9bff18d13473a9fdf81d5158248472a9d8ecf2bd (drm/ttm: use per BO cleanup workers)
+
+My analysis:
+two threads are running,
+one in the irq signalling the fence, in dma_fence_signal_timestamp_locked,
+it has done the DMA_FENCE_FLAG_SIGNALLED_BIT setting, but hasn't yet reached the callbacks.
+
+second thread in nouveau_cli_work_ready, where it sees the fence is signalled, so then puts the
+fence, cleanups the object and frees the work item, which contains the callback.
+
+thread one goes again and tries to call the callback and causes the use-after-free.
+
+Proposed fix:
+lock the fence signalled check in nouveau_cli_work_ready, so either the callbacks are done
+or the memory is freed.
+
+Signed-off-by: Dave Airlie <airlied@redhat.com>
+---
+ drivers/gpu/drm/nouveau/nouveau_drm.c | 14 ++++++++++----
+ 1 file changed, 10 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c
+index cc7c5b4a05fd..1a45be769848 100644
+--- a/drivers/gpu/drm/nouveau/nouveau_drm.c
++++ b/drivers/gpu/drm/nouveau/nouveau_drm.c
+@@ -137,10 +137,16 @@ nouveau_name(struct drm_device *dev)
+ static inline bool
+ nouveau_cli_work_ready(struct dma_fence *fence)
+ {
+- if (!dma_fence_is_signaled(fence))
+- return false;
+- dma_fence_put(fence);
+- return true;
++ unsigned long flags;
++ bool ret = true;
++ spin_lock_irqsave(fence->lock, flags);
++ if (!dma_fence_is_signaled_locked(fence))
++ ret = false;
++ spin_unlock_irqrestore(fence->lock, flags);
++
++ if (ret == true)
++ dma_fence_put(fence);
++ return ret;
+ }
+
+ static void
+--
+2.40.1
+