smcinvoke: Make memory objects release inline with callback objects
Release memory object from userspace when a call to release comes in kernel to prevent the memory leaks in the cases where mem objects are passed as a response inside a callback call. Change-Id: I5ce57b6be90e71e255a890895d5f2859312ba1e4 Signed-off-by: Anmolpreet Kaur <quic_anmolpre@quicinc.com>
This commit is contained in:

committato da
Gerrit - the friendly Code Review server

parent
399c8f65d0
commit
b38291450d
@@ -279,6 +279,8 @@ struct smcinvoke_mem_obj {
|
||||
struct list_head list;
|
||||
bool is_smcinvoke_created_shmbridge;
|
||||
uint64_t shmbridge_handle;
|
||||
struct smcinvoke_server_info *server;
|
||||
int32_t mem_obj_user_fd;
|
||||
};
|
||||
|
||||
static LIST_HEAD(g_bridge_postprocess);
|
||||
@@ -404,7 +406,7 @@ static struct smcinvoke_mem_obj *find_mem_obj_locked(uint16_t mem_obj_id,
|
||||
(mem_obj->mem_region_id == mem_obj_id)) ||
|
||||
(!is_mem_rgn_obj &&
|
||||
(mem_obj->mem_map_obj_id == mem_obj_id)))
|
||||
return mem_obj;
|
||||
return mem_obj;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@@ -649,6 +651,7 @@ static inline void free_mem_obj_locked(struct smcinvoke_mem_obj *mem_obj)
|
||||
struct smcinvoke_shmbridge_deregister_pending_list *entry = NULL;
|
||||
|
||||
list_del(&mem_obj->list);
|
||||
kfree(mem_obj->server);
|
||||
kfree(mem_obj);
|
||||
mem_obj = NULL;
|
||||
mutex_unlock(&g_smcinvoke_lock);
|
||||
@@ -732,7 +735,6 @@ static int release_mem_obj_locked(int32_t tzhandle)
|
||||
kref_put(&mem_obj->mem_regn_ref_cnt, del_mem_regn_obj_locked);
|
||||
else
|
||||
kref_put(&mem_obj->mem_map_obj_ref_cnt, del_mem_map_obj_locked);
|
||||
|
||||
return OBJECT_OK;
|
||||
}
|
||||
|
||||
@@ -855,6 +857,8 @@ static struct smcinvoke_cb_txn *find_cbtxn_locked(
|
||||
{
|
||||
int i = 0;
|
||||
struct smcinvoke_cb_txn *cb_txn = NULL;
|
||||
struct smcinvoke_mem_obj *mem_obj = NULL;
|
||||
int32_t tzhandle = 0;
|
||||
|
||||
/*
|
||||
* Since HASH_BITS() does not work on pointers, we can't select hash
|
||||
@@ -864,6 +868,12 @@ static struct smcinvoke_cb_txn *find_cbtxn_locked(
|
||||
/* pick up 1st req */
|
||||
hash_for_each(server->reqs_table, i, cb_txn, hash) {
|
||||
kref_get(&cb_txn->ref_cnt);
|
||||
tzhandle = (cb_txn->cb_req)->hdr.tzhandle;
|
||||
if(TZHANDLE_IS_MEM_OBJ(tzhandle)) {
|
||||
mem_obj= find_mem_obj_locked(TZHANDLE_GET_OBJID(tzhandle),
|
||||
SMCINVOKE_MEM_RGN_OBJ);
|
||||
kref_get(&mem_obj->mem_regn_ref_cnt);
|
||||
}
|
||||
hash_del(&cb_txn->hash);
|
||||
return cb_txn;
|
||||
}
|
||||
@@ -872,6 +882,12 @@ static struct smcinvoke_cb_txn *find_cbtxn_locked(
|
||||
server->responses_table, cb_txn, hash, txn_id) {
|
||||
if (cb_txn->txn_id == txn_id) {
|
||||
kref_get(&cb_txn->ref_cnt);
|
||||
tzhandle = (cb_txn->cb_req)->hdr.tzhandle;
|
||||
if(TZHANDLE_IS_MEM_OBJ(tzhandle)) {
|
||||
mem_obj= find_mem_obj_locked(TZHANDLE_GET_OBJID(tzhandle),
|
||||
SMCINVOKE_MEM_RGN_OBJ);
|
||||
kref_get(&mem_obj->mem_regn_ref_cnt);
|
||||
}
|
||||
hash_del(&cb_txn->hash);
|
||||
return cb_txn;
|
||||
}
|
||||
@@ -952,20 +968,30 @@ static bool is_remote_obj(int32_t uhandle, struct smcinvoke_file_data **tzobj,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int create_mem_obj(struct dma_buf *dma_buf, int32_t *mem_obj)
|
||||
static int create_mem_obj(struct dma_buf *dma_buf, int32_t *mem_obj,
|
||||
int32_t server_id, int32_t user_handle)
|
||||
{
|
||||
struct smcinvoke_mem_obj *t_mem_obj =
|
||||
kzalloc(sizeof(*t_mem_obj), GFP_KERNEL);
|
||||
struct smcinvoke_mem_obj *t_mem_obj = NULL;
|
||||
struct smcinvoke_server_info *server_i = NULL;
|
||||
|
||||
t_mem_obj = kzalloc(sizeof(struct smcinvoke_mem_obj), GFP_KERNEL);
|
||||
if (!t_mem_obj) {
|
||||
dma_buf_put(dma_buf);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
server_i = kzalloc(sizeof(struct smcinvoke_server_info),GFP_KERNEL);
|
||||
if (!server_i) {
|
||||
kfree(t_mem_obj);
|
||||
dma_buf_put(dma_buf);
|
||||
return -ENOMEM;
|
||||
}
|
||||
kref_init(&t_mem_obj->mem_regn_ref_cnt);
|
||||
t_mem_obj->dma_buf = dma_buf;
|
||||
mutex_lock(&g_smcinvoke_lock);
|
||||
t_mem_obj->mem_region_id = next_mem_region_obj_id_locked();
|
||||
server_i->server_id = server_id;
|
||||
t_mem_obj->server = server_i;
|
||||
t_mem_obj->mem_obj_user_fd = user_handle;
|
||||
list_add_tail(&t_mem_obj->list, &g_mem_objs);
|
||||
mutex_unlock(&g_smcinvoke_lock);
|
||||
*mem_obj = TZHANDLE_MAKE_LOCAL(MEM_RGN_SRVR_ID,
|
||||
@@ -1007,7 +1033,8 @@ static int get_tzhandle_from_uhandle(int32_t uhandle, int32_t server_fd,
|
||||
struct smcinvoke_file_data *tzobj = NULL;
|
||||
|
||||
if (is_dma_fd(UHANDLE_GET_FD(uhandle), &dma_buf)) {
|
||||
ret = create_mem_obj(dma_buf, tzhandle);
|
||||
server_id = get_server_id(server_fd);
|
||||
ret = create_mem_obj(dma_buf, tzhandle, server_id, uhandle);
|
||||
} else if (is_remote_obj(UHANDLE_GET_FD(uhandle),
|
||||
&tzobj, filp)) {
|
||||
*tzhandle = tzobj->tzhandle;
|
||||
@@ -1088,8 +1115,7 @@ static int get_uhandle_from_tzhandle(int32_t tzhandle, int32_t srvr_id,
|
||||
if (mem_obj != NULL) {
|
||||
int fd;
|
||||
|
||||
fd = dma_buf_fd(mem_obj->dma_buf, O_CLOEXEC);
|
||||
|
||||
fd = mem_obj->mem_obj_user_fd;
|
||||
if (fd < 0)
|
||||
goto exit_lock;
|
||||
*uhandle = fd;
|
||||
@@ -1380,6 +1406,8 @@ static void process_tzcb_req(void *buf, size_t buf_len, struct file **arr_filp)
|
||||
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;
|
||||
struct smcinvoke_mem_obj *mem_obj = NULL;
|
||||
uint16_t server_id = 0;
|
||||
|
||||
if (buf_len < sizeof(struct smcinvoke_tzcb_req)) {
|
||||
pr_err("smaller buffer length : %u\n", buf_len);
|
||||
@@ -1391,8 +1419,21 @@ static void process_tzcb_req(void *buf, size_t buf_len, struct file **arr_filp)
|
||||
/* check whether it is to be served by kernel or userspace */
|
||||
if (TZHANDLE_IS_KERNEL_OBJ(cb_req->hdr.tzhandle)) {
|
||||
return process_kernel_obj(buf, buf_len);
|
||||
} else if (TZHANDLE_IS_MEM_OBJ(cb_req->hdr.tzhandle)) {
|
||||
} else if (TZHANDLE_IS_MEM_MAP_OBJ(cb_req->hdr.tzhandle)) {
|
||||
/*
|
||||
* MEM_MAP memory object is created and owned by kernel,
|
||||
* hence its processing(handling deletion) is done in
|
||||
* kernel context.
|
||||
*/
|
||||
return process_mem_obj(buf, buf_len);
|
||||
} else if(TZHANDLE_IS_MEM_RGN_OBJ(cb_req->hdr.tzhandle)) {
|
||||
/*
|
||||
* MEM_RGN memory objects are created and owned by userspace,
|
||||
* and hence their deletion/handling requires going back to the
|
||||
* userspace, similar to that of callback objects. If we enter
|
||||
* this 'if' condition, its no-op here, and proceed similar to
|
||||
* case of callback objects.
|
||||
*/
|
||||
} else if (!TZHANDLE_IS_CB_OBJ(cb_req->hdr.tzhandle)) {
|
||||
pr_err("Request object is not a callback object\n");
|
||||
cb_req->result = OBJECT_ERROR_INVALID;
|
||||
@@ -1434,8 +1475,19 @@ static void process_tzcb_req(void *buf, size_t buf_len, struct file **arr_filp)
|
||||
|
||||
mutex_lock(&g_smcinvoke_lock);
|
||||
++cb_reqs_inflight;
|
||||
srvr_info = get_cb_server_locked(
|
||||
TZHANDLE_GET_SERVER(cb_req->hdr.tzhandle));
|
||||
|
||||
if(TZHANDLE_IS_MEM_RGN_OBJ(cb_req->hdr.tzhandle)) {
|
||||
mem_obj= find_mem_obj_locked(TZHANDLE_GET_OBJID(cb_req->hdr.tzhandle),SMCINVOKE_MEM_RGN_OBJ);
|
||||
if(!mem_obj) {
|
||||
pr_err("mem obj with tzhandle : %d not found",cb_req->hdr.tzhandle);
|
||||
goto out;
|
||||
}
|
||||
server_id = mem_obj->server->server_id;
|
||||
} else {
|
||||
server_id = TZHANDLE_GET_SERVER(cb_req->hdr.tzhandle);
|
||||
}
|
||||
|
||||
srvr_info = get_cb_server_locked(server_id);
|
||||
if (!srvr_info || srvr_info->state == SMCINVOKE_SERVER_STATE_DEFUNCT) {
|
||||
/* ret equals Object_ERROR_DEFUNCT, at this point go to out */
|
||||
if (!srvr_info)
|
||||
@@ -1532,6 +1584,13 @@ out:
|
||||
cb_req->hdr.counts, cb_reqs_inflight);
|
||||
|
||||
memcpy(buf, cb_req, buf_len);
|
||||
|
||||
if (TZHANDLE_IS_MEM_RGN_OBJ(cb_req->hdr.tzhandle)) {
|
||||
mutex_unlock(&g_smcinvoke_lock);
|
||||
process_mem_obj(buf, buf_len);
|
||||
pr_err("ppid : %x, mem obj deleted\n", current->pid);
|
||||
mutex_lock(&g_smcinvoke_lock);
|
||||
}
|
||||
kref_put(&cb_txn->ref_cnt, delete_cb_txn_locked);
|
||||
if (srvr_info)
|
||||
kref_put(&srvr_info->ref_cnt, destroy_cb_server);
|
||||
@@ -2153,6 +2212,7 @@ static long process_accept_req(struct file *filp, unsigned int cmd,
|
||||
|
||||
cb_txn->state = SMCINVOKE_REQ_PROCESSED;
|
||||
mutex_lock(&g_smcinvoke_lock);
|
||||
|
||||
kref_put(&cb_txn->ref_cnt, delete_cb_txn_locked);
|
||||
mutex_unlock(&g_smcinvoke_lock);
|
||||
wake_up(&server_info->rsp_wait_q);
|
||||
|
Fai riferimento in un nuovo problema
Block a user