amdgpu userq has a userq_mutex meant to protect the list of userqs
and their state.

The CREATE option of the USERQ ioctl released the lock before
performing a last xa_alloc, relying on the xa lock to avoid
races.

The FREE option of the same ioctl didn't use the lock at all.

Acquire and hold the lock in both these cases, to ensure
correct serialization of these ioctl options against each other
and against future ioctl options.

Signed-off-by: David Francis <[email protected]>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
index 3fe10d6af757..cfee7466ef44 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
@@ -748,11 +748,11 @@ amdgpu_userq_create(struct drm_file *filp, union 
drm_amdgpu_userq *args)
        }
 
        atomic_inc(&uq_mgr->userq_count[queue->queue_type]);
-       mutex_unlock(&uq_mgr->userq_mutex);
-
        r = xa_alloc(&uq_mgr->userq_xa, &qid, queue,
                     XA_LIMIT(1, AMDGPU_MAX_USERQ_COUNT),
                     GFP_KERNEL);
+
+       mutex_unlock(&uq_mgr->userq_mutex);
        if (r) {
                /*
                 * This drops the last reference which should take care of
@@ -890,18 +890,17 @@ int amdgpu_userq_ioctl(struct drm_device *dev, void *data,
                if (r)
                        drm_file_err(filp, "Failed to create usermode queue\n");
                break;
-
-       case AMDGPU_USERQ_OP_FREE: {
+       case AMDGPU_USERQ_OP_FREE:
+               mutex_lock(&fpriv->userq_mgr.userq_mutex);
                xa_lock(&fpriv->userq_mgr.userq_xa);
                queue = __xa_erase(&fpriv->userq_mgr.userq_xa, 
args->in.queue_id);
                xa_unlock(&fpriv->userq_mgr.userq_xa);
+               mutex_unlock(&fpriv->userq_mgr.userq_mutex);
                if (!queue)
                        return -ENOENT;
 
                amdgpu_userq_put(queue);
                break;
-       }
-
        default:
                drm_dbg_driver(dev, "Invalid user queue op specified: %d\n", 
args->in.op);
                return -EINVAL;
-- 
2.34.1

Reply via email to