Skip to content

Commit 11e451e

Browse files
author
Ben Skeggs
committed
drm/nouveau: remove fence wait code from deferred client work handler
Fences attached to deferred client work items now originate from channels belonging to the client, meaning we can be certain they've been signalled before we destroy a client. This closes a race that could happen if the dma_fence_wait_timeout() call didn't succeed. When the fence was later signalled, a use-after-free was possible. Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
1 parent 470db8b commit 11e451e

File tree

1 file changed

+14
-16
lines changed

1 file changed

+14
-16
lines changed

drivers/gpu/drm/nouveau/nouveau_drm.c

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -113,24 +113,22 @@ nouveau_name(struct drm_device *dev)
113113
}
114114

115115
static inline bool
116-
nouveau_cli_work_ready(struct dma_fence *fence, bool wait)
116+
nouveau_cli_work_ready(struct dma_fence *fence)
117117
{
118-
if (!dma_fence_is_signaled(fence)) {
119-
if (!wait)
120-
return false;
121-
WARN_ON(dma_fence_wait_timeout(fence, false, 2 * HZ) <= 0);
122-
}
118+
if (!dma_fence_is_signaled(fence))
119+
return false;
123120
dma_fence_put(fence);
124121
return true;
125122
}
126123

127124
static void
128-
nouveau_cli_work_flush(struct nouveau_cli *cli, bool wait)
125+
nouveau_cli_work(struct work_struct *w)
129126
{
127+
struct nouveau_cli *cli = container_of(w, typeof(*cli), work);
130128
struct nouveau_cli_work *work, *wtmp;
131129
mutex_lock(&cli->lock);
132130
list_for_each_entry_safe(work, wtmp, &cli->worker, head) {
133-
if (!work->fence || nouveau_cli_work_ready(work->fence, wait)) {
131+
if (!work->fence || nouveau_cli_work_ready(work->fence)) {
134132
list_del(&work->head);
135133
work->func(work);
136134
}
@@ -158,17 +156,17 @@ nouveau_cli_work_queue(struct nouveau_cli *cli, struct dma_fence *fence,
158156
mutex_unlock(&cli->lock);
159157
}
160158

161-
static void
162-
nouveau_cli_work(struct work_struct *w)
163-
{
164-
struct nouveau_cli *cli = container_of(w, typeof(*cli), work);
165-
nouveau_cli_work_flush(cli, false);
166-
}
167-
168159
static void
169160
nouveau_cli_fini(struct nouveau_cli *cli)
170161
{
171-
nouveau_cli_work_flush(cli, true);
162+
/* All our channels are dead now, which means all the fences they
163+
* own are signalled, and all callback functions have been called.
164+
*
165+
* So, after flushing the workqueue, there should be nothing left.
166+
*/
167+
flush_work(&cli->work);
168+
WARN_ON(!list_empty(&cli->worker));
169+
172170
usif_client_fini(cli);
173171
nouveau_vmm_fini(&cli->vmm);
174172
nvif_mmu_fini(&cli->mmu);

0 commit comments

Comments
 (0)