Endpoint lookup in the receive path acts as a demultiplexer routing incoming messages to the appropriate endpoint. This is a read-heavy operation (frequent message receives) with infrequent writes (endpoint creation/destruction). Since idr_find() is safe under RCU read-side protection, RCU can be used to optimize this path.
Convert endpoint lookup to use RCU: - Read path: Use rcu_read_lock/unlock for lockless lookup - Destroy path: Add synchronize_rcu() after endpoint removal This reduces lock contention in the hot receive path. RCU safety note: When idr_alloc() returns, the endpoint becomes immediately visible to idr_find(), but ept->addr might not yet be set. This creates a theoretical window where RX could find an endpoint with uninitialized addr. This is safe because: 1) When endpoints are created via rpmsg core callbacks, initialization completes before announce_create() is sent. Remote processors only send messages after receiving the announcement. 2) For manually created endpoints, drivers control timing and typically do not announce until ready. Thus, messages only arrive after ept->addr is initialized, making this RCU optimization safe. No functional change except reduced contention. Signed-off-by: Zhongqiu Han <[email protected]> --- drivers/rpmsg/virtio_rpmsg_bus.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c index 79d983055b4d..4cbb8a8aaec5 100644 --- a/drivers/rpmsg/virtio_rpmsg_bus.c +++ b/drivers/rpmsg/virtio_rpmsg_bus.c @@ -17,6 +17,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/mutex.h> +#include <linux/rcupdate.h> #include <linux/rpmsg.h> #include <linux/rpmsg/byteorder.h> #include <linux/rpmsg/ns.h> @@ -297,6 +298,12 @@ __rpmsg_destroy_ept(struct virtproc_info *vrp, struct rpmsg_endpoint *ept) idr_remove(&vrp->endpoints, ept->addr); mutex_unlock(&vrp->endpoints_lock); + /* + * Wait for any ongoing RCU read-side critical sections to complete. + * This ensures no one is accessing the endpoint after removal. + */ + synchronize_rcu(); + /* make sure in-flight inbound messages won't invoke cb anymore */ mutex_lock(&ept->cb_lock); ept->cb = NULL; @@ -680,7 +687,7 @@ static int rpmsg_recv_single(struct virtproc_info *vrp, struct device *dev, } /* use the dst addr to fetch the callback of the appropriate user */ - mutex_lock(&vrp->endpoints_lock); + rcu_read_lock(); ept = idr_find(&vrp->endpoints, __rpmsg32_to_cpu(little_endian, msg->dst)); @@ -688,7 +695,7 @@ static int rpmsg_recv_single(struct virtproc_info *vrp, struct device *dev, if (ept) kref_get(&ept->refcount); - mutex_unlock(&vrp->endpoints_lock); + rcu_read_unlock(); if (ept) { /* make sure ept->cb doesn't go away while we use it */ -- 2.43.0
