summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTharun Kumar Merugu <mtharu@codeaurora.org>2018-05-22 19:33:34 +0530
committerAlexander Grund <flamefire89@gmail.com>2023-12-23 19:22:00 +0100
commit1e0f188773f9c191feaab224a4d4b62c46180b69 (patch)
tree374578f51fa705b2e8ace4b87d5f45b19c2f8d80
parent7af54ebb945341fad6ec21be79a76d1fa3d1cb18 (diff)
msm: adsprpc: Avoid race condition during map creation and free
Avoid race condition among concurrent fastrpc threads while creating and removing memory mappings. Change-Id: Ibf9ab0d4d19137804dbff4237a973895c410330c Acked-by: Thyagarajan Venkatanarayanan <venkatan@qti.qualcomm.com> Signed-off-by: Tharun Kumar Merugu <mtharu@codeaurora.org>
-rw-r--r--drivers/char/adsprpc.c77
1 files changed, 48 insertions, 29 deletions
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index 244ae28757d3..efb40c9ab71a 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -334,6 +334,7 @@ struct fastrpc_file {
struct fastrpc_perf perf;
struct dentry *debugfs_file;
struct mutex map_mutex;
+ struct mutex internal_map_mutex;
char *debug_buf;
/* Identifies the device (MINOR_NUM_DEV / MINOR_NUM_SECURE_DEV) */
int dev_minor;
@@ -467,15 +468,11 @@ static void fastrpc_mmap_add(struct fastrpc_mmap *map)
map->flags == ADSP_MMAP_REMOTE_HEAP_ADDR) {
struct fastrpc_apps *me = &gfa;
- spin_lock(&me->hlock);
hlist_add_head(&map->hn, &me->maps);
- spin_unlock(&me->hlock);
} else {
struct fastrpc_file *fl = map->fl;
- spin_lock(&fl->hlock);
hlist_add_head(&map->hn, &fl->maps);
- spin_unlock(&fl->hlock);
}
}
@@ -490,7 +487,6 @@ static int fastrpc_mmap_find(struct fastrpc_file *fl, int fd, uintptr_t va,
return -EOVERFLOW;
if (mflags == ADSP_MMAP_HEAP_ADDR ||
mflags == ADSP_MMAP_REMOTE_HEAP_ADDR) {
- spin_lock(&me->hlock);
hlist_for_each_entry_safe(map, n, &me->maps, hn) {
if (va >= map->va &&
va + len <= map->va + map->len &&
@@ -504,23 +500,18 @@ static int fastrpc_mmap_find(struct fastrpc_file *fl, int fd, uintptr_t va,
break;
}
}
- spin_unlock(&me->hlock);
} else {
- spin_lock(&fl->hlock);
hlist_for_each_entry_safe(map, n, &fl->maps, hn) {
if (va >= map->va &&
va + len <= map->va + map->len &&
map->fd == fd) {
- if (map->refs + 1 == INT_MAX) {
- spin_unlock(&fl->hlock);
+ if (map->refs + 1 == INT_MAX)
return -ETOOMANYREFS;
- }
map->refs++;
match = map;
break;
}
}
- spin_unlock(&fl->hlock);
}
if (match) {
*ppmap = match;
@@ -556,7 +547,6 @@ static int fastrpc_mmap_remove(struct fastrpc_file *fl, uintptr_t va,
struct hlist_node *n;
struct fastrpc_apps *me = &gfa;
- spin_lock(&me->hlock);
hlist_for_each_entry_safe(map, n, &me->maps, hn) {
if (map->refs == 1 && map->raddr == va &&
map->raddr + map->len == va + len &&
@@ -567,12 +557,10 @@ static int fastrpc_mmap_remove(struct fastrpc_file *fl, uintptr_t va,
break;
}
}
- spin_unlock(&me->hlock);
if (match) {
*ppmap = match;
return 0;
}
- spin_lock(&fl->hlock);
hlist_for_each_entry_safe(map, n, &fl->maps, hn) {
if (map->refs == 1 && map->raddr == va &&
map->raddr + map->len == va + len &&
@@ -583,7 +571,6 @@ static int fastrpc_mmap_remove(struct fastrpc_file *fl, uintptr_t va,
break;
}
}
- spin_unlock(&fl->hlock);
if (match) {
*ppmap = match;
return 0;
@@ -614,17 +601,13 @@ static void fastrpc_mmap_free(struct fastrpc_mmap *map)
}
if (map->flags == ADSP_MMAP_HEAP_ADDR ||
map->flags == ADSP_MMAP_REMOTE_HEAP_ADDR) {
- spin_lock(&me->hlock);
map->refs--;
if (!map->refs)
hlist_del_init(&map->hn);
- spin_unlock(&me->hlock);
} else {
- spin_lock(&fl->hlock);
map->refs--;
if (!map->refs)
hlist_del_init(&map->hn);
- spin_unlock(&fl->hlock);
}
if (map->refs > 0)
return;
@@ -1133,8 +1116,10 @@ static void context_free(struct smq_invoke_ctx *ctx)
spin_lock(&ctx->fl->hlock);
hlist_del_init(&ctx->hn);
spin_unlock(&ctx->fl->hlock);
+ mutex_lock(&ctx->fl->map_mutex);
for (i = 0; i < nbufs; ++i)
fastrpc_mmap_free(ctx->maps[i]);
+ mutex_unlock(&ctx->fl->map_mutex);
fastrpc_buf_free(ctx->buf, 1);
fastrpc_buf_free(ctx->lbuf, 1);
ctx->magic = 0;
@@ -1274,10 +1259,12 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx)
uintptr_t buf = (uintptr_t)lpra[i].buf.pv;
size_t len = lpra[i].buf.len;
+ mutex_lock(&ctx->fl->map_mutex);
if (ctx->fds[i] && (ctx->fds[i] != -1))
fastrpc_mmap_create(ctx->fl, ctx->fds[i],
ctx->attrs[i], buf, len,
mflags, &ctx->maps[i]);
+ mutex_unlock(&ctx->fl->map_mutex);
ipage += 1;
}
metalen = copylen = (size_t)&ipage[0];
@@ -1494,7 +1481,9 @@ static int put_args(uint32_t kernel, struct smq_invoke_ctx *ctx,
if (err)
goto bail;
} else {
+ mutex_lock(&ctx->fl->map_mutex);
fastrpc_mmap_free(ctx->maps[i]);
+ mutex_unlock(&ctx->fl->map_mutex);
ctx->maps[i] = NULL;
}
}
@@ -1903,10 +1892,12 @@ static int fastrpc_init_process(struct fastrpc_file *fl,
init->filelen))
goto bail;
if (init->filelen) {
+ mutex_lock(&fl->map_mutex);
VERIFY(err, !fastrpc_mmap_create(fl, init->filefd, 0,
init->file, init->filelen, mflags, &file));
if (file)
file->is_filemap = true;
+ mutex_unlock(&fl->map_mutex);
if (err)
goto bail;
}
@@ -1996,9 +1987,11 @@ static int fastrpc_init_process(struct fastrpc_file *fl,
inbuf.pageslen = 0;
if (!me->staticpd_flags) {
inbuf.pageslen = 1;
+ mutex_lock(&fl->map_mutex);
VERIFY(err, !fastrpc_mmap_create(fl, -1, 0, init->mem,
init->memlen, ADSP_MMAP_REMOTE_HEAP_ADDR,
&mem));
+ mutex_unlock(&fl->map_mutex);
if (err)
goto bail;
phys = mem->phys;
@@ -2050,10 +2043,15 @@ bail:
if (mem->flags == ADSP_MMAP_REMOTE_HEAP_ADDR)
hyp_assign_phys(mem->phys, (uint64_t)mem->size,
destVM, 1, srcVM, hlosVMperm, 1);
+ mutex_lock(&fl->map_mutex);
fastrpc_mmap_free(mem);
+ mutex_unlock(&fl->map_mutex);
}
- if (file)
+ if (file) {
+ mutex_lock(&fl->map_mutex);
fastrpc_mmap_free(file);
+ mutex_unlock(&fl->map_mutex);
+ }
return err;
}
@@ -2309,7 +2307,7 @@ static int fastrpc_internal_munmap(struct fastrpc_file *fl,
struct fastrpc_buf *rbuf = NULL, *free = NULL;
struct hlist_node *n;
- mutex_lock(&fl->map_mutex);
+ mutex_lock(&fl->internal_map_mutex);
spin_lock(&fl->hlock);
hlist_for_each_entry_safe(rbuf, n, &fl->remote_bufs, hn_rem) {
if (rbuf->raddr && (rbuf->flags == ADSP_MMAP_ADD_PAGES)) {
@@ -2328,11 +2326,13 @@ static int fastrpc_internal_munmap(struct fastrpc_file *fl,
if (err)
goto bail;
fastrpc_buf_free(rbuf, 0);
- mutex_unlock(&fl->map_mutex);
+ mutex_unlock(&fl->internal_map_mutex);
return err;
}
+ mutex_lock(&fl->map_mutex);
VERIFY(err, !fastrpc_mmap_remove(fl, ud->vaddrout, ud->size, &map));
+ mutex_unlock(&fl->map_mutex);
if (err)
goto bail;
if (map) {
@@ -2340,12 +2340,17 @@ static int fastrpc_internal_munmap(struct fastrpc_file *fl,
map->phys, map->size, map->flags));
if (err)
goto bail;
+ mutex_lock(&fl->map_mutex);
fastrpc_mmap_free(map);
+ mutex_unlock(&fl->map_mutex);
}
bail:
- if (err && map)
+ if (err && map) {
+ mutex_lock(&fl->map_mutex);
fastrpc_mmap_add(map);
- mutex_unlock(&fl->map_mutex);
+ mutex_unlock(&fl->map_mutex);
+ }
+ mutex_unlock(&fl->internal_map_mutex);
return err;
}
@@ -2358,7 +2363,7 @@ static int fastrpc_internal_mmap(struct fastrpc_file *fl,
uintptr_t raddr = 0;
int err = 0;
- mutex_lock(&fl->map_mutex);
+ mutex_lock(&fl->internal_map_mutex);
if (ud->flags == ADSP_MMAP_ADD_PAGES) {
DEFINE_DMA_ATTRS(dma_attr);
@@ -2385,9 +2390,11 @@ static int fastrpc_internal_mmap(struct fastrpc_file *fl,
} else {
uintptr_t va_to_dsp;
+ mutex_lock(&fl->map_mutex);
VERIFY(err, !fastrpc_mmap_create(fl, ud->fd, 0,
(uintptr_t)ud->vaddrin, ud->size,
ud->flags, &map));
+ mutex_unlock(&fl->map_mutex);
if (err)
goto bail;
@@ -2404,9 +2411,16 @@ static int fastrpc_internal_mmap(struct fastrpc_file *fl,
}
ud->vaddrout = raddr;
bail:
- if (err && map)
- fastrpc_mmap_free(map);
- mutex_unlock(&fl->map_mutex);
+ if (err) {
+ if (map) {
+ mutex_lock(&fl->map_mutex);
+ fastrpc_mmap_free(map);
+ mutex_unlock(&fl->map_mutex);
+ }
+ if (!IS_ERR_OR_NULL(rbuf))
+ fastrpc_buf_free(rbuf, 0);
+ }
+ mutex_unlock(&fl->internal_map_mutex);
return err;
}
@@ -2587,6 +2601,7 @@ static int fastrpc_file_free(struct fastrpc_file *fl)
fastrpc_buf_free(fl->init_mem, 0);
fastrpc_context_list_dtor(fl);
fastrpc_cached_buf_list_free(fl);
+ mutex_lock(&fl->map_mutex);
do {
lmap = NULL;
hlist_for_each_entry_safe(map, n, &fl->maps, hn) {
@@ -2596,6 +2611,7 @@ static int fastrpc_file_free(struct fastrpc_file *fl)
}
fastrpc_mmap_free(lmap);
} while (lmap);
+ mutex_unlock(&fl->map_mutex);
if (fl->ssrcount == fl->apps->channel[cid].ssrcount)
kref_put_mutex(&fl->apps->channel[cid].kref,
@@ -2607,6 +2623,7 @@ static int fastrpc_file_free(struct fastrpc_file *fl)
bail:
fastrpc_remote_buf_list_free(fl);
mutex_destroy(&fl->map_mutex);
+ mutex_destroy(&fl->internal_map_mutex);
kfree(fl);
return 0;
}
@@ -2618,7 +2635,6 @@ static int fastrpc_device_release(struct inode *inode, struct file *file)
if (fl) {
if (fl->debugfs_file != NULL)
debugfs_remove(fl->debugfs_file);
-
fastrpc_file_free(fl);
file->private_data = NULL;
}
@@ -3032,8 +3048,10 @@ static int fastrpc_channel_open(struct fastrpc_file *fl)
}
if (cid == 0 && me->channel[cid].ssrcount !=
me->channel[cid].prevssrcount) {
+ mutex_lock(&fl->map_mutex);
if (fastrpc_mmap_remove_ssr(fl))
pr_err("ADSPRPC: SSR: Failed to unmap remote heap\n");
+ mutex_unlock(&fl->map_mutex);
me->channel[cid].prevssrcount =
me->channel[cid].ssrcount;
}
@@ -3098,6 +3116,7 @@ static int fastrpc_device_open(struct inode *inode, struct file *filp)
fl->debugfs_file = debugfs_file;
memset(&fl->perf, 0, sizeof(fl->perf));
filp->private_data = fl;
+ mutex_init(&fl->internal_map_mutex);
mutex_init(&fl->map_mutex);
spin_lock(&me->hlock);
hlist_add_head(&fl->hn, &me->drivers);