diff --git a/net/qrtr/qrtr.c b/net/qrtr/qrtr.c index 70e722932538..b93c9ea38480 100644 --- a/net/qrtr/qrtr.c +++ b/net/qrtr/qrtr.c @@ -638,28 +638,49 @@ int qrtr_endpoint_register(struct qrtr_endpoint *ep, unsigned int nid) } EXPORT_SYMBOL_GPL(qrtr_endpoint_register); +static void qrtr_notify_bye(u32 nid) +{ + struct sockaddr_qrtr src = {AF_QIPCRTR, nid, QRTR_PORT_CTRL}; + struct sockaddr_qrtr dst = {AF_QIPCRTR, qrtr_local_nid, QRTR_PORT_CTRL}; + struct qrtr_ctrl_pkt *pkt; + struct sk_buff *skb; + + skb = qrtr_alloc_ctrl_packet(&pkt); + if (!skb) + return; + + pkt->cmd = cpu_to_le32(QRTR_TYPE_BYE); + qrtr_local_enqueue(NULL, skb, QRTR_TYPE_BYE, &src, &dst); +} + /** * qrtr_endpoint_unregister - unregister endpoint * @ep: endpoint to unregister */ void qrtr_endpoint_unregister(struct qrtr_endpoint *ep) { + struct radix_tree_iter iter; struct qrtr_node *node = ep->node; - struct sockaddr_qrtr src = {AF_QIPCRTR, node->nid, QRTR_PORT_CTRL}; - struct sockaddr_qrtr dst = {AF_QIPCRTR, qrtr_local_nid, QRTR_PORT_CTRL}; - struct qrtr_ctrl_pkt *pkt; - struct sk_buff *skb; + unsigned long flags; + void __rcu **slot; mutex_lock(&node->ep_lock); node->ep = NULL; mutex_unlock(&node->ep_lock); /* Notify the local controller about the event */ - skb = qrtr_alloc_ctrl_packet(&pkt); - if (skb) { - pkt->cmd = cpu_to_le32(QRTR_TYPE_BYE); - qrtr_local_enqueue(NULL, skb, QRTR_TYPE_BYE, &src, &dst); + down_read(&qrtr_epts_lock); + spin_lock_irqsave(&qrtr_nodes_lock, flags); + radix_tree_for_each_slot(slot, &qrtr_nodes, &iter, 0) { + if (node != *slot) + continue; + + spin_unlock_irqrestore(&qrtr_nodes_lock, flags); + qrtr_notify_bye(iter.index); + spin_lock_irqsave(&qrtr_nodes_lock, flags); } + spin_unlock_irqrestore(&qrtr_nodes_lock, flags); + up_read(&qrtr_epts_lock); /* Wake up any transmitters waiting for resume-tx from the node */ wake_up_interruptible_all(&node->resume_tx);