Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bc029f75 authored by Sunil Khatri's avatar Sunil Khatri Committed by Lynus Vaz
Browse files

msm: camera: crm: Clean up the link handles on session destroy



It is possible that while the session is being destroyed, e.g., when
the v4l2 device is closed, the session object has link objects that
have not been unlinked. Clean up all the active link handles when
destroying the session.

Change-Id: Ie213b5fe090fd01ea7d552f534def84161cf3f10
Signed-off-by: default avatarSunil Khatri <sunilkh@codeaurora.org>
Signed-off-by: default avatarLynus Vaz <lvaz@codeaurora.org>
parent 6479e0e4
Loading
Loading
Loading
Loading
+118 −73
Original line number Diff line number Diff line
@@ -1263,45 +1263,71 @@ static struct cam_req_mgr_core_link *__cam_req_mgr_reserve_link(
	return NULL;
}

/*
 * __cam_req_mgr_free_link()
 *
 * @brief: Frees the link and its request queue
 *
 * @link: link identifier
 *
 */
static void __cam_req_mgr_free_link(struct cam_req_mgr_core_link *link)
{
	kfree(link->req.in_q);
	link->req.in_q = NULL;
	kfree(link);
}

/**
 * __cam_req_mgr_unreserve_link()
 *
 * @brief  : Reserves one link data struct within session
 * @brief  : Removes the link data struct from the session and frees it
 * @session: session identifier
 * @link   : link identifier
 *
 */
static void __cam_req_mgr_unreserve_link(
	struct cam_req_mgr_core_session *session,
	struct cam_req_mgr_core_link **link)
	struct cam_req_mgr_core_link *link)
{
	int32_t   i = 0;
	int i;

	if (!session || !*link) {
	if (!session || !link) {
		CAM_ERR(CAM_CRM, "NULL session/link ptr %pK %pK",
			session, *link);
			session, link);
		return;
	}

	mutex_lock(&session->lock);
	if (!session->num_links)
		CAM_WARN(CAM_CRM, "No active link or invalid state %d",
			session->num_links);
	else {
	if (!session->num_links) {
		CAM_WARN(CAM_CRM, "No active link or invalid state: hdl %x",
			link->link_hdl);
		mutex_unlock(&session->lock);
		return;
	}

	for (i = 0; i < MAX_LINKS_PER_SESSION; i++) {
			if (session->links[i] == *link)
		if (session->links[i] == link)
			session->links[i] = NULL;
	}
		session->num_links--;
		CAM_DBG(CAM_CRM, "Active session links (%d)",
			session->num_links);

	if ((session->sync_mode != CAM_REQ_MGR_SYNC_MODE_NO_SYNC) &&
		(link->sync_link)) {
		/*
		 * make sure to unlink sync setup under the assumption
		 * of only having 2 links in a given session
		 */
		session->sync_mode = CAM_REQ_MGR_SYNC_MODE_NO_SYNC;
		for (i = 0; i < MAX_LINKS_PER_SESSION; i++) {
			if (session->links[i])
				session->links[i]->sync_link = NULL;
		}
	}
	kfree((*link)->req.in_q);
	(*link)->req.in_q = NULL;
	kfree(*link);
	*link = NULL;
	mutex_unlock(&session->lock);

	session->num_links--;
	CAM_DBG(CAM_CRM, "Active session links (%d)", session->num_links);
	mutex_unlock(&session->lock);
	__cam_req_mgr_free_link(link);
}

/* Workqueue context processing section */
@@ -2145,11 +2171,63 @@ int cam_req_mgr_create_session(
	return rc;
}

/**
 * __cam_req_mgr_unlink()
 *
 * @brief : Unlink devices on a link structure from the session
 * @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)
{
	int rc;

	mutex_lock(&link->lock);
	spin_lock_bh(&link->link_state_spin_lock);
	link->state = CAM_CRM_LINK_STATE_IDLE;
	spin_unlock_bh(&link->link_state_spin_lock);
	__cam_req_mgr_print_req_tbl(&link->req);

	/* Destroy workq payload data */
	kfree(link->workq->task.pool[0].payload);
	link->workq->task.pool[0].payload = NULL;

	/* Destroy workq and timer of link */
	crm_timer_exit(&link->watchdog);

	cam_req_mgr_workq_destroy(&link->workq);

	/* Cleanup request tables and unlink devices */
	rc = __cam_req_mgr_destroy_link_info(link);
	if (rc) {
		CAM_ERR(CAM_CORE, "Unlink failed. Cannot proceed");
		goto done;
	}

	/* Free memory holding data of linked devs */
	__cam_req_mgr_destroy_subdev(link->l_dev);

