[PATCH v3 01/12] net: qrtr: support getting new endpoint ids externally
From: Juha-Matti Tilli <hidden>
Date: 2026-09-08 09:32:30
Also in:
ath11k, ath12k, linux-arm-msm, linux-wireless, lkml
Subsystem:
networking [general], qualcomm ipc router (qrtr) driver, the rest · Maintainers:
"David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Manivannan Sadhasivam, Linus Torvalds
This is originally based on a patch by Mihai Moldovan, that allowed registering endpoint-specific data and getting endpoint ids by the endpoint-specific data. Unfortunately, the old API did not support freeing the ids, creating a memory leak if someone repeatedly unloads and reloads kernel modules. Also, the old API had O(N) complexity where N was the amount of leaked memory. Because the patch has been extensively changed, I reset authorship. So, the new patch version only supports getting ids externally, with the idea being that MHI controller would know about its endpoint id. I made sure getting new data ids is permissible while holding a spinlock, since multiple threads may race to get the same id. Originally-by: Mihai Moldovan [off-list ref] Signed-off-by: Mihai Moldovan <redacted> Signed-off-by: Juha-Matti Tilli <redacted> --- MAINTAINERS | 1 + include/net/qrtr.h | 10 ++++++++++ net/qrtr/af_qrtr.c | 42 ++++++++++++++++++++++++++++++++++++------ net/qrtr/qrtr.h | 5 +++++ 4 files changed, 52 insertions(+), 6 deletions(-) create mode 100644 include/net/qrtr.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 0b42e898f4d8e..491f09cb7939c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS@@ -22506,6 +22506,7 @@ QUALCOMM IPC ROUTER (QRTR) DRIVER M: Manivannan Sadhasivam <mani@kernel.org> L: linux-arm-msm@vger.kernel.org S: Maintained +F: include/net/qrtr.h F: include/trace/events/qrtr.h F: include/uapi/linux/qrtr.h F: net/qrtr/
diff --git a/include/net/qrtr.h b/include/net/qrtr.h
new file mode 100644
index 0000000000000..762d60b03012e
--- /dev/null
+++ b/include/net/qrtr.h@@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#ifndef __NET_QRTR_H +#define __NET_QRTR_H + +#include <linux/types.h> + +int qrtr_endpoint_get_data_id(u32 *endpoint_id); +void qrtr_endpoint_free_data_id(u32 endpoint_id); + +#endif /* __NET_QRTR_H */
diff --git a/net/qrtr/af_qrtr.c b/net/qrtr/af_qrtr.c
index 7c50d32b11015..86a92e95e270f 100644
--- a/net/qrtr/af_qrtr.c
+++ b/net/qrtr/af_qrtr.c@@ -11,6 +11,7 @@ #include <linux/wait.h> #include <net/sock.h> +#include <net/qrtr.h> #include "qrtr.h"
@@ -753,8 +754,8 @@ static struct sk_buff *qrtr_alloc_ctrl_packet(struct qrtr_ctrl_pkt **pkt, int qrtr_endpoint_register(struct qrtr_endpoint *ep, unsigned int nid) { struct qrtr_node *node; - u32 endpoint_id; - int rc; + u32 endpoint_id = 0; + int rc = 0; if (!ep || !ep->xmit) return -EINVAL;
@@ -763,9 +764,18 @@ int qrtr_endpoint_register(struct qrtr_endpoint *ep, unsigned int nid) if (!node) return -ENOMEM; - rc = xa_alloc_cyclic(&qrtr_endpoints, &endpoint_id, NULL, - QRTR_ENDPOINT_RANGE, &next_endpoint_id, - GFP_KERNEL); + if (ep->endpoint_data_id) + endpoint_id = ep->endpoint_data_id; + + /* + * If we're registering an endpoint into smd or tun based qrtr, + * we don't have endpoint_data_id. Thus, allocate a new one. + */ + if (!endpoint_id) { + rc = xa_alloc_cyclic(&qrtr_endpoints, &endpoint_id, NULL, + QRTR_ENDPOINT_RANGE, &next_endpoint_id, + GFP_KERNEL); + } if (rc < 0) goto free_node;
@@ -857,13 +867,33 @@ void qrtr_endpoint_unregister(struct qrtr_endpoint *ep) qrtr_node_release(node); - xa_erase(&qrtr_endpoints, endpoint_id); + if (ep->endpoint_data_id != endpoint_id) + xa_erase(&qrtr_endpoints, endpoint_id); // did allocate ep->id = 0; ep->node = NULL; } EXPORT_SYMBOL_GPL(qrtr_endpoint_unregister); +int qrtr_endpoint_get_data_id(u32 *endpoint_id) +{ + int rc; + + *endpoint_id = 0; + // GFP_ATOMIC to allow while holding spinlock + rc = xa_alloc_cyclic(&qrtr_endpoints, endpoint_id, NULL, + QRTR_ENDPOINT_RANGE, &next_endpoint_id, + GFP_ATOMIC); + return rc; +} +EXPORT_SYMBOL_GPL(qrtr_endpoint_get_data_id); + +void qrtr_endpoint_free_data_id(u32 endpoint_id) +{ + xa_erase(&qrtr_endpoints, endpoint_id); +} +EXPORT_SYMBOL_GPL(qrtr_endpoint_free_data_id); + /* Lookup socket by port. * * Callers must release with qrtr_port_put()
diff --git a/net/qrtr/qrtr.h b/net/qrtr/qrtr.h
index affc24f426c64..86c9b4e724d7e 100644
--- a/net/qrtr/qrtr.h
+++ b/net/qrtr/qrtr.h@@ -21,6 +21,7 @@ struct qrtr_node_lookup_helper { /** * struct qrtr_endpoint - endpoint handle * @xmit: Callback for outgoing packets + * @endpoint_data_id: an already allocated id to be used instead of new alloc * * The socket buffer passed to the xmit function becomes owned by the endpoint * driver. As such, when the driver is done with the buffer, it should
@@ -32,6 +33,7 @@ struct qrtr_endpoint { struct qrtr_node *node; struct qrtr_node_lookup_helper helper; u32 id; + u32 endpoint_data_id; }; int qrtr_endpoint_register(struct qrtr_endpoint *ep, unsigned int nid);
@@ -47,4 +49,7 @@ void qrtr_ns_remove(void); int qrtr_msg_get_endpoint(struct msghdr *msg, u32 *out_endpoint_id); void qrtr_sock_set_report_endpoint(struct sock *sk); +int qrtr_endpoint_get_data_id(u32 *endpoint_id); +void qrtr_endpoint_free_data_id(u32 endpoint_id); + #endif
--
2.34.1