[PATCH] misc: fastrpc: ignore unsent and duplicate invoke replies

From: Yousef Alhouseen

Date: Wed Jun 24 2026 - 15:17:48 EST


fastrpc_rpmsg_callback() drops the invoke reference taken before sending
the request. The callback can currently consume a reference for a guessed
context ID before the request has been sent, and duplicate replies can
schedule multiple puts for the same send reference.

Track whether an invoke has been sent and whether a reply has already
been accepted while holding the channel IDR lock. Reject unsent and
duplicate replies so only the first valid response consumes the send
reference.

Signed-off-by: Yousef Alhouseen <alhouseenyousef@xxxxxxxxx>
---
drivers/misc/fastrpc.c | 25 +++++++++++++++++++++++--
1 file changed, 23 insertions(+), 2 deletions(-)

diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
index c91d5da42..4eaecee1b 100644
--- a/drivers/misc/fastrpc.c
+++ b/drivers/misc/fastrpc.c
@@ -250,6 +250,8 @@ struct fastrpc_invoke_ctx {
uintptr_t *buf_pv;
struct fastrpc_buf_overlap *olaps;
struct fastrpc_channel_ctx *cctx;
+ bool sent;
+ bool completed;
};

struct fastrpc_session_ctx {
@@ -1239,6 +1241,8 @@ static int fastrpc_invoke_send(struct fastrpc_session_ctx *sctx,
struct fastrpc_channel_ctx *cctx;
struct fastrpc_user *fl = ctx->fl;
struct fastrpc_msg *msg = &ctx->msg;
+ unsigned long flags;
+ bool put_ref = true;
int ret;

cctx = fl->cctx;
@@ -1255,10 +1259,23 @@ static int fastrpc_invoke_send(struct fastrpc_session_ctx *sctx,
msg->size = roundup(ctx->msg_sz, PAGE_SIZE);
fastrpc_context_get(ctx);

+ spin_lock_irqsave(&cctx->lock, flags);
+ ctx->sent = true;
+ spin_unlock_irqrestore(&cctx->lock, flags);
+
ret = rpmsg_send(cctx->rpdev->ept, (void *)msg, sizeof(*msg));

- if (ret)
- fastrpc_context_put(ctx);
+ if (ret) {
+ spin_lock_irqsave(&cctx->lock, flags);
+ if (ctx->completed)
+ put_ref = false;
+ else
+ ctx->sent = false;
+ spin_unlock_irqrestore(&cctx->lock, flags);
+
+ if (put_ref)
+ fastrpc_context_put(ctx);
+ }

return ret;

@@ -2586,6 +2603,10 @@ static int fastrpc_rpmsg_callback(struct rpmsg_device *rpdev, void *data,

spin_lock_irqsave(&cctx->lock, flags);
ctx = idr_find(&cctx->ctx_idr, ctxid);
+ if (ctx && (!ctx->sent || ctx->completed))
+ ctx = NULL;
+ if (ctx)
+ ctx->completed = true;
spin_unlock_irqrestore(&cctx->lock, flags);

if (!ctx) {
--
2.54.0