[PATCH v3 01/12] net: qrtr: support getting new endpoint ids externally
Juha-Matti Tilli
juha-matti.tilli at iki.fi
Tue Sep 8 02:31:34 PDT 2026
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 <ionic at ionic.de>
Signed-off-by: Mihai Moldovan <ionic at ionic.de>
Signed-off-by: Juha-Matti Tilli <juha-matti.tilli at iki.fi>
---
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 at kernel.org>
L: linux-arm-msm at 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
More information about the ath12k
mailing list