Переглянути джерело

Merge "msm: camera: reqmgr: Fix pagefault in workqueue get task" into camera-kernel.lnx.5.0

Camera Software Integration 3 роки тому
батько
коміт
cea86bb84b
1 змінених файлів з 35 додано та 27 видалено
  1. 35 27
      drivers/cam_req_mgr/cam_req_mgr_workq.c

+ 35 - 27
drivers/cam_req_mgr/cam_req_mgr_workq.c

@@ -153,21 +153,17 @@ int cam_req_mgr_workq_enqueue_task(struct crm_workq_task *task,
 
 	if (!task) {
 		CAM_WARN(CAM_CRM, "NULL task pointer can not schedule");
-		rc = -EINVAL;
-		goto end;
+		return -EINVAL;
 	}
 	workq = (struct cam_req_mgr_core_workq *)task->parent;
 	if (!workq) {
 		CAM_DBG(CAM_CRM, "NULL workq pointer suspect mem corruption");
-		rc = -EINVAL;
-		goto end;
+		return -EINVAL;
 	}
 
 	if (task->cancel == 1 || atomic_read(&workq->flush)) {
-		cam_req_mgr_workq_put_task(task);
-		CAM_INFO(CAM_CRM, "task aborted and queued back to pool");
 		rc = 0;
-		goto end;
+		goto abort;
 	}
 	task->priv = priv;
 	task->priority =
@@ -175,11 +171,11 @@ int cam_req_mgr_workq_enqueue_task(struct crm_workq_task *task,
 		? prio : CRM_TASK_PRIORITY_0;
 
 	WORKQ_ACQUIRE_LOCK(workq, flags);
-		if (!workq->job) {
-			rc = -EINVAL;
-			WORKQ_RELEASE_LOCK(workq, flags);
-			goto end;
-		}
+	if (!workq->job) {
+		rc = -EINVAL;
+		WORKQ_RELEASE_LOCK(workq, flags);
+		goto abort;
+	}
 
 	list_add_tail(&task->entry,
 		&workq->task.process_head[task->priority]);
@@ -191,7 +187,11 @@ int cam_req_mgr_workq_enqueue_task(struct crm_workq_task *task,
 	workq->workq_scheduled_ts = ktime_get();
 	queue_work(workq->job, &workq->work);
 	WORKQ_RELEASE_LOCK(workq, flags);
-end:
+
+	return rc;
+abort:
+	cam_req_mgr_workq_put_task(task);
+	CAM_INFO(CAM_CRM, "task aborted and queued back to pool");
 	return rc;
 }
 
@@ -271,24 +271,32 @@ void cam_req_mgr_workq_destroy(struct cam_req_mgr_core_workq **crm_workq)
 {
 	unsigned long flags = 0;
 	struct workqueue_struct   *job;
+	struct cam_req_mgr_core_workq *workq;
+	int i;
 
-	CAM_DBG(CAM_CRM, "destroy workque %pK", crm_workq);
-	if (*crm_workq) {
-		WORKQ_ACQUIRE_LOCK(*crm_workq, flags);
-		if ((*crm_workq)->job) {
-			job = (*crm_workq)->job;
-			(*crm_workq)->job = NULL;
-			WORKQ_RELEASE_LOCK(*crm_workq, flags);
+	if (crm_workq && *crm_workq) {
+		workq = *crm_workq;
+		CAM_DBG(CAM_CRM, "destroy workque %s", workq->workq_name);
+		WORKQ_ACQUIRE_LOCK(workq, flags);
+		/* prevent any processing of callbacks */
+		atomic_set(&workq->flush, 1);
+		if (workq->job) {
+			job = workq->job;
+			workq->job = NULL;
+			WORKQ_RELEASE_LOCK(workq, flags);
 			destroy_workqueue(job);
-		} else {
-			WORKQ_RELEASE_LOCK(*crm_workq, flags);
+			WORKQ_ACQUIRE_LOCK(workq, flags);
 		}
-
 		/* Destroy workq payload data */
-		kfree((*crm_workq)->task.pool[0].payload);
-		(*crm_workq)->task.pool[0].payload = NULL;
-		kfree((*crm_workq)->task.pool);
-		kfree(*crm_workq);
+		kfree(workq->task.pool[0].payload);
+		kfree(workq->task.pool);
+
+		/* Leave lists in stable state after freeing pool */
+		INIT_LIST_HEAD(&workq->task.empty_head);
+		for (i = 0; i < CRM_TASK_PRIORITY_MAX; i++)
+			INIT_LIST_HEAD(&workq->task.process_head[i]);
 		*crm_workq = NULL;
+		WORKQ_RELEASE_LOCK(workq, flags);
+		kfree(workq);
 	}
 }