lkml.org 
[lkml]   [2018]   [Aug]   [1]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.17 155/336] drm/nouveau: remove fence wait code from deferred client work handler
    Date
    4.17-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Ben Skeggs <bskeggs@redhat.com>

    [ Upstream commit 11e451e74050d9e9030581ce40337838acfcea5b ]

    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>
    Signed-off-by: Sasha Levin <alexander.levin@microsoft.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    ---
    drivers/gpu/drm/nouveau/nouveau_drm.c | 30 ++++++++++++++----------------
    1 file changed, 14 insertions(+), 16 deletions(-)

    --- a/drivers/gpu/drm/nouveau/nouveau_drm.c
    +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c
    @@ -116,24 +116,22 @@ nouveau_name(struct drm_device *dev)
    }

    static inline bool
    -nouveau_cli_work_ready(struct dma_fence *fence, bool wait)
    +nouveau_cli_work_ready(struct dma_fence *fence)
    {
    - if (!dma_fence_is_signaled(fence)) {
    - if (!wait)
    - return false;
    - WARN_ON(dma_fence_wait_timeout(fence, false, 2 * HZ) <= 0);
    - }
    + if (!dma_fence_is_signaled(fence))
    + return false;
    dma_fence_put(fence);
    return true;
    }

    static void
    -nouveau_cli_work_flush(struct nouveau_cli *cli, bool wait)
    +nouveau_cli_work(struct work_struct *w)
    {
    + struct nouveau_cli *cli = container_of(w, typeof(*cli), work);
    struct nouveau_cli_work *work, *wtmp;
    mutex_lock(&cli->lock);
    list_for_each_entry_safe(work, wtmp, &cli->worker, head) {
    - if (!work->fence || nouveau_cli_work_ready(work->fence, wait)) {
    + if (!work->fence || nouveau_cli_work_ready(work->fence)) {
    list_del(&work->head);
    work->func(work);
    }
    @@ -162,16 +160,16 @@ nouveau_cli_work_queue(struct nouveau_cl
    }

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

    \
     
     \ /
      Last update: 2018-08-01 20:21    [W:2.612 / U:0.108 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site