smcinvoke: implement retry and timeout for CB processing

CB requests are processed by HLOS userspace. It is possible that
userspace never returns with a response. This could cause trusted
environment that initiated CB request to reject processing anymore
non-secure requests. This is not a desirable situation. Hence, adding
timeout functionality along with retry mechanism to send error response
back to trusted env after maximum number of retries are already done and
continue processing requests from non-secure side.

Change-Id: Idbd3048d0b9594c9927d55a24a8ca77e14214746
Signed-off-by: Anmolpreet Kaur <anmolpre@codeaurora.org>
This commit is contained in:
Anmolpreet Kaur 2020-12-14 22:30:02 +05:30
commit e55be43040

View file

@ -61,6 +61,7 @@
*/
#define SMCINVOKE_SERVER_STATE_DEFUNCT 1
#define CBOBJ_MAX_RETRIES 5
#define FOR_ARGS(ndxvar, counts, section) \
for (ndxvar = OBJECT_COUNTS_INDEX_##section(counts); \
ndxvar < (OBJECT_COUNTS_INDEX_##section(counts) \
@ -1002,6 +1003,8 @@ static void process_tzcb_req(void *buf, size_t buf_len, struct file **arr_filp)
{
/* ret is going to TZ. Provide values from OBJECT_ERROR_<> */
int ret = OBJECT_ERROR_DEFUNCT;
int cbobj_retries = 0;
long timeout_jiff;
struct smcinvoke_cb_txn *cb_txn = NULL;
struct smcinvoke_tzcb_req *cb_req = NULL, *tmp_cb_req = NULL;
struct smcinvoke_server_info *srvr_info = NULL;
@ -1079,9 +1082,26 @@ static void process_tzcb_req(void *buf, size_t buf_len, struct file **arr_filp)
* as this CBObj is served by this server, srvr_info will be valid.
*/
wake_up_interruptible_all(&srvr_info->req_wait_q);
ret = wait_event_interruptible(srvr_info->rsp_wait_q,
(cb_txn->state == SMCINVOKE_REQ_PROCESSED) ||
(srvr_info->state == SMCINVOKE_SERVER_STATE_DEFUNCT));
/* timeout before 1s otherwise tzbusy would come */
timeout_jiff = msecs_to_jiffies(1000);
while (cbobj_retries < CBOBJ_MAX_RETRIES) {
ret = wait_event_interruptible_timeout(srvr_info->rsp_wait_q,
(cb_txn->state == SMCINVOKE_REQ_PROCESSED) ||
(srvr_info->state == SMCINVOKE_SERVER_STATE_DEFUNCT),
timeout_jiff);
if (ret == 0) {
pr_err("CBobj timed out cb-tzhandle:%d, retry:%d, op:%d counts :%d\n",
cb_req->hdr.tzhandle, cbobj_retries, cb_req->hdr.op, cb_req->hdr.counts);
pr_err("CBobj %d timedout pid %x,tid %x, srvr state=%d, srvr id:%u\n",
cb_req->hdr.tzhandle, current->pid, current->tgid, srvr_info->state,
srvr_info->server_id);
} else {
break;
}
cbobj_retries++;
}
out:
/*
@ -1091,18 +1111,26 @@ out:
*/
mutex_lock(&g_smcinvoke_lock);
hash_del(&cb_txn->hash);
if (cb_txn->state == SMCINVOKE_REQ_PROCESSED) {
/*
* it is possible that server was killed immediately
* after CB Req was processed but who cares now!
*/
} else if (!srvr_info ||
srvr_info->state == SMCINVOKE_SERVER_STATE_DEFUNCT) {
cb_req->result = OBJECT_ERROR_DEFUNCT;
pr_err("server invalid, res: %d\n", cb_req->result);
} else {
pr_debug("%s wait_event interrupted ret = %d\n", __func__, ret);
if (ret == 0) {
pr_err("CBObj timed out! No more retries\n");
cb_req->result = OBJECT_ERROR_ABORT;
} else if (ret < 0) {
pr_err("wait event interruped, ret: %d\n", ret);
cb_req->result = OBJECT_ERROR_ABORT;
} else {
if (cb_txn->state == SMCINVOKE_REQ_PROCESSED) {
/*
* it is possible that server was killed immediately
* after CB Req was processed but who cares now!
*/
} else if (!srvr_info ||
srvr_info->state == SMCINVOKE_SERVER_STATE_DEFUNCT) {
cb_req->result = OBJECT_ERROR_DEFUNCT;
pr_err("server invalid, res: %d\n", cb_req->result);
} else {
pr_err("%s: unexpected event happened\n", __func__);
cb_req->result = OBJECT_ERROR_ABORT;
}
}
--cb_reqs_inflight;
memcpy(buf, cb_req, buf_len);