fastrpc_rpmsg_remove() wakes pending invoke waiters when the rpmsg device is removed, but it does not release the send references taken before each request was submitted. Those references normally disappear only when a DSP reply arrives, which cannot be relied on after endpoint removal.
Walk the channel IDR during removal, mark in-flight contexts completed, and schedule the send-reference put while waking waiters with -EPIPE. This prevents disconnected channels from pinning invoke contexts indefinitely. Signed-off-by: Yousef Alhouseen <[email protected]> --- drivers/misc/fastrpc.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c index 90281859a..bfdf8ab6a 100644 --- a/drivers/misc/fastrpc.c +++ b/drivers/misc/fastrpc.c @@ -2580,30 +2580,31 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev) return err; } -static void fastrpc_notify_users(struct fastrpc_user *user) +static int fastrpc_notify_context(int id, void *ptr, void *data) { - struct fastrpc_invoke_ctx *ctx; + struct fastrpc_invoke_ctx *ctx = ptr; - spin_lock(&user->lock); - list_for_each_entry(ctx, &user->pending, node) { - ctx->retval = -EPIPE; - complete(&ctx->work); + if (ctx->sent && !ctx->completed) { + ctx->completed = true; + schedule_work(&ctx->put_work); } - spin_unlock(&user->lock); + + ctx->retval = -EPIPE; + complete(&ctx->work); + + return 0; } static void fastrpc_rpmsg_remove(struct rpmsg_device *rpdev) { struct fastrpc_channel_ctx *cctx = dev_get_drvdata(&rpdev->dev); struct fastrpc_buf *buf, *b; - struct fastrpc_user *user; unsigned long flags; /* No invocations past this point */ spin_lock_irqsave(&cctx->lock, flags); cctx->rpdev = NULL; - list_for_each_entry(user, &cctx->users, user) - fastrpc_notify_users(user); + idr_for_each(&cctx->ctx_idr, fastrpc_notify_context, NULL); spin_unlock_irqrestore(&cctx->lock, flags); if (cctx->fdevice) -- 2.54.0
