summaryrefslogtreecommitdiff
path: root/net/qrtr
diff options
context:
space:
mode:
authorLoic Poulain <loic.poulain@linaro.org>2020-11-06 18:33:30 +0100
committerJakub Kicinski <kuba@kernel.org>2020-11-11 15:29:34 -0800
commit90829f07baea7efe4ca77f79820f3849081186a8 (patch)
treedaa209c999be0bb1e6218330e0497e5e2d4ec4ec /net/qrtr
parentf7dec6cb914c8923808eefc034bba8227a5dfe3a (diff)
net: qrtr: Release distant nodes along the bridge node
Distant QRTR nodes can be accessed via an other node that acts as a bridge. When the a QRTR endpoint associated to a bridge node is released, all the linked distant nodes should also be released. This patch fixes endpoint release by: - Submitting QRTR BYE message locally on behalf of all the nodes accessible through the endpoint. - Removing all the routable node IDs from radix tree pointing to the released node endpoint. Signed-off-by: Loic Poulain <loic.poulain@linaro.org> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Diffstat (limited to 'net/qrtr')
-rw-r--r--net/qrtr/qrtr.c25
1 files changed, 19 insertions, 6 deletions
diff --git a/net/qrtr/qrtr.c b/net/qrtr/qrtr.c
index d4305deb3bdc..f4ab3ca6d73b 100644
--- a/net/qrtr/qrtr.c
+++ b/net/qrtr/qrtr.c
@@ -171,8 +171,13 @@ static void __qrtr_node_release(struct kref *kref)
void __rcu **slot;
spin_lock_irqsave(&qrtr_nodes_lock, flags);
- if (node->nid != QRTR_EP_NID_AUTO)
- radix_tree_delete(&qrtr_nodes, node->nid);
+ /* If the node is a bridge for other nodes, there are possibly
+ * multiple entries pointing to our released node, delete them all.
+ */
+ radix_tree_for_each_slot(slot, &qrtr_nodes, &iter, 0) {
+ if (*slot == node)
+ radix_tree_iter_delete(&qrtr_nodes, &iter, slot);
+ }
spin_unlock_irqrestore(&qrtr_nodes_lock, flags);
list_del(&node->item);
@@ -602,6 +607,7 @@ void qrtr_endpoint_unregister(struct qrtr_endpoint *ep)
struct qrtr_ctrl_pkt *pkt;
struct qrtr_tx_flow *flow;
struct sk_buff *skb;
+ unsigned long flags;
void __rcu **slot;
mutex_lock(&node->ep_lock);
@@ -609,11 +615,18 @@ void qrtr_endpoint_unregister(struct qrtr_endpoint *ep)
mutex_unlock(&node->ep_lock);
/* Notify the local controller about the event */
- skb = qrtr_alloc_ctrl_packet(&pkt, GFP_KERNEL);
- if (skb) {
- pkt->cmd = cpu_to_le32(QRTR_TYPE_BYE);
- qrtr_local_enqueue(NULL, skb, QRTR_TYPE_BYE, &src, &dst);
+ spin_lock_irqsave(&qrtr_nodes_lock, flags);
+ radix_tree_for_each_slot(slot, &qrtr_nodes, &iter, 0) {
+ if (*slot != node)
+ continue;
+ src.sq_node = iter.index;
+ skb = qrtr_alloc_ctrl_packet(&pkt, GFP_ATOMIC);
+ if (skb) {
+ pkt->cmd = cpu_to_le32(QRTR_TYPE_BYE);
+ qrtr_local_enqueue(NULL, skb, QRTR_TYPE_BYE, &src, &dst);
+ }
}
+ spin_unlock_irqrestore(&qrtr_nodes_lock, flags);
/* Wake up any transmitters waiting for resume-tx from the node */
mutex_lock(&node->qrtr_tx_lock);