From 8ddb93e2b84159b9d29df438e7766684534b3c53 Mon Sep 17 00:00:00 2001 From: smanag Date: Tue, 14 Nov 2017 14:57:57 +0530 Subject: [PATCH] drivers: soc: Synchronize apr callback and voice svc release Issue is seen when apr callback is received while voice_svc_release is in process of freeing the driver private data. Avoid invalid access of private data pointer by putting the callback and release functions in the same locked context. Change-Id: I93af13cab0a3c7e653a9bc9fa7f4f86bfa0502df Signed-off-by: smanag [haggertk: Backport to 3.4/msm8974] Signed-off-by: Kevin F. Haggerty --- arch/arm/mach-msm/qdsp6v2/voice_svc.c | 40 ++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-msm/qdsp6v2/voice_svc.c b/arch/arm/mach-msm/qdsp6v2/voice_svc.c index b2c7550fce6..e1b826737b4 100755 --- a/arch/arm/mach-msm/qdsp6v2/voice_svc.c +++ b/arch/arm/mach-msm/qdsp6v2/voice_svc.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -68,7 +69,11 @@ static void *dummy_q6_mvm; static void *dummy_q6_cvs; dev_t device_num; +spinlock_t voicesvc_lock; +static bool is_released; static int voice_svc_dummy_reg(void); +static int voice_svc_dummy_dereg(void); + static int32_t qdsp_dummy_apr_callback(struct apr_client_data *data, void *priv); @@ -82,6 +87,11 @@ static int32_t qdsp_apr_callback(struct apr_client_data *data, void *priv) pr_err("%s: data or priv is NULL\n", __func__); return -EINVAL; } + spin_lock(&voicesvc_lock); + if (is_released) { + spin_unlock(&voicesvc_lock); + return 0; + } prtd = (struct voice_svc_prvt*)priv; @@ -115,7 +125,7 @@ static int32_t qdsp_apr_callback(struct apr_client_data *data, void *priv) GFP_ATOMIC); if (response_list == NULL) { pr_err("%s: kmalloc failed\n", __func__); - + spin_unlock(&voicesvc_lock); return -ENOMEM; } @@ -139,6 +149,7 @@ static int32_t qdsp_apr_callback(struct apr_client_data *data, void *priv) spin_unlock_irqrestore(&prtd->response_lock, spin_flags); + spin_unlock(&voicesvc_lock); return 0; } @@ -536,6 +547,21 @@ err: return -EINVAL; } +static int voice_svc_dummy_dereg(void) +{ + pr_debug("%s\n", __func__); + if (dummy_q6_mvm != NULL) { + apr_deregister(dummy_q6_mvm); + dummy_q6_mvm = NULL; + } + + if (dummy_q6_cvs != NULL) { + apr_deregister(dummy_q6_cvs); + dummy_q6_cvs = NULL; + } + return 0; +} + static int voice_svc_open(struct inode *inode, struct file *file) { struct voice_svc_prvt *prtd = NULL; @@ -559,6 +585,7 @@ static int voice_svc_open(struct inode *inode, struct file *file) mutex_init(&prtd->response_mutex_lock); file->private_data = (void*)prtd; + is_released = 0; /* Current APR implementation doesn't support session based * multiple service registrations. The apr_deregister() * function sets the destination and client IDs to zero, if @@ -582,8 +609,18 @@ static int voice_svc_release(struct inode *inode, struct file *file) return -EINVAL; } + if (reg_dummy_sess) { + voice_svc_dummy_dereg(); + reg_dummy_sess = 0; + } + mutex_destroy(&prtd->response_mutex_lock); + + spin_lock(&voicesvc_lock); kfree(file->private_data); + is_released = 1; + spin_unlock(&voicesvc_lock); + return 0; } @@ -641,6 +678,7 @@ static int voice_svc_probe(struct platform_device *pdev) goto add_err; } pr_debug("%s: Device created\n", __func__); + spin_lock_init(&voicesvc_lock); goto done; add_err: