msm: ipc: Fix potential AB-BA deadlock
In kernel QMI, while receiving responses continuously, there is a
classic out-of-order(AB-BA) deadlock scenario between IPC router and
Kernel QMI interface. The scenario is as below:
1) IPC Router receives the message for kernel QMI port and acquires the
corresponding port's port_rx_q_lock and then calls the notify
function for that port which tries to acquire the handle_lock of the
port.
2) Kernel QMI interface, that runs independent of IPC Router activities,
tries to send a message and acquires handle_lock for the port and
tries to acquire the port's port_rx_q_lock to read the response from
the port.
3) This creates a classic AB-BA deadlock because port_rx_q_lock is
locked at step 1 and handle_lock is acquired at step 2.
Fix the deadlock.
Change-Id: I532cff30b445e11baa715a570e5e853d9b71bab3
Signed-off-by: Zaheerulla Meer <zmeer@codeaurora.org>
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index 21baa06..e66afeb 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -464,6 +464,7 @@
struct rr_packet *pkt, int clone)
{
struct rr_packet *temp_pkt = pkt;
+ void (*notify)(unsigned event, void *priv);
if (unlikely(!port_ptr || !pkt))
return -EINVAL;
@@ -482,9 +483,10 @@
wake_lock(&port_ptr->port_rx_wake_lock);
list_add_tail(&temp_pkt->list, &port_ptr->port_rx_q);
wake_up(&port_ptr->port_rx_wait_q);
- if (port_ptr->notify)
- port_ptr->notify(MSM_IPC_ROUTER_READ_CB, port_ptr->priv);
+ notify = port_ptr->notify;
mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
+ if (notify)
+ notify(MSM_IPC_ROUTER_READ_CB, port_ptr->priv);
return 0;
}