diff --git a/drivers/cam_req_mgr/cam_req_mgr_core.c b/drivers/cam_req_mgr/cam_req_mgr_core.c index 6fe30410fd..f059403030 100644 --- a/drivers/cam_req_mgr/cam_req_mgr_core.c +++ b/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);