From 0edaeafbfc6d1d8b2fc0e850f7151b090438def3 Mon Sep 17 00:00:00 2001 From: Yu Qiaowei Date: Thu, 2 Nov 2023 16:41:53 +0800 Subject: [PATCH] video: rockchip: rga3: prevent calling mmget()/mmput() in spin_lock Change-Id: Iab49cf67340fa2a476bb5931a927b04f7c8edb01 Signed-off-by: Yu Qiaowei --- drivers/video/rockchip/rga3/rga_job.c | 68 ++++++++++++++++++--------- 1 file changed, 46 insertions(+), 22 deletions(-) diff --git a/drivers/video/rockchip/rga3/rga_job.c b/drivers/video/rockchip/rga3/rga_job.c index f7d9ccc3866f..fae613bbf716 100644 --- a/drivers/video/rockchip/rga3/rga_job.c +++ b/drivers/video/rockchip/rga3/rga_job.c @@ -494,7 +494,7 @@ static bool rga_is_need_current_mm(struct rga_req *req) return false; } -static int rga_request_get_current_mm(struct rga_request *request) +static struct mm_struct *rga_request_get_current_mm(struct rga_request *request) { int i; @@ -502,23 +502,21 @@ static int rga_request_get_current_mm(struct rga_request *request) if (rga_is_need_current_mm(&(request->task_list[i]))) { mmgrab(current->mm); mmget(current->mm); - request->current_mm = current->mm; - break; + return current->mm; } } - return 0; + return NULL; } -static void rga_request_put_current_mm(struct rga_request *request) +static void rga_request_put_current_mm(struct mm_struct *mm) { - if (request->current_mm == NULL) + if (mm == NULL) return; - mmput(request->current_mm); - mmdrop(request->current_mm); - request->current_mm = NULL; + mmput(mm); + mmdrop(mm); } static int rga_request_add_acquire_fence_callback(int acquire_fence_fd, @@ -695,6 +693,7 @@ static int rga_request_scheduler_job_abort(struct rga_request *request) static void rga_request_release_abort(struct rga_request *request, int err_code) { unsigned long flags; + struct mm_struct *current_mm; struct rga_pending_request_manager *request_manager = rga_drvdata->pend_request_manager; if (rga_request_scheduler_job_abort(request) > 0) @@ -709,11 +708,13 @@ static void rga_request_release_abort(struct rga_request *request, int err_code) request->is_running = false; request->is_done = false; - - rga_request_put_current_mm(request); + current_mm = request->current_mm; + request->current_mm = NULL; spin_unlock_irqrestore(&request->lock, flags); + rga_request_put_current_mm(current_mm); + rga_dma_fence_signal(request->release_fence, err_code); mutex_lock(&request_manager->lock); @@ -852,6 +853,7 @@ static void rga_request_acquire_fence_signaled_cb(struct dma_fence *fence, { int ret; unsigned long flags; + struct mm_struct *current_mm; struct rga_fence_waiter *waiter = (struct rga_fence_waiter *)_waiter; struct rga_request *request = (struct rga_request *)waiter->private; struct rga_pending_request_manager *request_manager = rga_drvdata->pend_request_manager; @@ -861,10 +863,15 @@ static void rga_request_acquire_fence_signaled_cb(struct dma_fence *fence, pr_err("acquire_fence callback: rga request[%d] commit failed!\n", request->id); spin_lock_irqsave(&request->lock, flags); - rga_request_put_current_mm(request); + request->is_running = false; + current_mm = request->current_mm; + request->current_mm = NULL; + spin_unlock_irqrestore(&request->lock, flags); + rga_request_put_current_mm(current_mm); + /* * Since the callback is called while holding &dma_fence.lock, * the _locked API is used here. @@ -884,6 +891,7 @@ int rga_request_release_signal(struct rga_scheduler_t *scheduler, struct rga_job { struct rga_pending_request_manager *request_manager; struct rga_request *request; + struct mm_struct *current_mm; int finished_count, failed_count; bool is_finished = false; unsigned long flags; @@ -925,11 +933,13 @@ int rga_request_release_signal(struct rga_scheduler_t *scheduler, struct rga_job request->is_running = false; request->is_done = true; - - rga_request_put_current_mm(request); + current_mm = request->current_mm; + request->current_mm = NULL; spin_unlock_irqrestore(&request->lock, flags); + rga_request_put_current_mm(current_mm); + rga_dma_fence_signal(request->release_fence, request->ret); is_finished = true; @@ -1089,6 +1099,9 @@ int rga_request_submit(struct rga_request *request) int ret = 0; unsigned long flags; struct dma_fence *release_fence; + struct mm_struct *current_mm; + + current_mm = rga_request_get_current_mm(request); spin_lock_irqsave(&request->lock, flags); @@ -1096,14 +1109,16 @@ int rga_request_submit(struct rga_request *request) spin_unlock_irqrestore(&request->lock, flags); pr_err("can not re-config when request is running\n"); - return -EFAULT; + ret = -EFAULT; + goto err_put_current_mm; } if (request->task_list == NULL) { spin_unlock_irqrestore(&request->lock, flags); pr_err("can not find task list from id[%d]\n", request->id); - return -EINVAL; + ret = -EINVAL; + goto err_put_current_mm; } /* Reset */ @@ -1111,8 +1126,7 @@ int rga_request_submit(struct rga_request *request) request->is_done = false; request->finished_task_count = 0; request->failed_task_count = 0; - - rga_request_get_current_mm(request); + request->current_mm = current_mm; /* Unlock after ensuring that the current request will not be resubmitted. */ spin_unlock_irqrestore(&request->lock, flags); @@ -1122,7 +1136,7 @@ int rga_request_submit(struct rga_request *request) if (IS_ERR(release_fence)) { pr_err("Can not alloc release fence!\n"); ret = IS_ERR(release_fence); - goto error_put_current_mm; + goto err_reset_request; } request->release_fence = release_fence; @@ -1171,14 +1185,17 @@ err_put_release_fence: request->release_fence = NULL; } -error_put_current_mm: +err_reset_request: spin_lock_irqsave(&request->lock, flags); - rga_request_put_current_mm(request); + request->current_mm = NULL; request->is_running = false; spin_unlock_irqrestore(&request->lock, flags); +err_put_current_mm: + rga_request_put_current_mm(current_mm); + return ret; } @@ -1267,6 +1284,7 @@ int rga_request_free(struct rga_request *request) static void rga_request_kref_release(struct kref *ref) { struct rga_request *request; + struct mm_struct *current_mm; unsigned long flags; request = container_of(ref, struct rga_request, refcount); @@ -1276,16 +1294,22 @@ static void rga_request_kref_release(struct kref *ref) spin_lock_irqsave(&request->lock, flags); - rga_request_put_current_mm(request); rga_dma_fence_put(request->release_fence); + current_mm = request->current_mm; + request->current_mm = NULL; if (!request->is_running || request->is_done) { spin_unlock_irqrestore(&request->lock, flags); + + rga_request_put_current_mm(current_mm); + goto free_request; } spin_unlock_irqrestore(&request->lock, flags); + rga_request_put_current_mm(current_mm); + rga_request_scheduler_job_abort(request); free_request: