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

Commit 89656063 authored by Zhen Kong's avatar Zhen Kong
Browse files

qseecom: abort all listener threads before listener unregistration



Wake up and abort all busy listener processing threads before listener
unregistration, then to avoid deadlock between listener unregistration
and listener processing threads, as mutex may be hold by another busy
listener thread when qseecom gets a listener unregistration request or
qseecom daemon is dead.

Change-Id: I6b6ddb34eb6bcff763e3d13f026c4b2f4bcb32a9
Signed-off-by: default avatarZhen Kong <zkong@codeaurora.org>
parent 9ea664bf
Loading
Loading
Loading
Loading
+80 −81
Original line number Diff line number Diff line
@@ -198,6 +198,7 @@ struct qseecom_registered_listener_list {
	wait_queue_head_t          listener_block_app_wq;
	struct sglist_info sglistinfo_ptr[MAX_ION_FD];
	uint32_t sglist_cnt;
	int abort;
};

struct qseecom_registered_app_list {
@@ -1367,6 +1368,23 @@ static int qseecom_register_listener(struct qseecom_dev_handle *data,
	return ret;
}

static void __qseecom_listener_abort_all(int abort)
{
	struct qseecom_registered_listener_list *entry = NULL;
	unsigned long flags;

	spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
	list_for_each_entry(entry,
			&qseecom.registered_listener_list_head, list) {
		pr_debug("set abort %d for listener %d\n",
				abort, entry->svc.listener_id);
		entry->abort = abort;
	}
	if (abort)
		wake_up_interruptible_all(&qseecom.send_resp_wq);
	spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
}

static int qseecom_unregister_listener(struct qseecom_dev_handle *data)
{
	int ret = 0;
@@ -1399,6 +1417,7 @@ static int qseecom_unregister_listener(struct qseecom_dev_handle *data)
	}

	data->abort = 1;
	ptr_svc->abort = 1;
	wake_up_all(&ptr_svc->rcv_req_wq);

