From: Rob Clark <robdcl...@chromium.org>

For errors after msm_submitqueue_get(), we need to drop the submitqueue
reference.  Additionally after get_unused_fd() we need to drop the fd.
The ordering for dropping the queue lock and put_unused_fd() is not
important, so just move this all into out_post_unlock.

v2: Only drop queue ref if submit doesn't take it
v3: Fix unitialized submit ref in error path
v4: IS_ERR_OR_NULL()

Reported-by: pinkperfect2...@gmail.com
Fixes: f0de40a131d9 drm/msm: ("Reorder lock vs submit alloc")
Signed-off-by: Rob Clark <robdcl...@chromium.org>
---
 drivers/gpu/drm/msm/msm_gem_submit.c | 25 ++++++++++++++++++-------
 1 file changed, 18 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c 
b/drivers/gpu/drm/msm/msm_gem_submit.c
index 6c6aefaa72be..8a3c9246ebf7 100644
--- a/drivers/gpu/drm/msm/msm_gem_submit.c
+++ b/drivers/gpu/drm/msm/msm_gem_submit.c
@@ -720,21 +720,21 @@ static void msm_process_post_deps(struct 
msm_submit_post_dep *post_deps,
                }
        }
 }
 
 int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
                struct drm_file *file)
 {
        struct msm_drm_private *priv = dev->dev_private;
        struct drm_msm_gem_submit *args = data;
        struct msm_file_private *ctx = file->driver_priv;
-       struct msm_gem_submit *submit;
+       struct msm_gem_submit *submit = NULL;
        struct msm_gpu *gpu = priv->gpu;
        struct msm_gpu_submitqueue *queue;
        struct msm_ringbuffer *ring;
        struct msm_submit_post_dep *post_deps = NULL;
        struct drm_syncobj **syncobjs_to_reset = NULL;
        int out_fence_fd = -1;
        bool has_ww_ticket = false;
        unsigned i;
        int ret;
 
@@ -767,27 +767,29 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void 
*data,
        queue = msm_submitqueue_get(ctx, args->queueid);
        if (!queue)
                return -ENOENT;
 
        ring = gpu->rb[queue->ring_nr];
 
        if (args->flags & MSM_SUBMIT_FENCE_FD_OUT) {
                out_fence_fd = get_unused_fd_flags(O_CLOEXEC);
                if (out_fence_fd < 0) {
                        ret = out_fence_fd;
-                       return ret;
+                       goto out_post_unlock;
                }
        }
 
        submit = submit_create(dev, gpu, queue, args->nr_bos, args->nr_cmds);
-       if (IS_ERR(submit))
-               return PTR_ERR(submit);
+       if (IS_ERR(submit)) {
+               ret = PTR_ERR(submit);
+               goto out_post_unlock;
+       }
 
        trace_msm_gpu_submit(pid_nr(submit->pid), ring->id, submit->ident,
                args->nr_bos, args->nr_cmds);
 
        ret = mutex_lock_interruptible(&queue->lock);
        if (ret)
                goto out_post_unlock;
 
        if (args->flags & MSM_SUBMIT_SUDO)
                submit->in_rb = true;
@@ -962,25 +964,34 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void 
*data,
        msm_reset_syncobjs(syncobjs_to_reset, args->nr_in_syncobjs);
        msm_process_post_deps(post_deps, args->nr_out_syncobjs,
                              submit->user_fence);
 
 
 out:
        submit_cleanup(submit, !!ret);
        if (has_ww_ticket)
                ww_acquire_fini(&submit->ticket);
 out_unlock:
-       if (ret && (out_fence_fd >= 0))
-               put_unused_fd(out_fence_fd);
        mutex_unlock(&queue->lock);
 out_post_unlock:
-       msm_gem_submit_put(submit);
+       if (ret && (out_fence_fd >= 0))
+               put_unused_fd(out_fence_fd);
+
+       if (!IS_ERR_OR_NULL(submit)) {
+               msm_gem_submit_put(submit);
+       } else {
+               /*
+                * If the submit hasn't yet taken ownership of the queue
+                * then we need to drop the reference ourself:
+                */
+               msm_submitqueue_put(queue);
+       }
        if (!IS_ERR_OR_NULL(post_deps)) {
                for (i = 0; i < args->nr_out_syncobjs; ++i) {
                        kfree(post_deps[i].chain);
                        drm_syncobj_put(post_deps[i].syncobj);
                }
                kfree(post_deps);
        }
 
        if (!IS_ERR_OR_NULL(syncobjs_to_reset)) {
                for (i = 0; i < args->nr_in_syncobjs; ++i) {
-- 
2.40.1

Reply via email to