diff options
Diffstat (limited to '0001-nouveau-fix-client-work-fence-deletion-race.patch')
-rw-r--r-- | 0001-nouveau-fix-client-work-fence-deletion-race.patch | 55 |
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 + |