	while (atomic_read(&data->ioctl_count) > 1) {
@@ -1718,12 +1737,13 @@ static int qseecom_set_client_mem_param(struct qseecom_dev_handle *data,
	return ret;
}

static int __qseecom_listener_has_sent_rsp(struct qseecom_dev_handle *data)
static int __qseecom_listener_has_sent_rsp(struct qseecom_dev_handle *data,
			struct qseecom_registered_listener_list *ptr_svc)
{
	int ret;

	ret = (qseecom.send_resp_flag != 0);
	return ret || data->abort;
	return ret || data->abort || ptr_svc->abort;
}

static int __qseecom_reentrancy_listener_has_sent_rsp(
@@ -1733,62 +1753,7 @@ static int __qseecom_reentrancy_listener_has_sent_rsp(
	int ret;

	ret = (ptr_svc->send_resp_flag != 0);
	return ret || data->abort;
}

static int __qseecom_qseos_fail_return_resp_tz(struct qseecom_dev_handle *data,
					struct qseecom_command_scm_resp *resp,
			struct qseecom_client_listener_data_irsp *send_data_rsp,
			struct qseecom_registered_listener_list *ptr_svc,
							uint32_t lstnr)
{
	int ret = 0;

	send_data_rsp->status = QSEOS_RESULT_FAILURE;
	qseecom.send_resp_flag = 0;
	send_data_rsp->qsee_cmd_id = QSEOS_LISTENER_DATA_RSP_COMMAND;
	send_data_rsp->listener_id = lstnr;
	if (ptr_svc)
		pr_warn("listener_id:%x, lstnr: %x\n",
					ptr_svc->svc.listener_id, lstnr);
	if (lstnr == RPMB_SERVICE) {
		ret = __qseecom_enable_clk(CLK_QSEE);
		if (ret)
			return ret;
	}

	if (ptr_svc && ptr_svc->dmabuf) {
		ret = qseecom_dmabuf_cache_operations(ptr_svc->dmabuf,
						QSEECOM_CACHE_CLEAN);
		if (ret)
			goto exit;
	}
	ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, send_data_rsp,
				sizeof(send_data_rsp), resp, sizeof(*resp));
	if (ret) {
		pr_err("scm_call() failed with err: %d (app_id = %d)\n",
						ret, data->client.app_id);
		goto exit;
	}

	if (ptr_svc && ptr_svc->dmabuf) {
		ret = qseecom_dmabuf_cache_operations(ptr_svc->dmabuf,
						QSEECOM_CACHE_INVALIDATE);
		if (ret)
			goto exit;
	}

	if ((resp->result != QSEOS_RESULT_SUCCESS) &&
			(resp->result != QSEOS_RESULT_INCOMPLETE)) {
		pr_err("fail:resp res= %d,app_id = %d,lstr = %d\n",
				resp->result, data->client.app_id, lstnr);
		ret = -EINVAL;
	}
exit:
	if (lstnr == RPMB_SERVICE)
		__qseecom_disable_clk(CLK_QSEE);

	return ret;
	return ret || data->abort || ptr_svc->abort;
}

static void __qseecom_clean_listener_sglistinfo(
@@ -1839,23 +1804,33 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,

		if (ptr_svc == NULL) {
			pr_err("Listener Svc %d does not exist\n", lstnr);
			__qseecom_qseos_fail_return_resp_tz(data, resp,
					&send_data_rsp, ptr_svc, lstnr);
			return -EINVAL;
			rc = -EINVAL;
			status = QSEOS_RESULT_FAILURE;
			goto err_resp;
		}

		if (!ptr_svc->dmabuf) {
			pr_err("Client dmabuf is not initialized\n");
			__qseecom_qseos_fail_return_resp_tz(data, resp,
					&send_data_rsp, ptr_svc, lstnr);
			return -EINVAL;
			rc = -EINVAL;
			status = QSEOS_RESULT_FAILURE;
			goto err_resp;
		}

		if (ptr_svc->svc.listener_id != lstnr) {
			pr_warn("Service requested does not exist\n");
			__qseecom_qseos_fail_return_resp_tz(data, resp,
					&send_data_rsp, NULL, lstnr);
			return -ERESTARTSYS;
			pr_err("Service %d does not exist\n",
						lstnr);
			rc = -ERESTARTSYS;
			ptr_svc = NULL;
			status = QSEOS_RESULT_FAILURE;
			goto err_resp;
		}

		if (ptr_svc->abort == 1) {
			pr_err("Service %d abort %d\n",
						lstnr, ptr_svc->abort);
			rc = -ENODEV;
			status = QSEOS_RESULT_FAILURE;
			goto err_resp;
		}
		pr_debug("waking up rcv_req_wq and waiting for send_resp_wq\n");

@@ -1872,7 +1847,8 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
			 */
			if (!qseecom.qsee_reentrancy_support &&
				!wait_event_freezable(qseecom.send_resp_wq,
				__qseecom_listener_has_sent_rsp(data))) {
				__qseecom_listener_has_sent_rsp(
						data, ptr_svc))) {
				break;
			}

@@ -1886,7 +1862,7 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,

		/* restore signal mask */
		sigprocmask(SIG_SETMASK, &old_sigset, NULL);
		if (data->abort) {
		if (data->abort || ptr_svc->abort) {
			pr_err("Abort clnt %d waiting on lstnr svc %d, ret %d",
				data->client.app_id, lstnr, ret);
			rc = -ENODEV;
@@ -1894,7 +1870,7 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
		} else {
			status = QSEOS_RESULT_SUCCESS;
		}

err_resp:
		qseecom.send_resp_flag = 0;
		ptr_svc->send_resp_flag = 0;
		table = ptr_svc->sglistinfo_ptr;
@@ -1957,6 +1933,8 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
		if (ret)
			return ret;

		pr_debug("resp status %d, res= %d, app_id = %d, lstr = %d\n",
			status, resp->result, data->client.app_id, lstnr);
		if ((resp->result != QSEOS_RESULT_SUCCESS) &&
			(resp->result != QSEOS_RESULT_INCOMPLETE)) {
			pr_err("fail:resp res= %d,app_id = %d,lstr = %d\n",
@@ -2107,7 +2085,7 @@ static int __qseecom_reentrancy_process_incomplete_cmd(
	size_t cmd_len;
	struct sglist_info *table = NULL;

	while (ret == 0 && rc == 0 && resp->result == QSEOS_RESULT_INCOMPLETE) {
	while (ret == 0 && resp->result == QSEOS_RESULT_INCOMPLETE) {
		lstnr = resp->data;
		/*
		 * Wake up blocking lsitener service with the lstnr id
@@ -2128,17 +2106,33 @@ static int __qseecom_reentrancy_process_incomplete_cmd(

		if (ptr_svc == NULL) {
			pr_err("Listener Svc %d does not exist\n", lstnr);
			return -EINVAL;
			rc = -EINVAL;
			status = QSEOS_RESULT_FAILURE;
			goto err_resp;
		}

		if (!ptr_svc->dmabuf) {
			pr_err("Client dmabuf is not initialized\n");
			return -EINVAL;
			rc = -EINVAL;
			status = QSEOS_RESULT_FAILURE;
			goto err_resp;
		}

		if (ptr_svc->svc.listener_id != lstnr) {
			pr_warn("Service requested does not exist\n");
			return -ERESTARTSYS;
			pr_err("Service %d does not exist\n",
						lstnr);
			rc = -ERESTARTSYS;
			ptr_svc = NULL;
			status = QSEOS_RESULT_FAILURE;
			goto err_resp;
		}

		if (ptr_svc->abort == 1) {
			pr_err("Service %d abort %d\n",
						lstnr, ptr_svc->abort);
			rc = -ENODEV;
			status = QSEOS_RESULT_FAILURE;
			goto err_resp;
		}
		pr_debug("waking up rcv_req_wq and waiting for send_resp_wq\n");

@@ -2164,7 +2158,7 @@ static int __qseecom_reentrancy_process_incomplete_cmd(

		/* restore signal mask */
		sigprocmask(SIG_SETMASK, &old_sigset, NULL);
		if (data->abort) {
		if (data->abort || ptr_svc->abort) {
			pr_err("Abort clnt %d waiting on lstnr svc %d, ret %d",
				data->client.app_id, lstnr, ret);
			rc = -ENODEV;
@@ -2172,6 +2166,7 @@ static int __qseecom_reentrancy_process_incomplete_cmd(
		} else {
			status  = QSEOS_RESULT_SUCCESS;
		}
err_resp:
		table = ptr_svc->sglistinfo_ptr;
		if (qseecom.qsee_version < QSEE_VERSION_40) {
			send_data_rsp.listener_id  = lstnr;
@@ -3907,7 +3902,7 @@ static int __qseecom_listener_has_rcvd_req(struct qseecom_dev_handle *data,
	int ret;

	ret = (svc->rcv_req_flag != 0);
	return ret || data->abort;
	return ret || data->abort || svc->abort;
}

static int qseecom_receive_req(struct qseecom_dev_handle *data)
@@ -3931,7 +3926,7 @@ static int qseecom_receive_req(struct qseecom_dev_handle *data)
			return -ERESTARTSYS;
		}

		if (data->abort) {
		if (data->abort || this_lstnr->abort) {
			pr_err("Aborting Listener Service = %d\n",
					(uint32_t)data->listener.id);
			return -ENODEV;
@@ -6189,7 +6184,7 @@ static int qseecom_update_key_user_info(struct qseecom_dev_handle *data,
}
static int qseecom_is_es_activated(void __user *argp)
{
	struct qseecom_is_es_activated_req req;
	struct qseecom_is_es_activated_req req = {0};
	struct qseecom_command_scm_resp resp;
	int ret;

@@ -7012,12 +7007,14 @@ static inline long qseecom_ioctl(struct file *file,
			break;
		}
		pr_debug("ioctl unregister_listener_req()\n");
		__qseecom_listener_abort_all(1);
		mutex_lock(&app_access_lock);
		atomic_inc(&data->ioctl_count);
		ret = qseecom_unregister_listener(data);
		atomic_dec(&data->ioctl_count);
		wake_up_all(&data->abort_wq);
		mutex_unlock(&app_access_lock);
		__qseecom_listener_abort_all(0);
		if (ret)
			pr_err("failed qseecom_unregister_listener: %d\n", ret);
		break;
@@ -7684,9 +7681,11 @@ static int qseecom_release(struct inode *inode, struct file *file)
			data->type, data->mode, data);
		switch (data->type) {
		case QSEECOM_LISTENER_SERVICE:
			__qseecom_listener_abort_all(1);
			mutex_lock(&app_access_lock);
			ret = qseecom_unregister_listener(data);
			mutex_unlock(&app_access_lock);
			__qseecom_listener_abort_all(0);
			break;
		case QSEECOM_CLIENT_APP:
			mutex_lock(&app_access_lock);