Browse Source

Merge "msm: camera: reqmgr: Prevent session deadlock" into camera-kernel.lnx.5.0

Camera Software Integration 3 years ago
parent
commit
6f1081755e
1 changed files with 21 additions and 13 deletions
  1. 21 13
      drivers/cam_req_mgr/cam_req_mgr_core.c

+ 21 - 13
drivers/cam_req_mgr/cam_req_mgr_core.c

@@ -1424,20 +1424,20 @@ static int __cam_req_mgr_process_req(struct cam_req_mgr_core_link *link,
 		return -EINVAL;
 	}
 
+	mutex_lock(&session->lock);
 	/*
-	 * In case if the wq is scheduled while destroying session
-	 * the session mutex is already taken and will cause a
-	 * dead lock. To avoid further processing check link state
-	 * and exit.
+	 * During session destroy/unlink the link state is updated and session
+	 * mutex is released when flushing the workq. In case the wq is scheduled
+	 * thereafter this API will then check the updated link state and exit
 	 */
 	spin_lock_bh(&link->link_state_spin_lock);
 	if (link->state == CAM_CRM_LINK_STATE_IDLE) {
 		spin_unlock_bh(&link->link_state_spin_lock);
+		mutex_unlock(&session->lock);
 		return -EPERM;
 	}
 	spin_unlock_bh(&link->link_state_spin_lock);
 
-	mutex_lock(&session->lock);
 	in_q = link->req.in_q;
 	/*
 	 * Check if new read index,
@@ -4460,13 +4460,17 @@ end:
 /**
  * __cam_req_mgr_unlink()
  *
- * @brief : Unlink devices on a link structure from the session
- * @link  : Pointer to the link structure
+ * @brief  : Unlink devices on a link structure from the session
+ *           This API is to be invoked with session mutex held
+ * @session: session of the link
+ * @link   : Pointer to the link structure
  *
  * @return: 0 for success, negative for failure
  *
  */
-static int __cam_req_mgr_unlink(struct cam_req_mgr_core_link *link)
+static int __cam_req_mgr_unlink(
+	struct cam_req_mgr_core_session *session,
+	struct cam_req_mgr_core_link *link)
 {
 	int rc;
 
@@ -4482,14 +4486,16 @@ static int __cam_req_mgr_unlink(struct cam_req_mgr_core_link *link)
 	}
 
 	mutex_lock(&link->lock);
-
 	spin_lock_bh(&link->link_state_spin_lock);
 	/* Destroy timer of link */
 	crm_timer_exit(&link->watchdog);
 	spin_unlock_bh(&link->link_state_spin_lock);
+	/* Release session mutex for workq processing */
+	mutex_unlock(&session->lock);
 	/* Destroy workq of link */
 	cam_req_mgr_workq_destroy(&link->workq);
-
+	/* Acquire session mutex after workq flush */
+	mutex_lock(&session->lock);
 	/* Cleanup request tables and unlink devices */
 	__cam_req_mgr_destroy_link_info(link);
 	/* Free memory holding data of linked devs */
@@ -4531,6 +4537,7 @@ int cam_req_mgr_destroy_session(
 		goto end;
 
 	}
+
 	mutex_lock(&cam_session->lock);
 	if (cam_session->num_links) {
 		CAM_DBG(CAM_CRM, "destroy session %x num_active_links %d",
@@ -4546,7 +4553,7 @@ int cam_req_mgr_destroy_session(
 				link->link_hdl);
 			/* Ignore return value since session is going away */
 			link->is_shutdown = is_shutdown;
-			__cam_req_mgr_unlink(link);
+			__cam_req_mgr_unlink(cam_session, link);
 			__cam_req_mgr_free_link(link);
 		}
 	}
@@ -4829,8 +4836,9 @@ int cam_req_mgr_unlink(struct cam_req_mgr_unlink_info *unlink_info)
 		rc = -EINVAL;
 		goto done;
 	}
-
-	rc = __cam_req_mgr_unlink(link);
+	mutex_lock(&cam_session->lock);
+	rc = __cam_req_mgr_unlink(cam_session, link);
+	mutex_unlock(&cam_session->lock);
 
 	/* Free curent link and put back into session's free pool of links */
 	__cam_req_mgr_unreserve_link(cam_session, link);