msm: ipc: Serialize SMD XPRT CLOSE and OPEN events
When a remote subsystem resets, IPC Router's SMD XPRT Layer queues a CLOSE
event. When the concerned subsytem powers up and the channel is reopened,
SMD XPRT Layer queues a OPEN event. When the remote subsytem resets and
powers up quickly, the following race condition exists:
a) IPC Router is scheduled out while handling the CLOSE event, leaving a
stale XPRT
b) IPC Router's SMD XPRT Layer queues a OPEN event
c) IPC Router's SMD XPRT Layer reads a HELLO message, finds a stale
XPRT and queues a DATA event on the stale XPRT
This race condition causes a kernel panic.
Fix this race condition by not handling any other SMD XPRT event until
the CLOSE event is complete.
CRs-Fixed: 488331
Change-Id: I2283e163413d1896bd6842530b8a6a2b537e22de
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 2c91371..a86ed4c 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -189,8 +189,6 @@
static uint32_t next_port_id;
static DEFINE_MUTEX(next_port_id_lock);
-static atomic_t pending_close_count = ATOMIC_INIT(0);
-static wait_queue_head_t subsystem_restart_wait;
static struct workqueue_struct *msm_ipc_router_workqueue;
enum {
@@ -2610,10 +2608,7 @@
modem_reset_cleanup(xprt_work->xprt->priv);
msm_ipc_router_remove_xprt(xprt_work->xprt);
-
- if (atomic_dec_return(&pending_close_count) == 0)
- wake_up(&subsystem_restart_wait);
-
+ xprt_work->xprt->sft_close_done(xprt_work->xprt);
kfree(xprt_work);
}
@@ -2647,7 +2642,6 @@
case IPC_ROUTER_XPRT_EVENT_CLOSE:
D("close event for '%s'\n", xprt->name);
- atomic_inc(&pending_close_count);
xprt_work = kmalloc(sizeof(struct msm_ipc_router_xprt_work),
GFP_ATOMIC);
xprt_work->xprt = xprt;
@@ -2675,45 +2669,6 @@
queue_work(xprt_info->workqueue, &xprt_info->read_data);
}
-static int modem_restart_notifier_cb(struct notifier_block *this,
- unsigned long code,
- void *data);
-static struct notifier_block msm_ipc_router_nb = {
- .notifier_call = modem_restart_notifier_cb,
-};
-
-static int modem_restart_notifier_cb(struct notifier_block *this,
- unsigned long code,
- void *data)
-{
- switch (code) {
- case SUBSYS_BEFORE_SHUTDOWN:
- D("%s: SUBSYS_BEFORE_SHUTDOWN\n", __func__);
- break;
-
- case SUBSYS_BEFORE_POWERUP:
- D("%s: waiting for RPC restart to complete\n", __func__);
- wait_event(subsystem_restart_wait,
- atomic_read(&pending_close_count) == 0);
- D("%s: finished restart wait\n", __func__);
- break;
-
- default:
- break;
- }
-
- return NOTIFY_DONE;
-}
-
-static void *restart_notifier_handle;
-static __init int msm_ipc_router_modem_restart_late_init(void)
-{
- restart_notifier_handle = subsys_notif_register_notifier("modem",
- &msm_ipc_router_nb);
- return 0;
-}
-late_initcall(msm_ipc_router_modem_restart_late_init);
-
static int __init msm_ipc_router_init(void)
{
int i, ret;
@@ -2743,7 +2698,6 @@
mutex_unlock(&routing_table_lock);
init_waitqueue_head(&newserver_wait);
- init_waitqueue_head(&subsystem_restart_wait);
ret = msm_ipc_router_init_sockets();
if (ret < 0)
pr_err("%s: Init sockets failed\n", __func__);