From cc60f7fdd8f3eb1883d3db7b207aad89c86047cd Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Mon, 3 Oct 2022 09:57:24 -0700 Subject: [PATCH] net: qrtr: Add socket mode optimization A remote endpoint should not need to know when a client socket is freed if the socket never established commnication with the endpoint. Add a mode to keep track of which endpoints a socket communicates with. There are three modes a socket can be in: INIT - Socket has not sent anything or only local messages, only send client close to local services. SINGLE - Socket has sent messages to a single ept, send event to this single ept. MULTI - Socket has sent messages to multiple epts, broadcast release of this socket. Server state changes should be broadcast throughout the system. Change the ipc state of a port when it sends a NEW SERVER control packet. This ensures the DEL CLIENT control packet is propagated correctly for servers. Change-Id: I416742cff598bf7aa9da2baa2e86a53b18367870 Signed-off-by: Chris Lew --- net/qrtr/af_qrtr.c | 73 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 60 insertions(+), 13 deletions(-) diff --git a/net/qrtr/af_qrtr.c b/net/qrtr/af_qrtr.c index b502ccd6377f..b814fc296f6e 100644 --- a/net/qrtr/af_qrtr.c +++ b/net/qrtr/af_qrtr.c @@ -24,6 +24,10 @@ #define QRTR_EPH_PORT_RANGE \ XA_LIMIT(QRTR_MIN_EPH_SOCKET, QRTR_MAX_EPH_SOCKET) +/* qrtr socket states */ +#define QRTR_STATE_MULTI -2 +#define QRTR_STATE_INIT -1 + /** * struct qrtr_hdr_v1 - (I|R)PCrouter packet header version 1 * @version: protocol version @@ -90,6 +94,8 @@ struct qrtr_sock { struct sock sk; struct sockaddr_qrtr us; struct sockaddr_qrtr peer; + + int state; }; static inline struct qrtr_sock *qrtr_sk(struct sock *sk) @@ -688,29 +694,60 @@ static void qrtr_port_put(struct qrtr_sock *ipc) sock_put(&ipc->sk); } -/* Remove port assignment. */ -static void qrtr_port_remove(struct qrtr_sock *ipc) +static void qrtr_send_del_client(struct qrtr_sock *ipc) { struct qrtr_ctrl_pkt *pkt; - struct sk_buff *skb; - int port = ipc->us.sq_port; struct sockaddr_qrtr to; + struct qrtr_node *node; + struct sk_buff *skbn; + struct sk_buff *skb; + int type = QRTR_TYPE_DEL_CLIENT; + + skb = qrtr_alloc_ctrl_packet(&pkt, GFP_KERNEL); + if (!skb) + return; to.sq_family = AF_QIPCRTR; to.sq_node = QRTR_NODE_BCAST; to.sq_port = QRTR_PORT_CTRL; - skb = qrtr_alloc_ctrl_packet(&pkt, GFP_KERNEL); - if (skb) { - pkt->cmd = cpu_to_le32(QRTR_TYPE_DEL_CLIENT); - pkt->client.node = cpu_to_le32(ipc->us.sq_node); - pkt->client.port = cpu_to_le32(ipc->us.sq_port); + pkt->cmd = cpu_to_le32(QRTR_TYPE_DEL_CLIENT); + pkt->client.node = cpu_to_le32(ipc->us.sq_node); + pkt->client.port = cpu_to_le32(ipc->us.sq_port); - skb_set_owner_w(skb, &ipc->sk); - qrtr_bcast_enqueue(NULL, skb, QRTR_TYPE_DEL_CLIENT, &ipc->us, - &to); + skb_set_owner_w(skb, &ipc->sk); + + if (ipc->state == QRTR_STATE_MULTI) { + qrtr_bcast_enqueue(NULL, skb, type, &ipc->us, &to); + return; } + if (ipc->state > QRTR_STATE_INIT) { + node = qrtr_node_lookup(ipc->state); + if (!node) + goto exit; + + skbn = skb_clone(skb, GFP_KERNEL); + if (!skbn) { + qrtr_node_release(node); + goto exit; + } + + skb_set_owner_w(skbn, &ipc->sk); + qrtr_node_enqueue(node, skbn, type, &ipc->us, &to); + qrtr_node_release(node); + } +exit: + qrtr_local_enqueue(NULL, skb, type, &ipc->us, &to); +} + +/* Remove port assignment. */ +static void qrtr_port_remove(struct qrtr_sock *ipc) +{ + int port = ipc->us.sq_port; + + qrtr_send_del_client(ipc); + if (port == QRTR_PORT_CTRL) port = 0; @@ -963,6 +1000,11 @@ static int qrtr_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) return -ECONNRESET; } enqueue_fn = qrtr_node_enqueue; + + if (ipc->state > QRTR_STATE_INIT && ipc->state != node->nid) + ipc->state = QRTR_STATE_MULTI; + else if (ipc->state == QRTR_STATE_INIT) + ipc->state = node->nid; } plen = (len + 3) & ~3; @@ -981,7 +1023,8 @@ static int qrtr_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) goto out_node; } - if (ipc->us.sq_port == QRTR_PORT_CTRL) { + if (ipc->us.sq_port == QRTR_PORT_CTRL || + addr->sq_port == QRTR_PORT_CTRL) { if (len < 4) { rc = -EINVAL; kfree_skb(skb); @@ -993,6 +1036,9 @@ static int qrtr_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) } type = le32_to_cpu(qrtr_type); + if (addr->sq_port == QRTR_PORT_CTRL && type == QRTR_TYPE_NEW_SERVER) + ipc->state = QRTR_STATE_MULTI; + rc = enqueue_fn(node, skb, type, &ipc->us, addr); if (rc >= 0) rc = len; @@ -1284,6 +1330,7 @@ static int qrtr_create(struct net *net, struct socket *sock, ipc->us.sq_family = AF_QIPCRTR; ipc->us.sq_node = qrtr_local_nid; ipc->us.sq_port = 0; + ipc->state = QRTR_STATE_INIT; return 0; }