msm: rpc: Reorganize the usage of spinlocks in RPC Router reader thread
A race condition exists between a driver closing an RPC endpoint and
RPC Router routing an incoming RPC message to that endpoint. So hold
the appropriate locks to avoid both the events happening simultaneously.
CRs-Fixed: 301630
Signed-off-by: Karthikeyan Ramasubramanian <kramasub@codeaurora.org>
diff --git a/arch/arm/mach-msm/smd_rpcrouter.c b/arch/arm/mach-msm/smd_rpcrouter.c
index b45b182..e0aad46 100644
--- a/arch/arm/mach-msm/smd_rpcrouter.c
+++ b/arch/arm/mach-msm/smd_rpcrouter.c
@@ -628,6 +628,9 @@
/* Endpoint with dst_pid = 0xffffffff corresponds to that of
** router port. So don't send a REMOVE CLIENT message while
** destroying it.*/
+ spin_lock_irqsave(&local_endpoints_lock, flags);
+ list_del(&ept->list);
+ spin_unlock_irqrestore(&local_endpoints_lock, flags);
if (ept->dst_pid != 0xffffffff) {
msg.cmd = RPCROUTER_CTRL_CMD_REMOVE_CLIENT;
msg.cli.pid = ept->pid;
@@ -659,9 +662,6 @@
wake_lock_destroy(&ept->read_q_wake_lock);
wake_lock_destroy(&ept->reply_q_wake_lock);
- spin_lock_irqsave(&local_endpoints_lock, flags);
- list_del(&ept->list);
- spin_unlock_irqrestore(&local_endpoints_lock, flags);
kfree(ept);
return 0;
}
@@ -691,16 +691,11 @@
static struct msm_rpc_endpoint *rpcrouter_lookup_local_endpoint(uint32_t cid)
{
struct msm_rpc_endpoint *ept;
- unsigned long flags;
- spin_lock_irqsave(&local_endpoints_lock, flags);
list_for_each_entry(ept, &local_endpoints, list) {
- if (ept->cid == cid) {
- spin_unlock_irqrestore(&local_endpoints_lock, flags);
+ if (ept->cid == cid)
return ept;
- }
}
- spin_unlock_irqrestore(&local_endpoints_lock, flags);
return NULL;
}
@@ -1121,8 +1116,10 @@
}
#endif
+ spin_lock_irqsave(&local_endpoints_lock, flags);
ept = rpcrouter_lookup_local_endpoint(hdr.dst_cid);
if (!ept) {
+ spin_unlock_irqrestore(&local_endpoints_lock, flags);
DIAG("no local ept for cid %08x\n", hdr.dst_cid);
kfree(frag);
goto done;
@@ -1132,7 +1129,7 @@
* and if so, append this fragment to that packet.
*/
mid = PACMARK_MID(pm);
- spin_lock_irqsave(&ept->incomplete_lock, flags);
+ spin_lock(&ept->incomplete_lock);
list_for_each_entry(pkt, &ept->incomplete, list) {
if (pkt->mid == mid) {
pkt->last->next = frag;
@@ -1140,15 +1137,14 @@
pkt->length += frag->length;
if (PACMARK_LAST(pm)) {
list_del(&pkt->list);
- spin_unlock_irqrestore(&ept->incomplete_lock,
- flags);
+ spin_unlock(&ept->incomplete_lock);
goto packet_complete;
}
- spin_unlock_irqrestore(&ept->incomplete_lock, flags);
+ spin_unlock(&ept->incomplete_lock);
+ spin_unlock_irqrestore(&local_endpoints_lock, flags);
goto done;
}
}
- spin_unlock_irqrestore(&ept->incomplete_lock, flags);
/* This mid is new -- create a packet for it, and put it on
* the incomplete list if this fragment is not a last fragment,
* otherwise put it on the read queue.
@@ -1161,16 +1157,20 @@
pkt->length = frag->length;
if (!PACMARK_LAST(pm)) {
list_add_tail(&pkt->list, &ept->incomplete);
+ spin_unlock(&ept->incomplete_lock);
+ spin_unlock_irqrestore(&local_endpoints_lock, flags);
goto done;
}
+ spin_unlock(&ept->incomplete_lock);
packet_complete:
- spin_lock_irqsave(&ept->read_q_lock, flags);
+ spin_lock(&ept->read_q_lock);
D("%s: take read lock on ept %p\n", __func__, ept);
wake_lock(&ept->read_q_wake_lock);
list_add_tail(&pkt->list, &ept->read_q);
wake_up(&ept->wait_q);
- spin_unlock_irqrestore(&ept->read_q_lock, flags);
+ spin_unlock(&ept->read_q_lock);
+ spin_unlock_irqrestore(&local_endpoints_lock, flags);
done:
if (hdr.confirm_rx) {