msm: adsprpc: block smmu unmap of buffer used in pending rpc call
A dynamic SMMU mapping created as part of an RPC call can potentially be removed by a parallel munmap ioctl call before the RPC call is complete, leading to SMMU faults. Maintain a ref-count that indicates that the mapping is being used by a pending RPC call and allow the mapping to be removed only if this count is 0. Change-Id: Ieb4ff6b298ff9c48953bc5b3539fdfe19a14b442 Acked-by: Santosh Sakore <ssakore@qti.qualcomm.com> Signed-off-by: Santosh Sakore <quic_ssakore@quicinc.com>
This commit is contained in:

committed by
Gerrit - the friendly Code Review server

parent
64813776c7
commit
e696574fb5
@@ -957,6 +957,8 @@ static int fastrpc_mmap_remove(struct fastrpc_file *fl, int fd, uintptr_t va,
|
|||||||
if ((fd < 0 || map->fd == fd) && map->raddr == va &&
|
if ((fd < 0 || map->fd == fd) && map->raddr == va &&
|
||||||
map->raddr + map->len == va + len &&
|
map->raddr + map->len == va + len &&
|
||||||
map->refs == 1 &&
|
map->refs == 1 &&
|
||||||
|
/* Remove map only if it isn't being used in any pending RPC calls */
|
||||||
|
!map->ctx_refs &&
|
||||||
/* Skip unmap if it is fastrpc shell memory */
|
/* Skip unmap if it is fastrpc shell memory */
|
||||||
!map->is_filemap) {
|
!map->is_filemap) {
|
||||||
match = map;
|
match = map;
|
||||||
@@ -997,7 +999,7 @@ static void fastrpc_mmap_free(struct fastrpc_mmap *map, uint32_t flags)
|
|||||||
map->flags == ADSP_MMAP_REMOTE_HEAP_ADDR) {
|
map->flags == ADSP_MMAP_REMOTE_HEAP_ADDR) {
|
||||||
spin_lock_irqsave(&me->hlock, irq_flags);
|
spin_lock_irqsave(&me->hlock, irq_flags);
|
||||||
map->refs--;
|
map->refs--;
|
||||||
if (!map->refs && !map->is_persistent)
|
if (!map->refs && !map->is_persistent && !map->ctx_refs)
|
||||||
hlist_del_init(&map->hn);
|
hlist_del_init(&map->hn);
|
||||||
spin_unlock_irqrestore(&me->hlock, irq_flags);
|
spin_unlock_irqrestore(&me->hlock, irq_flags);
|
||||||
if (map->refs > 0) {
|
if (map->refs > 0) {
|
||||||
@@ -1012,7 +1014,7 @@ static void fastrpc_mmap_free(struct fastrpc_mmap *map, uint32_t flags)
|
|||||||
spin_unlock_irqrestore(&me->hlock, irq_flags);
|
spin_unlock_irqrestore(&me->hlock, irq_flags);
|
||||||
} else {
|
} else {
|
||||||
map->refs--;
|
map->refs--;
|
||||||
if (!map->refs)
|
if (!map->refs && !map->ctx_refs)
|
||||||
hlist_del_init(&map->hn);
|
hlist_del_init(&map->hn);
|
||||||
if (map->refs > 0 && !flags)
|
if (map->refs > 0 && !flags)
|
||||||
return;
|
return;
|
||||||
@@ -1953,8 +1955,15 @@ static void context_free(struct smq_invoke_ctx *ctx)
|
|||||||
spin_unlock(&ctx->fl->hlock);
|
spin_unlock(&ctx->fl->hlock);
|
||||||
|
|
||||||
mutex_lock(&ctx->fl->map_mutex);
|
mutex_lock(&ctx->fl->map_mutex);
|
||||||
for (i = 0; i < nbufs; ++i)
|
for (i = 0; i < nbufs; ++i) {
|
||||||
|
/*
|
||||||
|
* Decrement ctx refs count before mmap free,
|
||||||
|
* indicate remote call no longer using it
|
||||||
|
*/
|
||||||
|
if (ctx->maps[i] && ctx->maps[i]->ctx_refs)
|
||||||
|
ctx->maps[i]->ctx_refs--;
|
||||||
fastrpc_mmap_free(ctx->maps[i], 0);
|
fastrpc_mmap_free(ctx->maps[i], 0);
|
||||||
|
}
|
||||||
mutex_unlock(&ctx->fl->map_mutex);
|
mutex_unlock(&ctx->fl->map_mutex);
|
||||||
|
|
||||||
fastrpc_buf_free(ctx->buf, 1);
|
fastrpc_buf_free(ctx->buf, 1);
|
||||||
@@ -2342,6 +2351,12 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx)
|
|||||||
err = fastrpc_mmap_create(ctx->fl, ctx->fds[i], NULL,
|
err = fastrpc_mmap_create(ctx->fl, ctx->fds[i], NULL,
|
||||||
ctx->attrs[i], buf, len,
|
ctx->attrs[i], buf, len,
|
||||||
mflags, &ctx->maps[i]);
|
mflags, &ctx->maps[i]);
|
||||||
|
/*
|
||||||
|
* Increment ctx refs count for in/out buffer if map created,
|
||||||
|
* indicate map under use in remote call
|
||||||
|
*/
|
||||||
|
if (ctx->maps[i])
|
||||||
|
ctx->maps[i]->ctx_refs++;
|
||||||
mutex_unlock(&ctx->fl->map_mutex);
|
mutex_unlock(&ctx->fl->map_mutex);
|
||||||
if (err)
|
if (err)
|
||||||
goto bail;
|
goto bail;
|
||||||
@@ -2369,10 +2384,23 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx)
|
|||||||
FASTRPC_ATTR_NOVA, 0, 0, dmaflags,
|
FASTRPC_ATTR_NOVA, 0, 0, dmaflags,
|
||||||
&ctx->maps[i]);
|
&ctx->maps[i]);
|
||||||
if (err) {
|
if (err) {
|
||||||
for (j = bufs; j < i; j++)
|
for (j = bufs; j < i; j++) {
|
||||||
|
/*
|
||||||
|
* Due to error decrement ctx refs count before mmap free
|
||||||
|
* for each in/out handle, if map created
|
||||||
|
*/
|
||||||
|
if (ctx->maps[j] && ctx->maps[j]->ctx_refs)
|
||||||
|
ctx->maps[j]->ctx_refs--;
|
||||||
fastrpc_mmap_free(ctx->maps[j], 0);
|
fastrpc_mmap_free(ctx->maps[j], 0);
|
||||||
|
}
|
||||||
mutex_unlock(&ctx->fl->map_mutex);
|
mutex_unlock(&ctx->fl->map_mutex);
|
||||||
goto bail;
|
goto bail;
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Increment ctx refs count for in/out handle if map created
|
||||||
|
* and no error, indicate map under use in remote call
|
||||||
|
*/
|
||||||
|
ctx->maps[i]->ctx_refs++;
|
||||||
}
|
}
|
||||||
ipage += 1;
|
ipage += 1;
|
||||||
}
|
}
|
||||||
@@ -2704,6 +2732,12 @@ static int put_args(uint32_t kernel, struct smq_invoke_ctx *ctx,
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
mutex_lock(&ctx->fl->map_mutex);
|
mutex_lock(&ctx->fl->map_mutex);
|
||||||
|
/*
|
||||||
|
* Decrement ctx refs count before mmap free,
|
||||||
|
* indicate remote call no longer using it
|
||||||
|
*/
|
||||||
|
if (ctx->maps[i]->ctx_refs)
|
||||||
|
ctx->maps[i]->ctx_refs--;
|
||||||
fastrpc_mmap_free(ctx->maps[i], 0);
|
fastrpc_mmap_free(ctx->maps[i], 0);
|
||||||
mutex_unlock(&ctx->fl->map_mutex);
|
mutex_unlock(&ctx->fl->map_mutex);
|
||||||
ctx->maps[i] = NULL;
|
ctx->maps[i] = NULL;
|
||||||
@@ -2714,9 +2748,16 @@ static int put_args(uint32_t kernel, struct smq_invoke_ctx *ctx,
|
|||||||
if (!fdlist[i])
|
if (!fdlist[i])
|
||||||
break;
|
break;
|
||||||
if (!fastrpc_mmap_find(ctx->fl, (int)fdlist[i], NULL, 0, 0,
|
if (!fastrpc_mmap_find(ctx->fl, (int)fdlist[i], NULL, 0, 0,
|
||||||
0, 0, &mmap))
|
0, 0, &mmap)) {
|
||||||
|
/*
|
||||||
|
* Decrement ctx refs count before mmap free,
|
||||||
|
* indicate remote call no longer using it
|
||||||
|
*/
|
||||||
|
if (mmap && mmap->ctx_refs)
|
||||||
|
mmap->ctx_refs--;
|
||||||
fastrpc_mmap_free(mmap, 0);
|
fastrpc_mmap_free(mmap, 0);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
mutex_unlock(&ctx->fl->map_mutex);
|
mutex_unlock(&ctx->fl->map_mutex);
|
||||||
if (ctx->crc && crclist && rpra)
|
if (ctx->crc && crclist && rpra)
|
||||||
K_COPY_TO_USER(err, kernel, ctx->crc,
|
K_COPY_TO_USER(err, kernel, ctx->crc,
|
||||||
|
@@ -1031,6 +1031,8 @@ struct fastrpc_mmap {
|
|||||||
/* Mapping for fastrpc shell */
|
/* Mapping for fastrpc shell */
|
||||||
bool is_filemap;
|
bool is_filemap;
|
||||||
char *servloc_name; /* Indicate which daemon mapped this */
|
char *servloc_name; /* Indicate which daemon mapped this */
|
||||||
|
/* Indicates map is being used by a pending RPC call */
|
||||||
|
unsigned int ctx_refs;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum fastrpc_perfkeys {
|
enum fastrpc_perfkeys {
|
||||||
|
Reference in New Issue
Block a user