	/* Destroy the link handle */
	rc = cam_destroy_device_hdl(link->link_hdl);
	if (rc < 0) {
		CAM_ERR(CAM_CRM, "error while destroying dev handle %d %x",
			rc, link->link_hdl);
	}

done:
	mutex_unlock(&link->lock);
	return rc;
}

int cam_req_mgr_destroy_session(
		struct cam_req_mgr_session_info *ses_info)
{
	int rc;
	int i;
	struct cam_req_mgr_core_session *cam_session = NULL;
	struct cam_req_mgr_core_link *link;

	if (!ses_info) {
		CAM_DBG(CAM_CRM, "NULL session info pointer");
@@ -2167,10 +2245,20 @@ int cam_req_mgr_destroy_session(
	}
	mutex_lock(&cam_session->lock);
	if (cam_session->num_links) {
		CAM_ERR(CAM_CRM, "destroy session %x num_active_links %d",
		CAM_DBG(CAM_CRM, "destroy session %x num_active_links %d",
			ses_info->session_hdl,
			cam_session->num_links);
		/* @TODO : Go through active links and destroy ? */

		for (i = 0; i < MAX_LINKS_PER_SESSION; i++) {
			link = cam_session->links[i];

			if (!link)
				continue;

			/* Ignore return value since session is going away */
			__cam_req_mgr_unlink(link);
			__cam_req_mgr_free_link(link);
		}
	}
	list_del(&cam_session->entry);
	mutex_unlock(&cam_session->lock);
@@ -2286,7 +2374,7 @@ int cam_req_mgr_link(struct cam_req_mgr_link_info *link_info)
	link_info->link_hdl = 0;
link_hdl_fail:
	mutex_unlock(&link->lock);
	__cam_req_mgr_unreserve_link(cam_session, &link);
	__cam_req_mgr_unreserve_link(cam_session, link);
	mutex_unlock(&g_crm_core_dev->crm_lock);
	return rc;
}
@@ -2296,7 +2384,6 @@ int cam_req_mgr_unlink(struct cam_req_mgr_unlink_info *unlink_info)
	int                              rc = 0;
	struct cam_req_mgr_core_session *cam_session;
	struct cam_req_mgr_core_link    *link;
	int                              i;

	if (!unlink_info) {
		CAM_ERR(CAM_CRM, "NULL pointer");
@@ -2319,60 +2406,18 @@ int cam_req_mgr_unlink(struct cam_req_mgr_unlink_info *unlink_info)
	link = cam_get_device_priv(unlink_info->link_hdl);
	if (!link) {
		CAM_ERR(CAM_CRM, "NULL pointer");
		mutex_unlock(&g_crm_core_dev->crm_lock);
		return -EINVAL;
	}

	mutex_lock(&link->lock);
	spin_lock_bh(&link->link_state_spin_lock);
	link->state = CAM_CRM_LINK_STATE_IDLE;
	spin_unlock_bh(&link->link_state_spin_lock);
	__cam_req_mgr_print_req_tbl(&link->req);

	if ((cam_session->sync_mode != CAM_REQ_MGR_SYNC_MODE_NO_SYNC) &&
		(link->sync_link)) {
		/*
		 * make sure to unlink sync setup under the assumption
		 * of only having 2 links in a given session
		 */
		cam_session->sync_mode = CAM_REQ_MGR_SYNC_MODE_NO_SYNC;
		for (i = 0; i < MAX_LINKS_PER_SESSION; i++) {
			if (cam_session->links[i])
				cam_session->links[i]->sync_link = NULL;
		}
	}

	/* Destroy workq payload data */
	kfree(link->workq->task.pool[0].payload);
	link->workq->task.pool[0].payload = NULL;

	/* Destroy workq and timer of link */
	crm_timer_exit(&link->watchdog);

	cam_req_mgr_workq_destroy(&link->workq);

	/* Cleanup request tables and unlink devices */
	rc = __cam_req_mgr_destroy_link_info(link);
	if (rc) {
		CAM_ERR(CAM_CORE, "Unlink failed. Cannot proceed");
		return rc;
		rc = -EINVAL;
		goto done;
	}

	/* Free memory holding data of linked devs */
	__cam_req_mgr_destroy_subdev(link->l_dev);

	/* Destroy the link handle */
	rc = cam_destroy_device_hdl(unlink_info->link_hdl);
	if (rc < 0) {
		CAM_ERR(CAM_CRM, "error while destroying dev handle %d %x",
			rc, link->link_hdl);
	}
	rc = __cam_req_mgr_unlink(link);

	/* Free curent link and put back into session's free pool of links */
	mutex_unlock(&link->lock);
	__cam_req_mgr_unreserve_link(cam_session, &link);
	mutex_unlock(&g_crm_core_dev->crm_lock);
	if (!rc)
		__cam_req_mgr_unreserve_link(cam_session, link);

done:
	mutex_unlock(&g_crm_core_dev->crm_lock);
	return rc;
}